Merge branch 'for-patrick' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6
This commit is contained in:
commit
2c2bf08614
6 changed files with 65 additions and 56 deletions
|
@ -422,6 +422,7 @@ struct ip_vs_conn {
|
||||||
struct ip_vs_seq in_seq; /* incoming seq. struct */
|
struct ip_vs_seq in_seq; /* incoming seq. struct */
|
||||||
struct ip_vs_seq out_seq; /* outgoing seq. struct */
|
struct ip_vs_seq out_seq; /* outgoing seq. struct */
|
||||||
|
|
||||||
|
const struct ip_vs_pe *pe;
|
||||||
char *pe_data;
|
char *pe_data;
|
||||||
__u8 pe_data_len;
|
__u8 pe_data_len;
|
||||||
};
|
};
|
||||||
|
@ -814,8 +815,19 @@ void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe);
|
||||||
void ip_vs_unbind_pe(struct ip_vs_service *svc);
|
void ip_vs_unbind_pe(struct ip_vs_service *svc);
|
||||||
int register_ip_vs_pe(struct ip_vs_pe *pe);
|
int register_ip_vs_pe(struct ip_vs_pe *pe);
|
||||||
int unregister_ip_vs_pe(struct ip_vs_pe *pe);
|
int unregister_ip_vs_pe(struct ip_vs_pe *pe);
|
||||||
extern struct ip_vs_pe *ip_vs_pe_get(const char *name);
|
struct ip_vs_pe *ip_vs_pe_getbyname(const char *name);
|
||||||
extern void ip_vs_pe_put(struct ip_vs_pe *pe);
|
|
||||||
|
static inline void ip_vs_pe_get(const struct ip_vs_pe *pe)
|
||||||
|
{
|
||||||
|
if (pe && pe->module)
|
||||||
|
__module_get(pe->module);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ip_vs_pe_put(const struct ip_vs_pe *pe)
|
||||||
|
{
|
||||||
|
if (pe && pe->module)
|
||||||
|
module_put(pe->module);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IPVS protocol functions (from ip_vs_proto.c)
|
* IPVS protocol functions (from ip_vs_proto.c)
|
||||||
|
@ -904,7 +916,7 @@ extern char ip_vs_master_mcast_ifn[IP_VS_IFNAME_MAXLEN];
|
||||||
extern char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
|
extern char ip_vs_backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
|
||||||
extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid);
|
extern int start_sync_thread(int state, char *mcast_ifn, __u8 syncid);
|
||||||
extern int stop_sync_thread(int state);
|
extern int stop_sync_thread(int state);
|
||||||
extern void ip_vs_sync_conn(struct ip_vs_conn *cp);
|
extern void ip_vs_sync_conn(const struct ip_vs_conn *cp);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -48,18 +48,18 @@
|
||||||
/*
|
/*
|
||||||
* Connection hash size. Default is what was selected at compile time.
|
* Connection hash size. Default is what was selected at compile time.
|
||||||
*/
|
*/
|
||||||
int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS;
|
static int ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS;
|
||||||
module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444);
|
module_param_named(conn_tab_bits, ip_vs_conn_tab_bits, int, 0444);
|
||||||
MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size");
|
MODULE_PARM_DESC(conn_tab_bits, "Set connections' hash size");
|
||||||
|
|
||||||
/* size and mask values */
|
/* size and mask values */
|
||||||
int ip_vs_conn_tab_size;
|
int ip_vs_conn_tab_size __read_mostly;
|
||||||
int ip_vs_conn_tab_mask;
|
static int ip_vs_conn_tab_mask __read_mostly;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Connection hash table: for input and output packets lookups of IPVS
|
* Connection hash table: for input and output packets lookups of IPVS
|
||||||
*/
|
*/
|
||||||
static struct list_head *ip_vs_conn_tab;
|
static struct list_head *ip_vs_conn_tab __read_mostly;
|
||||||
|
|
||||||
/* SLAB cache for IPVS connections */
|
/* SLAB cache for IPVS connections */
|
||||||
static struct kmem_cache *ip_vs_conn_cachep __read_mostly;
|
static struct kmem_cache *ip_vs_conn_cachep __read_mostly;
|
||||||
|
@ -71,7 +71,7 @@ static atomic_t ip_vs_conn_count = ATOMIC_INIT(0);
|
||||||
static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0);
|
static atomic_t ip_vs_conn_no_cport_cnt = ATOMIC_INIT(0);
|
||||||
|
|
||||||
/* random value for IPVS connection hash */
|
/* random value for IPVS connection hash */
|
||||||
static unsigned int ip_vs_conn_rnd;
|
static unsigned int ip_vs_conn_rnd __read_mostly;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fine locking granularity for big connection hash table
|
* 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)
|
||||||
ip_vs_conn_fill_param(cp->af, cp->protocol, &cp->caddr, cp->cport,
|
ip_vs_conn_fill_param(cp->af, cp->protocol, &cp->caddr, cp->cport,
|
||||||
NULL, 0, &p);
|
NULL, 0, &p);
|
||||||
|
|
||||||
if (cp->dest && cp->dest->svc->pe) {
|
if (cp->pe) {
|
||||||
p.pe = cp->dest->svc->pe;
|
p.pe = cp->pe;
|
||||||
p.pe_data = cp->pe_data;
|
p.pe_data = cp->pe_data;
|
||||||
p.pe_data_len = cp->pe_data_len;
|
p.pe_data_len = cp->pe_data_len;
|
||||||
}
|
}
|
||||||
|
@ -354,7 +354,7 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
|
||||||
|
|
||||||
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
|
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
|
||||||
if (p->pe_data && p->pe->ct_match) {
|
if (p->pe_data && p->pe->ct_match) {
|
||||||
if (p->pe->ct_match(p, cp))
|
if (p->pe == cp->pe && p->pe->ct_match(p, cp))
|
||||||
goto out;
|
goto out;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -765,6 +765,7 @@ static void ip_vs_conn_expire(unsigned long data)
|
||||||
if (cp->flags & IP_VS_CONN_F_NFCT)
|
if (cp->flags & IP_VS_CONN_F_NFCT)
|
||||||
ip_vs_conn_drop_conntrack(cp);
|
ip_vs_conn_drop_conntrack(cp);
|
||||||
|
|
||||||
|
ip_vs_pe_put(cp->pe);
|
||||||
kfree(cp->pe_data);
|
kfree(cp->pe_data);
|
||||||
if (unlikely(cp->app != NULL))
|
if (unlikely(cp->app != NULL))
|
||||||
ip_vs_unbind_app(cp);
|
ip_vs_unbind_app(cp);
|
||||||
|
@ -826,7 +827,9 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
|
||||||
&cp->daddr, daddr);
|
&cp->daddr, daddr);
|
||||||
cp->dport = dport;
|
cp->dport = dport;
|
||||||
cp->flags = flags;
|
cp->flags = flags;
|
||||||
if (flags & IP_VS_CONN_F_TEMPLATE && p->pe_data) {
|
if (flags & IP_VS_CONN_F_TEMPLATE && p->pe) {
|
||||||
|
ip_vs_pe_get(p->pe);
|
||||||
|
cp->pe = p->pe;
|
||||||
cp->pe_data = p->pe_data;
|
cp->pe_data = p->pe_data;
|
||||||
cp->pe_data_len = p->pe_data_len;
|
cp->pe_data_len = p->pe_data_len;
|
||||||
}
|
}
|
||||||
|
@ -958,15 +961,13 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
|
||||||
char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3];
|
char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3];
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
if (cp->dest && cp->pe_data &&
|
if (cp->pe_data) {
|
||||||
cp->dest->svc->pe->show_pe_data) {
|
|
||||||
pe_data[0] = ' ';
|
pe_data[0] = ' ';
|
||||||
len = strlen(cp->dest->svc->pe->name);
|
len = strlen(cp->pe->name);
|
||||||
memcpy(pe_data + 1, cp->dest->svc->pe->name, len);
|
memcpy(pe_data + 1, cp->pe->name, len);
|
||||||
pe_data[len + 1] = ' ';
|
pe_data[len + 1] = ' ';
|
||||||
len += 2;
|
len += 2;
|
||||||
len += cp->dest->svc->pe->show_pe_data(cp,
|
len += cp->pe->show_pe_data(cp, pe_data + len);
|
||||||
pe_data + len);
|
|
||||||
}
|
}
|
||||||
pe_data[len] = '\0';
|
pe_data[len] = '\0';
|
||||||
|
|
||||||
|
|
|
@ -1139,7 +1139,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u->pe_name && *u->pe_name) {
|
if (u->pe_name && *u->pe_name) {
|
||||||
pe = ip_vs_pe_get(u->pe_name);
|
pe = ip_vs_pe_getbyname(u->pe_name);
|
||||||
if (pe == NULL) {
|
if (pe == NULL) {
|
||||||
pr_info("persistence engine module ip_vs_pe_%s "
|
pr_info("persistence engine module ip_vs_pe_%s "
|
||||||
"not found\n", u->pe_name);
|
"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)
|
||||||
old_sched = sched;
|
old_sched = sched;
|
||||||
|
|
||||||
if (u->pe_name && *u->pe_name) {
|
if (u->pe_name && *u->pe_name) {
|
||||||
pe = ip_vs_pe_get(u->pe_name);
|
pe = ip_vs_pe_getbyname(u->pe_name);
|
||||||
if (pe == NULL) {
|
if (pe == NULL) {
|
||||||
pr_info("persistence engine module ip_vs_pe_%s "
|
pr_info("persistence engine module ip_vs_pe_%s "
|
||||||
"not found\n", u->pe_name);
|
"not found\n", u->pe_name);
|
||||||
|
|
|
@ -30,7 +30,7 @@ void ip_vs_unbind_pe(struct ip_vs_service *svc)
|
||||||
|
|
||||||
/* Get pe in the pe list by name */
|
/* Get pe in the pe list by name */
|
||||||
static struct ip_vs_pe *
|
static struct ip_vs_pe *
|
||||||
ip_vs_pe_getbyname(const char *pe_name)
|
__ip_vs_pe_getbyname(const char *pe_name)
|
||||||
{
|
{
|
||||||
struct ip_vs_pe *pe;
|
struct ip_vs_pe *pe;
|
||||||
|
|
||||||
|
@ -60,28 +60,22 @@ ip_vs_pe_getbyname(const char *pe_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup pe and try to load it if it doesn't exist */
|
/* Lookup pe and try to load it if it doesn't exist */
|
||||||
struct ip_vs_pe *ip_vs_pe_get(const char *name)
|
struct ip_vs_pe *ip_vs_pe_getbyname(const char *name)
|
||||||
{
|
{
|
||||||
struct ip_vs_pe *pe;
|
struct ip_vs_pe *pe;
|
||||||
|
|
||||||
/* Search for the pe by name */
|
/* Search for the pe by name */
|
||||||
pe = ip_vs_pe_getbyname(name);
|
pe = __ip_vs_pe_getbyname(name);
|
||||||
|
|
||||||
/* If pe not found, load the module and search again */
|
/* If pe not found, load the module and search again */
|
||||||
if (!pe) {
|
if (!pe) {
|
||||||
request_module("ip_vs_pe_%s", name);
|
request_module("ip_vs_pe_%s", name);
|
||||||
pe = ip_vs_pe_getbyname(name);
|
pe = __ip_vs_pe_getbyname(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pe;
|
return pe;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ip_vs_pe_put(struct ip_vs_pe *pe)
|
|
||||||
{
|
|
||||||
if (pe && pe->module)
|
|
||||||
module_put(pe->module);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register a pe in the pe list */
|
/* Register a pe in the pe list */
|
||||||
int register_ip_vs_pe(struct ip_vs_pe *pe)
|
int register_ip_vs_pe(struct ip_vs_pe *pe)
|
||||||
{
|
{
|
||||||
|
|
|
@ -236,7 +236,7 @@ get_curr_sync_buff(unsigned long time)
|
||||||
* Add an ip_vs_conn information into the current sync_buff.
|
* Add an ip_vs_conn information into the current sync_buff.
|
||||||
* Called by ip_vs_in.
|
* Called by ip_vs_in.
|
||||||
*/
|
*/
|
||||||
void ip_vs_sync_conn(struct ip_vs_conn *cp)
|
void ip_vs_sync_conn(const struct ip_vs_conn *cp)
|
||||||
{
|
{
|
||||||
struct ip_vs_sync_mesg *m;
|
struct ip_vs_sync_mesg *m;
|
||||||
struct ip_vs_sync_conn *s;
|
struct ip_vs_sync_conn *s;
|
||||||
|
@ -303,7 +303,7 @@ ip_vs_conn_fill_param_sync(int af, int protocol,
|
||||||
* Process received multicast message and create the corresponding
|
* Process received multicast message and create the corresponding
|
||||||
* ip_vs_conn entries.
|
* ip_vs_conn entries.
|
||||||
*/
|
*/
|
||||||
static void ip_vs_process_message(const char *buffer, const size_t buflen)
|
static void ip_vs_process_message(char *buffer, const size_t buflen)
|
||||||
{
|
{
|
||||||
struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;
|
struct ip_vs_sync_mesg *m = (struct ip_vs_sync_mesg *)buffer;
|
||||||
struct ip_vs_sync_conn *s;
|
struct ip_vs_sync_conn *s;
|
||||||
|
@ -381,7 +381,6 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
if (ip_vs_conn_fill_param_sync(AF_INET, s->protocol,
|
if (ip_vs_conn_fill_param_sync(AF_INET, s->protocol,
|
||||||
(union nf_inet_addr *)&s->caddr,
|
(union nf_inet_addr *)&s->caddr,
|
||||||
s->cport,
|
s->cport,
|
||||||
|
@ -394,7 +393,6 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
|
||||||
cp = ip_vs_conn_in_get(¶m);
|
cp = ip_vs_conn_in_get(¶m);
|
||||||
else
|
else
|
||||||
cp = ip_vs_ct_in_get(¶m);
|
cp = ip_vs_ct_in_get(¶m);
|
||||||
}
|
|
||||||
if (!cp) {
|
if (!cp) {
|
||||||
/*
|
/*
|
||||||
* Find the appropriate destination for the connection.
|
* Find the appropriate destination for the connection.
|
||||||
|
|
|
@ -188,7 +188,6 @@ __ip_vs_reroute_locally(struct sk_buff *skb)
|
||||||
},
|
},
|
||||||
.mark = skb->mark,
|
.mark = skb->mark,
|
||||||
};
|
};
|
||||||
struct rtable *rt;
|
|
||||||
|
|
||||||
if (ip_route_output_key(net, &rt, &fl))
|
if (ip_route_output_key(net, &rt, &fl))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -408,7 +407,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
|
|
||||||
/* MTU checking */
|
/* MTU checking */
|
||||||
mtu = dst_mtu(&rt->dst);
|
mtu = dst_mtu(&rt->dst);
|
||||||
if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
|
if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
|
||||||
|
!skb_is_gso(skb)) {
|
||||||
ip_rt_put(rt);
|
ip_rt_put(rt);
|
||||||
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
||||||
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
|
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,
|
||||||
|
|
||||||
/* MTU checking */
|
/* MTU checking */
|
||||||
mtu = dst_mtu(&rt->dst);
|
mtu = dst_mtu(&rt->dst);
|
||||||
if (skb->len > mtu) {
|
if (skb->len > mtu && !skb_is_gso(skb)) {
|
||||||
if (!skb->dev) {
|
if (!skb->dev) {
|
||||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||||
|
|
||||||
|
@ -561,7 +561,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
|
|
||||||
/* MTU checking */
|
/* MTU checking */
|
||||||
mtu = dst_mtu(&rt->dst);
|
mtu = dst_mtu(&rt->dst);
|
||||||
if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
|
if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
|
||||||
|
!skb_is_gso(skb)) {
|
||||||
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
||||||
IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0,
|
IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0,
|
||||||
"ip_vs_nat_xmit(): frag needed for");
|
"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,
|
||||||
|
|
||||||
/* MTU checking */
|
/* MTU checking */
|
||||||
mtu = dst_mtu(&rt->dst);
|
mtu = dst_mtu(&rt->dst);
|
||||||
if (skb->len > mtu) {
|
if (skb->len > mtu && !skb_is_gso(skb)) {
|
||||||
if (!skb->dev) {
|
if (!skb->dev) {
|
||||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||||
|
|
||||||
|
@ -791,8 +792,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
|
|
||||||
df |= (old_iph->frag_off & htons(IP_DF));
|
df |= (old_iph->frag_off & htons(IP_DF));
|
||||||
|
|
||||||
if ((old_iph->frag_off & htons(IP_DF))
|
if ((old_iph->frag_off & htons(IP_DF) &&
|
||||||
&& mtu < ntohs(old_iph->tot_len)) {
|
mtu < ntohs(old_iph->tot_len) && !skb_is_gso(skb))) {
|
||||||
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
||||||
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
|
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
|
||||||
goto tx_error_put;
|
goto tx_error_put;
|
||||||
|
@ -904,7 +905,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
if (skb_dst(skb))
|
if (skb_dst(skb))
|
||||||
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
|
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
|
||||||
|
|
||||||
if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
|
if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
|
||||||
|
!skb_is_gso(skb)) {
|
||||||
if (!skb->dev) {
|
if (!skb->dev) {
|
||||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||||
|
|
||||||
|
@ -1009,7 +1011,8 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
|
|
||||||
/* MTU checking */
|
/* MTU checking */
|
||||||
mtu = dst_mtu(&rt->dst);
|
mtu = dst_mtu(&rt->dst);
|
||||||
if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) {
|
if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu &&
|
||||||
|
!skb_is_gso(skb)) {
|
||||||
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
|
||||||
ip_rt_put(rt);
|
ip_rt_put(rt);
|
||||||
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
|
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,
|
||||||
|
|
||||||
/* MTU checking */
|
/* MTU checking */
|
||||||
mtu = dst_mtu(&rt->dst);
|
mtu = dst_mtu(&rt->dst);
|
||||||
if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
|
if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF)) &&
|
||||||
|
!skb_is_gso(skb)) {
|
||||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
|
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
|
||||||
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
|
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
|
||||||
goto tx_error_put;
|
goto tx_error_put;
|
||||||
|
@ -1290,7 +1294,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
|
|
||||||
/* MTU checking */
|
/* MTU checking */
|
||||||
mtu = dst_mtu(&rt->dst);
|
mtu = dst_mtu(&rt->dst);
|
||||||
if (skb->len > mtu) {
|
if (skb->len > mtu && !skb_is_gso(skb)) {
|
||||||
if (!skb->dev) {
|
if (!skb->dev) {
|
||||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue