diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index c677f89eb..3f60790c3 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -1704,6 +1704,7 @@ struct bpf_sym_addrs { extern struct bpf_sym_addrs resolve_addrs; extern struct bpf_map *conntrack_map; extern bool bpf_mode_on; +extern bool no_route_to_host_fix; extern __be32 major_nic_ip; int ip_vs_bpf_put(void); diff --git a/net/netfilter/ipvs/ip_vs_bpf_proc.c b/net/netfilter/ipvs/ip_vs_bpf_proc.c index dc567c533..f62ca049f 100644 --- a/net/netfilter/ipvs/ip_vs_bpf_proc.c +++ b/net/netfilter/ipvs/ip_vs_bpf_proc.c @@ -54,7 +54,7 @@ __be32 major_nic_ip; static int ip_local_port_begin; static int ip_local_port_end; struct bpf_map *conntrack_map; - +bool no_route_to_host_fix; struct ip_vs_iter_state { struct seq_net_private p; struct hlist_head *l; @@ -667,6 +667,58 @@ static ssize_t ip_vs_port_write(struct file *file, return count; } +static ssize_t ip_vs_bpf_fix_write(struct file *file, + const char __user *ubuf, + size_t count, + loff_t *ppos) +{ + char buf[10]; + int fix; + + memset(buf, 0, sizeof(buf)); + if (*ppos > 0) { + pr_err("%s %d\n", __func__, __LINE__); + return -EFAULT; + } + if (copy_from_user(buf, ubuf, count)) { + pr_err("%s %d\n", __FILE__, __LINE__); + return -EFAULT; + } + if (kstrtoint(buf, 0, &fix) != 0) { + pr_err("%s %d\n", __FILE__, __LINE__); + return -EINVAL; + } + if (fix != 1 && fix != 0) { + pr_err("%s %d\n", __FILE__, __LINE__); + return -EINVAL; + } + + no_route_to_host_fix = fix; + return count; +} + +static ssize_t ip_vs_bpf_fix_read(struct file *file, + char __user *ubuf, + size_t count, + loff_t *ppos) +{ + int len = 0; + char buf[10]; + + memset(buf, 0, sizeof(buf)); + if (*ppos > 0) { + /* return 0 to sigal eof to user */ + return 0; + } + /* snprintf need tail to save null bytes */ + len = snprintf(buf, sizeof(buf), "0x%d\n", no_route_to_host_fix); + if (copy_to_user(ubuf, buf, len)) + return -EFAULT; + /* so next time ppos will be bigger than 0 and return 0 */ + *ppos = len; + return len; +} + static const struct file_operations ip_vs_svc_fops = { .owner = THIS_MODULE, .open = ip_vs_svc_open, @@ -694,6 +746,12 @@ static const struct file_operations ip_vs_port_fops = { .write = ip_vs_port_write, }; +static const struct file_operations ip_vs_bpf_fix_fops = { + .owner = THIS_MODULE, + .read = ip_vs_bpf_fix_read, + .write = ip_vs_bpf_fix_write, +}; + struct ip_vs_err_map { int errno; const char *name; @@ -774,9 +832,14 @@ int ip_vs_svc_proc_init(struct netns_ipvs *ipvs) if (!proc_create("ip_vs_bpf_stat", S_IRUGO, ipvs->net->proc_net, &ip_vs_bpf_stat_fops)) goto out_bpf_stat; + if (!proc_create("ip_vs_bpf_fix", 0600, + ipvs->net->proc_net, &ip_vs_bpf_fix_fops)) + goto out_bpf_fix; return 0; +out_bpf_fix: + remove_proc_entry("ip_vs_bpf_stat", ipvs->net->proc_net); out_bpf_stat: remove_proc_entry("ip_vs_port_range", ipvs->net->proc_net); out_port_range: @@ -796,5 +859,6 @@ int ip_vs_svc_proc_cleanup(struct netns_ipvs *ipvs) remove_proc_entry("ip_vs_devip", ipvs->net->proc_net); remove_proc_entry("ip_vs_port_range", ipvs->net->proc_net); remove_proc_entry("ip_vs_bpf_stat", ipvs->net->proc_net); + remove_proc_entry("ip_vs_bpf_fix", ipvs->net->proc_net); return 0; } diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index b65e0e562..00958a7ba 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -270,7 +270,7 @@ static void ip_vs_unlink_bpf(struct ip_vs_conn *cp) return; } - if (atomic_dec_return(&v->ref) != 0) + if (no_route_to_host_fix && atomic_dec_return(&v->ref) != 0) return; reply.sip = cp->dest->addr.ip; reply.sport = cp->dest->port; @@ -1125,10 +1125,12 @@ static bool ip_vs_conn_new_bpf(struct ip_vs_dest *dest, * otherwise, it doesn't reschedule. in such case, the following code * will not run. */ - v = map->ops->map_lookup_elem(map, &key); - if (v) { - atomic_inc(&v->ref); - return true; + if (no_route_to_host_fix) { + v = map->ops->map_lookup_elem(map, &key); + if (v) { + atomic_inc(&v->ref); + return true; + } } lip = alloc_localip(); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 0b638104c..b3252bec1 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1994,8 +1994,9 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int * as zero rs may be killed already. * Only enable in bpf mode currently. Shall promote to IPVS mode later. */ - if (bpf_mode_on && cp && unlikely(!atomic_read(&cp->dest->weight)) && - is_new_conn(skb, &iph) && !iph.fragoffs) { + if (no_route_to_host_fix && bpf_mode_on && cp && + unlikely(!atomic_read(&cp->dest->weight)) && + is_new_conn(skb, &iph) && !iph.fragoffs) { ip_vs_conn_expire_now(cp); __ip_vs_conn_put(cp); cp = NULL;