aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip_vs.h18
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c31
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_pe.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c28
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c26
6 files changed, 65 insertions, 56 deletions
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index b7bbd6c28cfa..d5a32e47f9d9 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -422,6 +422,7 @@ struct ip_vs_conn {
422 struct ip_vs_seq in_seq; /* incoming seq. struct */ 422 struct ip_vs_seq in_seq; /* incoming seq. struct */
423 struct ip_vs_seq out_seq; /* outgoing seq. struct */ 423 struct ip_vs_seq out_seq; /* outgoing seq. struct */
424 424
425 const struct ip_vs_pe *pe;
425 char *pe_data; 426 char *pe_data;
426 __u8 pe_data_len; 427 __u8 pe_data_len;
427}; 428};
@@ -814,8 +815,19 @@ void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe);
814void ip_vs_unbind_pe(struct ip_vs_service *svc); 815void ip_vs_unbind_pe(struct ip_vs_service *svc);
815int register_ip_vs_pe(struct ip_vs_pe *pe); 816int register_ip_vs_pe(struct ip_vs_pe *pe);
816int unregister_ip_vs_pe(struct ip_vs_pe *pe); 817int unregister_ip_vs_pe(struct ip_vs_pe *pe);
817extern struct ip_vs_pe *ip_vs_pe_get(const char *name); 818struct ip_vs_pe *ip_vs_pe_getbyname(const char *name);
818extern void ip_vs_pe_put(struct ip_vs_pe *pe); 819
820static inline void ip_vs_pe_get(const struct ip_vs_pe *pe)
821{
822 if (pe && pe->module)
823 __module_get(pe->module);
824}
825
826static inline void ip_vs_pe_put(const struct ip_vs_pe *pe)
827{
828 if (pe && pe->module)
829 module_put(pe->module);
830}
819 831
820/* 832/*
821 * IPVS protocol functions (from ip_vs_proto.c) 833 * IPVS protocol functions (from ip_vs_proto.c)
@@ -904,7 +916,7 @@ extern char ip_vs_master_mcast_ifn[IP_VS_IFNAME_MAXLEN];
904extern char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; 916extern char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
905extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid); 917extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid);
906extern int stop_sync_thread(int state); 918extern int stop_sync_thread(int state);
907extern void ip_vs_sync_conn(struct ip_vs_conn *cp); 919extern void ip_vs_sync_conn(const struct ip_vs_conn *cp);
908 920
909 921
910/* 922/*
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index e9adecdc8ca4..7615f9e3d955 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -48,18 +48,18 @@
48/* 48/*
49 * Connection hash size. Default is what was selected at compile time. 49 * Connection hash size. Default is what was selected at compile time.
50*/ 50*/
51int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS; 51static int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS;
52module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444); 52module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444);
53MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size"); 53MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size");
54 54
55/* size and mask values */ 55/* size and mask values */
56int ip_vs_conn_tab_size; 56int ip_vs_conn_tab_size __read_mostly;
57int ip_vs_conn_tab_mask; 57static int ip_vs_conn_tab_mask __read_mostly;
58 58
59/* 59/*
60 * Connection hash table: for input and output packets lookups of IPVS 60 * Connection hash table: for input and output packets lookups of IPVS
61 */ 61 */
62static struct list_head *ip_vs_conn_tab; 62static struct list_head *ip_vs_conn_tab __read_mostly;
63 63
64/* SLAB cache for IPVS connections */ 64/* SLAB cache for IPVS connections */
65static struct kmem_cache *ip_vs_conn_cachep __read_mostly; 65static struct kmem_cache *ip_vs_conn_cachep __read_mostly;
@@ -71,7 +71,7 @@ static atomic_t ip_vs_conn_count = ATOMIC_INIT(0);
71static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0); 71static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0);
72 72
73/* random value for IPVS connection hash */ 73/* random value for IPVS connection hash */
74static unsigned int ip_vs_conn_rnd; 74static unsigned int ip_vs_conn_rnd __read_mostly;
75 75
76/* 76/*
77 * Fine locking granularity for big connection hash table 77 * Fine locking granularity for big connection hash table
@@ -176,8 +176,8 @@ static unsigned int ip_vs_conn_hashkey_conn(const struct ip_vs_conn *cp)
176 ip_vs_conn_fill_param(cp->af, cp->protocol, &cp->caddr, cp->cport, 176 ip_vs_conn_fill_param(cp->af, cp->protocol, &cp->caddr, cp->cport,
177 NULL, 0, &p); 177 NULL, 0, &p);
178 178
179 if (cp->dest && cp->dest->svc->pe) { 179 if (cp->pe) {
180 p.pe = cp->dest->svc->pe; 180 p.pe = cp->pe;
181 p.pe_data = cp->pe_data; 181 p.pe_data = cp->pe_data;
182 p.pe_data_len = cp->pe_data_len; 182 p.pe_data_len = cp->pe_data_len;
183 } 183 }
@@ -354,7 +354,7 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
354 354
355 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { 355 list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
356 if (p->pe_data && p->pe->ct_match) { 356 if (p->pe_data && p->pe->ct_match) {
357 if (p->pe->ct_match(p, cp)) 357 if (p->pe == cp->pe && p->pe->ct_match(p, cp))
358 goto out; 358 goto out;
359 continue; 359 continue;
360 } 360 }
@@ -765,6 +765,7 @@ static void ip_vs_conn_expire(unsigned long data)
765 if (cp->flags & IP_VS_CONN_F_NFCT) 765 if (cp->flags & IP_VS_CONN_F_NFCT)
766 ip_vs_conn_drop_conntrack(cp); 766 ip_vs_conn_drop_conntrack(cp);
767 767
768 ip_vs_pe_put(cp->pe);
768 kfree(cp->pe_data); 769 kfree(cp->pe_data);
769 if (unlikely(cp->app != NULL)) 770 if (unlikely(cp->app != NULL))
770 ip_vs_unbind_app(cp); 771 ip_vs_unbind_app(cp);
@@ -826,7 +827,9 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
826 &cp->daddr, daddr); 827 &cp->daddr, daddr);
827 cp->dport = dport; 828 cp->dport = dport;
828 cp->flags = flags; 829 cp->flags = flags;
829 if (flags & IP_VS_CONN_F_TEMPLATE && p->pe_data) { 830 if (flags & IP_VS_CONN_F_TEMPLATE && p->pe) {
831 ip_vs_pe_get(p->pe);
832 cp->pe = p->pe;
830 cp->pe_data = p->pe_data; 833 cp->pe_data = p->pe_data;
831 cp->pe_data_len = p->pe_data_len; 834 cp->pe_data_len = p->pe_data_len;
832 } 835 }
@@ -958,15 +961,13 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
958 char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3]; 961 char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3];
959 size_t len = 0; 962 size_t len = 0;
960 963
961 if (cp->dest && cp->pe_data && 964 if (cp->pe_data) {
962 cp->dest->svc->pe->show_pe_data) {
963 pe_data[0] = ' '; 965 pe_data[0] = ' ';
964 len = strlen(cp->dest->svc->pe->name); 966 len = strlen(cp->pe->name);
965 memcpy(pe_data + 1, cp->dest->svc->pe->name, len); 967 memcpy(pe_data + 1, cp->pe->name, len);
966 pe_data[len + 1] = ' '; 968 pe_data[len + 1] = ' ';
967 len += 2; 969 len += 2;
968 len += cp->dest->svc->pe->show_pe_data(cp, 970 len += cp->pe->show_pe_data(cp, pe_data + len);
969 pe_data + len);
970 } 971 }
971 pe_data[len] = '\0'; 972 pe_data[len] = '\0';
972 973
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 5f5daa30b0af..3e92558dfcc2 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1139,7 +1139,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
1139 } 1139 }
1140 1140
1141 if (u->pe_name && *u->pe_name) { 1141 if (u->pe_name && *u->pe_name) {
1142 pe = ip_vs_pe_get(u->pe_name); 1142 pe = ip_vs_pe_getbyname(u->pe_name);
1143 if (pe == NULL) { 1143 if (pe == NULL) {
1144 pr_info("persistence engine module ip_vs_pe_%s " 1144 pr_info("persistence engine module ip_vs_pe_%s "
1145 "not found\n", u->pe_name); 1145 "not found\n", u->pe_name);
@@ -1250,7 +1250,7 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
1250 old_sched = sched; 1250 old_sched = sched;
1251 1251
1252 if (u->pe_name && *u->pe_name) { 1252 if (u->pe_name && *u->pe_name) {
1253 pe = ip_vs_pe_get(u->pe_name); 1253 pe = ip_vs_pe_getbyname(u->pe_name);
1254 if (pe == NULL) { 1254 if (pe == NULL) {
1255 pr_info("persistence engine module ip_vs_pe_%s " 1255 pr_info("persistence engine module ip_vs_pe_%s "
1256 "not found\n", u->pe_name); 1256 "not found\n", u->pe_name);
diff --git a/net/netfilter/ipvs/ip_vs_pe.c b/net/netfilter/ipvs/ip_vs_pe.c
index 3414af70ee12..e99f920b93d1 100644
--- a/net/netfilter/ipvs/ip_vs_pe.c
+++ b/net/netfilter/ipvs/ip_vs_pe.c
@@ -30,7 +30,7 @@ void ip_vs_unbind_pe(struct ip_vs_service *svc)
30 30
31/* Get pe in the pe list by name */ 31/* Get pe in the pe list by name */
32static struct ip_vs_pe * 32static struct ip_vs_pe *
33ip_vs_pe_getbyname(const char *pe_name) 33__ip_vs_pe_getbyname(const char *pe_name)
34{ 34{
35 struct ip_vs_pe *pe; 35 struct ip_vs_pe *pe;
36 36
@@ -60,28 +60,22 @@ ip_vs_pe_getbyname(const char *pe_name)
60} 60}
61 61
62/* Lookup pe and try to load it if it doesn't exist */ 62/* Lookup pe and try to load it if it doesn't exist */
63struct ip_vs_pe *ip_vs_pe_get(const char *name) 63struct ip_vs_pe *ip_vs_pe_getbyname(const char *name)
64{ 64{
65 struct ip_vs_pe *pe; 65 struct ip_vs_pe *pe;
66 66
67 /* Search for the pe by name */ 67 /* Search for the pe by name */
68 pe = ip_vs_pe_getbyname(name); 68 pe = __ip_vs_pe_getbyname(name);
69 69
70 /* If pe not found, load the module and search again */ 70 /* If pe not found, load the module and search again */
71 if (!pe) { 71 if (!pe) {
72 request_module("ip_vs_pe_%s", name); 72 request_module("ip_vs_pe_%s", name);
73 pe = ip_vs_pe_getbyname(name); 73 pe = __ip_vs_pe_getbyname(name);
74 } 74 }
75 75
76 return pe; 76 return pe;
77} 77}
78 78
79void ip_vs_pe_put(struct ip_vs_pe *pe)
80{
81 if (pe && pe->module)
82 module_put(pe->module);
83}
84
85/* Register a pe in the pe list */ 79/* Register a pe in the pe list */
86int register_ip_vs_pe(struct ip_vs_pe *pe) 80int register_ip_vs_pe(struct ip_vs_pe *pe)
87{ 81{
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index ab85aedea17e..3897d6bf3b29 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -236,7 +236,7 @@ get_curr_sync_buff(unsigned long time)
236 * Add an ip_vs_conn information into the current sync_buff. 236 * Add an ip_vs_conn information into the current sync_buff.
237 * Called by ip_vs_in. 237 * Called by ip_vs_in.
238 */ 238 */
239void ip_vs_sync_conn(struct ip_vs_conn *cp) 239void ip_vs_sync_conn(const struct ip_vs_conn *cp)
240{ 240{
241 struct ip_vs_sync_mesg *m; 241 struct ip_vs_sync_mesg *m;
242 struct ip_vs_sync_conn *s; 242 struct ip_vs_sync_conn *s;
@@ -303,7 +303,7 @@ ip_vs_conn_fill_param_sync(int af, int protocol,
303 * Process received multicast message and create the corresponding 303 * Process received multicast message and create the corresponding
304 * ip_vs_conn entries. 304 * ip_vs_conn entries.
305 */ 305 */
306static void ip_vs_process_message(const char *buffer, const size_t buflen) 306static void ip_vs_process_message(char *buffer, const size_t buflen)
307{ 307{
308 struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer; 308 struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;
309 struct ip_vs_sync_conn *s; 309 struct ip_vs_sync_conn *s;
@@ -381,20 +381,18 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
381 } 381 }
382 } 382 }
383 383
384 { 384 if (ip_vs_conn_fill_param_sync(AF_INET, s->protocol,
385 if (ip_vs_conn_fill_param_sync(AF_INET, s->protocol, 385 (union nf_inet_addr *)&s->caddr,
386 (union nf_inet_addr *)&s->caddr, 386 s->cport,
387 s->cport, 387 (union nf_inet_addr *)&s->vaddr,
388 (union nf_inet_addr *)&s->vaddr, 388 s->vport, &param)) {
389 s->vport, &param)) { 389 pr_err("ip_vs_conn_fill_param_sync failed");
390 pr_err("ip_vs_conn_fill_param_sync failed"); 390 return;
391 return;
392 }
393 if (!(flags & IP_VS_CONN_F_TEMPLATE))
394 cp = ip_vs_conn_in_get(&param);
395 else
396 cp = ip_vs_ct_in_get(&param);
397 } 391 }
392 if (!(flags & IP_VS_CONN_F_TEMPLATE))
393 cp = ip_vs_conn_in_get(&param);
394 else
395 cp = ip_vs_ct_in_get(&param);
398 if (!cp) { 396 if (!cp) {
399 /* 397 /*
400 * Find the appropriate destination for the connection. 398 * Find the appropriate destination for the connection.
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 10bd39c0ae2d..fb2a445ddc59 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -188,7 +188,6 @@ __ip_vs_reroute_locally(struct sk_buff *skb)
188 }, 188 },
189 .mark = skb->mark, 189 .mark = skb->mark,
190 }; 190 };
191 struct rtable *rt;
192 191
193 if (ip_route_output_key(net, &rt, &fl)) 192 if (ip_route_output_key(net, &rt, &fl))
194 return 0; 193 return 0;
@@ -408,7 +407,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
408 407
409 /* MTU checking */ 408 /* MTU checking */
410 mtu = dst_mtu(&rt->dst); 409 mtu = dst_mtu(&rt->dst);
411 if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) { 410 if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
411 !skb_is_gso(skb)) {
412 ip_rt_put(rt); 412 ip_rt_put(rt);
413 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); 413 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
414 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 414 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
@@ -461,7 +461,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
461 461
462 /* MTU checking */ 462 /* MTU checking */
463 mtu = dst_mtu(&rt->dst); 463 mtu = dst_mtu(&rt->dst);
464 if (skb->len > mtu) { 464 if (skb->len > mtu && !skb_is_gso(skb)) {
465 if (!skb->dev) { 465 if (!skb->dev) {
466 struct net *net = dev_net(skb_dst(skb)->dev); 466 struct net *net = dev_net(skb_dst(skb)->dev);
467 467
@@ -561,7 +561,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
561 561
562 /* MTU checking */ 562 /* MTU checking */
563 mtu = dst_mtu(&rt->dst); 563 mtu = dst_mtu(&rt->dst);
564 if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) { 564 if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
565 !skb_is_gso(skb)) {
565 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); 566 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
566 IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0, 567 IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0,
567 "ip_vs_nat_xmit(): frag needed for"); 568 "ip_vs_nat_xmit(): frag needed for");
@@ -676,7 +677,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
676 677
677 /* MTU checking */ 678 /* MTU checking */
678 mtu = dst_mtu(&rt->dst); 679 mtu = dst_mtu(&rt->dst);
679 if (skb->len > mtu) { 680 if (skb->len > mtu && !skb_is_gso(skb)) {
680 if (!skb->dev) { 681 if (!skb->dev) {
681 struct net *net = dev_net(skb_dst(skb)->dev); 682 struct net *net = dev_net(skb_dst(skb)->dev);
682 683
@@ -791,8 +792,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
791 792
792 df |= (old_iph->frag_off & htons(IP_DF)); 793 df |= (old_iph->frag_off & htons(IP_DF));
793 794
794 if ((old_iph->frag_off & htons(IP_DF)) 795 if ((old_iph->frag_off & htons(IP_DF) &&
795 && mtu < ntohs(old_iph->tot_len)) { 796 mtu < ntohs(old_iph->tot_len) && !skb_is_gso(skb))) {
796 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); 797 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
797 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 798 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
798 goto tx_error_put; 799 goto tx_error_put;
@@ -904,7 +905,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
904 if (skb_dst(skb)) 905 if (skb_dst(skb))
905 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); 906 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
906 907
907 if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) { 908 if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
909 !skb_is_gso(skb)) {
908 if (!skb->dev) { 910 if (!skb->dev) {
909 struct net *net = dev_net(skb_dst(skb)->dev); 911 struct net *net = dev_net(skb_dst(skb)->dev);
910 912
@@ -1009,7 +1011,8 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
1009 1011
1010 /* MTU checking */ 1012 /* MTU checking */
1011 mtu = dst_mtu(&rt->dst); 1013 mtu = dst_mtu(&rt->dst);
1012 if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) { 1014 if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu &&
1015 !skb_is_gso(skb)) {
1013 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); 1016 icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
1014 ip_rt_put(rt); 1017 ip_rt_put(rt);
1015 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 1018 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
@@ -1176,7 +1179,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
1176 1179
1177 /* MTU checking */ 1180 /* MTU checking */
1178 mtu = dst_mtu(&rt->dst); 1181 mtu = dst_mtu(&rt->dst);
1179 if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) { 1182 if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF)) &&
1183 !skb_is_gso(skb)) {
1180 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); 1184 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
1181 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 1185 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
1182 goto tx_error_put; 1186 goto tx_error_put;
@@ -1290,7 +1294,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1290 1294
1291 /* MTU checking */ 1295 /* MTU checking */
1292 mtu = dst_mtu(&rt->dst); 1296 mtu = dst_mtu(&rt->dst);
1293 if (skb->len > mtu) { 1297 if (skb->len > mtu && !skb_is_gso(skb)) {
1294 if (!skb->dev) { 1298 if (!skb->dev) {
1295 struct net *net = dev_net(skb_dst(skb)->dev); 1299 struct net *net = dev_net(skb_dst(skb)->dev);
1296 1300