Commit 2c2bf086 authored by Patrick McHardy's avatar Patrick McHardy
parents 3bfd45f9 8f1b03a4
...@@ -422,6 +422,7 @@ struct ip_vs_conn { ...@@ -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); ...@@ -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]; ...@@ -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 @@ ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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,20 +381,18 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) ...@@ -381,20 +381,18 @@ 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, (union nf_inet_addr *)&s->vaddr,
(union nf_inet_addr *)&s->vaddr, s->vport, &param)) {
s->vport, &param)) { pr_err("ip_vs_conn_fill_param_sync failed");
pr_err("ip_vs_conn_fill_param_sync failed"); return;
return;
}
if (!(flags & IP_VS_CONN_F_TEMPLATE))
cp = ip_vs_conn_in_get(&param);
else
cp = ip_vs_ct_in_get(&param);
} }
if (!(flags & IP_VS_CONN_F_TEMPLATE))
cp = ip_vs_conn_in_get(&param);
else
cp = ip_vs_ct_in_get(&param);
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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment