hulk inclusion category: featrue bugzilla: https://atomgit.com/openeuler/kernel/issues/8480 -------------------------------- Add bpf_handle_ingress/egress_ptype helper function to handle the ingress or egress ptype logic. Signed-off-by: Pu Lehui <pulehui@huawei.com> --- include/uapi/linux/bpf.h | 16 ++++++++++ net/core/filter.c | 58 ++++++++++++++++++++++++++++++++++ net/ipv4/ip_output.c | 31 +----------------- tools/include/uapi/linux/bpf.h | 16 ++++++++++ 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 8d393472de02..f0840df75d35 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -3998,6 +3998,20 @@ union bpf_attr { * Set valid net device to egress skb. * Return * 0 on success, or negative error in case of failure. + * + * void bpf_handle_ingress_ptype(struct sk_buff *skb) + * Description + * Handle ingress ptype all logic based on the current + * net device of skb. + * Return + * Void. + * + * void bpf_handle_egress_ptype(struct sk_buff *skb) + * Description + * Handle egress ptype all logic based on the current + * net device of skb. + * Return + * Void. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4184,6 +4198,8 @@ union bpf_attr { FN(get_skb_ethhdr), \ FN(set_ingress_dev), \ FN(set_egress_dev), \ + FN(handle_ingress_ptype), \ + FN(handle_egress_ptype), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/net/core/filter.c b/net/core/filter.c index 0ee0c974b17b..567bdb3cf0ba 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3791,6 +3791,60 @@ static const struct bpf_func_proto bpf_set_egress_dev_proto = { .arg2_type = ARG_ANYTHING, }; +BPF_CALL_1(bpf_handle_ingress_ptype, struct sk_buff *, skb) +{ + struct list_head *ptype_list = &ptype_all; + struct packet_type *ptype; + + rcu_read_lock(); +again: + list_for_each_entry_rcu(ptype, ptype_list, list) { + if (likely(!skb_orphan_frags_rx(skb, GFP_ATOMIC))) { + refcount_inc(&skb->users); + ptype->func(skb, skb->dev, ptype, skb->dev); + } + } + + if (ptype_list == &ptype_all) { + ptype_list = &skb->dev->ptype_all; + goto again; + } + + rcu_read_unlock(); + return 0; +} + +static const struct bpf_func_proto bpf_handle_ingress_ptype_proto = { + .func = bpf_handle_ingress_ptype, + .gpl_only = false, + .ret_type = RET_VOID, + .arg1_type = ARG_PTR_TO_CTX, +}; + +BPF_CALL_1(bpf_handle_egress_ptype, struct sk_buff *, skb) +{ + struct net_device *dev, *orig_dev = skb->dev; + + rcu_read_lock(); + dev = skb_dst_dev_rcu(skb); + skb->dev = dev; + skb->protocol = htons(ETH_P_IP); + + if (dev_nit_active(skb->dev)) + dev_queue_xmit_nit(skb, skb->dev); + + skb->dev = orig_dev; + rcu_read_unlock(); + return 0; +} + +static const struct bpf_func_proto bpf_handle_egress_ptype_proto = { + .func = bpf_handle_egress_ptype, + .gpl_only = false, + .ret_type = RET_VOID, + .arg1_type = ARG_PTR_TO_CTX, +}; + BPF_CALL_2(bpf_skb_change_skb_dev, struct sk_buff *, skb, u32, ifindex) { struct net_device *dev; @@ -7525,6 +7579,10 @@ hisock_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return is_ingress ? &bpf_set_ingress_dev_proto : NULL; case BPF_FUNC_set_egress_dev: return !is_ingress ? &bpf_set_egress_dev_proto : NULL; + case BPF_FUNC_handle_ingress_ptype: + return is_ingress ? &bpf_handle_ingress_ptype_proto : NULL; + case BPF_FUNC_handle_egress_ptype: + return !is_ingress ? &bpf_handle_egress_ptype_proto : NULL; default: return bpf_base_func_proto(func_id); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 587668db4ea4..5ef7653fa994 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -463,35 +463,6 @@ static void ip_copy_addrs(struct iphdr *iph, const struct flowi4 *fl4) } #ifdef CONFIG_HISOCK -static int hisock_egress_redirect_xmit(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct netdev_queue *txq; - bool free_skb = true; - int cpu, rc; - - rcu_read_lock_bh(); - - txq = netdev_core_pick_tx(dev, skb, NULL); - cpu = smp_processor_id(); - HARD_TX_LOCK(dev, txq, cpu); - if (!netif_xmit_stopped(txq)) { - rc = netdev_start_xmit(skb, dev, txq, 0); - if (dev_xmit_complete(rc)) - free_skb = false; - } - HARD_TX_UNLOCK(dev, txq); - - rcu_read_unlock_bh(); - - if (free_skb) { - rc = -ENETDOWN; - kfree_skb(skb); - } - - return rc; -} - static int do_hisock_egress_redirect(struct net *net, struct sock *sk, struct sk_buff *skb) { struct iphdr *iph; @@ -501,7 +472,7 @@ static int do_hisock_egress_redirect(struct net *net, struct sock *sk, struct sk skb->dev = skb_dst(skb)->dev; if (skb_mac_header_was_set(skb)) - return hisock_egress_redirect_xmit(skb); + return dev_queue_xmit(skb); iph = ip_hdr(skb); iph->tot_len = htons(skb->len); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 9dfe2ea7a018..7729ba3a13bb 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -3998,6 +3998,20 @@ union bpf_attr { * Set valid net device to egress skb. * Return * 0 on success, or negative error in case of failure. + * + * void bpf_handle_ingress_ptype(struct sk_buff *skb) + * Description + * Handle ingress ptype all logic based on the current + * net device of skb. + * Return + * Void. + * + * void bpf_handle_egress_ptype(struct sk_buff *skb) + * Description + * Handle egress ptype all logic based on the current + * net device of skb. + * Return + * Void. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4184,6 +4198,8 @@ union bpf_attr { FN(get_skb_ethhdr), \ FN(set_ingress_dev), \ FN(set_egress_dev), \ + FN(handle_ingress_ptype), \ + FN(handle_egress_ptype), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- 2.34.1