diff options
-rw-r--r-- | include/net/ip_vs.h | 18 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_conn.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 4 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_pe.c | 14 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_sync.c | 28 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_xmit.c | 26 |
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); | |||
814 | void ip_vs_unbind_pe(struct ip_vs_service *svc); | 815 | void ip_vs_unbind_pe(struct ip_vs_service *svc); |
815 | int register_ip_vs_pe(struct ip_vs_pe *pe); | 816 | int register_ip_vs_pe(struct ip_vs_pe *pe); |
816 | int unregister_ip_vs_pe(struct ip_vs_pe *pe); | 817 | int unregister_ip_vs_pe(struct ip_vs_pe *pe); |
817 | extern struct ip_vs_pe *ip_vs_pe_get(const char *name); | 818 | struct ip_vs_pe *ip_vs_pe_getbyname(const char *name); |
818 | extern void ip_vs_pe_put(struct ip_vs_pe *pe); | 819 | |
820 | static 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 | |||
826 | static 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]; | |||
904 | extern char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; | 916 | extern char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; |
905 | extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid); | 917 | extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid); |
906 | extern int stop_sync_thread(int state); | 918 | extern int stop_sync_thread(int state); |
907 | extern void ip_vs_sync_conn(struct ip_vs_conn *cp); | 919 | extern 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 | */ |
51 | int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS; | 51 | static int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS; |
52 | module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444); | 52 | module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444); |
53 | MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size"); | 53 | MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size"); |
54 | 54 | ||
55 | /* size and mask values */ | 55 | /* size and mask values */ |
56 | int ip_vs_conn_tab_size; | 56 | int ip_vs_conn_tab_size __read_mostly; |
57 | int ip_vs_conn_tab_mask; | 57 | static 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 | */ |
62 | static struct list_head *ip_vs_conn_tab; | 62 | static struct list_head *ip_vs_conn_tab __read_mostly; |
63 | 63 | ||
64 | /* SLAB cache for IPVS connections */ | 64 | /* SLAB cache for IPVS connections */ |
65 | static struct kmem_cache *ip_vs_conn_cachep __read_mostly; | 65 | static struct kmem_cache *ip_vs_conn_cachep __read_mostly; |
@@ -71,7 +71,7 @@ static atomic_t ip_vs_conn_count = ATOMIC_INIT(0); | |||
71 | static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0); | 71 | static 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 */ |
74 | static unsigned int ip_vs_conn_rnd; | 74 | static 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 */ |
32 | static struct ip_vs_pe * | 32 | static struct ip_vs_pe * |
33 | ip_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 */ |
63 | struct ip_vs_pe *ip_vs_pe_get(const char *name) | 63 | struct 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 | ||
79 | void 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 */ |
86 | int register_ip_vs_pe(struct ip_vs_pe *pe) | 80 | int 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 | */ |
239 | void ip_vs_sync_conn(struct ip_vs_conn *cp) | 239 | void 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 | */ |
306 | static void ip_vs_process_message(const char *buffer, const size_t buflen) | 306 | static 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, ¶m)) { |
389 | s->vport, ¶m)) { | 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(¶m); | ||
395 | else | ||
396 | cp = ip_vs_ct_in_get(¶m); | ||
397 | } | 391 | } |
392 | if (!(flags & IP_VS_CONN_F_TEMPLATE)) | ||
393 | cp = ip_vs_conn_in_get(¶m); | ||
394 | else | ||
395 | cp = ip_vs_ct_in_get(¶m); | ||
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 | ||