@@ -3714,6 +3714,7 @@ static inline void dev_consume_skb_any(struct sk_buff *skb)
void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog);
int do_xdp_generic_rx(struct bpf_prog *xdp_prog, struct sk_buff *skb);
+u32 do_xdp_egress_skb(struct net_device *dev, struct sk_buff *skb);
int netif_rx(struct sk_buff *skb);
int netif_rx_ni(struct sk_buff *skb);
int netif_receive_skb(struct sk_buff *skb);
@@ -4534,6 +4535,16 @@ static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
struct sk_buff *skb, struct net_device *dev,
bool more)
{
+ if (static_branch_unlikely(&xdp_egress_needed_key)) {
+ u32 act;
+
+ rcu_read_lock();
+ act = do_xdp_egress_skb(dev, skb);
+ rcu_read_unlock();
+ if (act == XDP_DROP)
+ return NET_XMIT_DROP;
+ }
+
__this_cpu_write(softnet_data.xmit.more, more);
return ops->ndo_start_xmit(skb, dev);
}
@@ -4619,7 +4619,6 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
}
static DEFINE_STATIC_KEY_FALSE(generic_xdp_needed_key);
-DEFINE_STATIC_KEY_FALSE(xdp_egress_needed_key);
int do_xdp_generic_rx(struct bpf_prog *xdp_prog, struct sk_buff *skb)
{
@@ -4670,6 +4669,57 @@ int do_xdp_generic_rx(struct bpf_prog *xdp_prog, struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(do_xdp_generic_rx);
+DEFINE_STATIC_KEY_FALSE(xdp_egress_needed_key);
+EXPORT_SYMBOL_GPL(xdp_egress_needed_key);
+
+static u32 handle_xdp_egress_act(u32 act, struct net_device *dev,
+ struct bpf_prog *xdp_prog)
+{
+ switch (act) {
+ case XDP_DROP:
+ /* fall through */
+ case XDP_PASS:
+ break;
+ case XDP_TX:
+ /* fall through */
+ case XDP_REDIRECT:
+ /* fall through */
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ /* fall through */
+ case XDP_ABORTED:
+ trace_xdp_exception(dev, xdp_prog, act);
+ act = XDP_DROP;
+ break;
+ }
+
+ return act;
+}
+
+u32 do_xdp_egress_skb(struct net_device *dev, struct sk_buff *skb)
+{
+ struct bpf_prog *xdp_prog;
+ u32 act = XDP_PASS;
+
+ xdp_prog = rcu_dereference(dev->xdp_egress_prog);
+ if (xdp_prog) {
+ struct xdp_txq_info txq = { .dev = dev };
+ struct xdp_buff xdp;
+
+ xdp.txq = &txq;
+ act = do_xdp_generic_core(skb, &xdp, xdp_prog);
+ act = handle_xdp_egress_act(act, dev, xdp_prog);
+ if (act == XDP_DROP) {
+ atomic_long_inc(&dev->tx_dropped);
+ skb_tx_error(skb);
+ kfree_skb(skb);
+ }
+ }
+
+ return act;
+}
+EXPORT_SYMBOL_GPL(do_xdp_egress_skb);
+
static int netif_rx_internal(struct sk_buff *skb)
{
int ret;