Skip to content

Commit 879af96

Browse files
joamakiborkmann
authored andcommitted
net, core: Add support for XDP redirection to slave device
This adds the ndo_xdp_get_xmit_slave hook for transforming XDP_TX into XDP_REDIRECT after BPF program run when the ingress device is a bond slave. The dev_xdp_prog_count is exposed so that slave devices can be checked for loaded XDP programs in order to avoid the situation where both bond master and slave have programs loaded according to xdp_state. Signed-off-by: Jussi Maki <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Cc: Jay Vosburgh <[email protected]> Cc: Veaceslav Falico <[email protected]> Cc: Andy Gospodarek <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent a815bde commit 879af96

File tree

4 files changed

+55
-2
lines changed

4 files changed

+55
-2
lines changed

include/linux/filter.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,14 +776,25 @@ static inline u32 bpf_prog_run_clear_cb(const struct bpf_prog *prog,
776776

777777
DECLARE_BPF_DISPATCHER(xdp)
778778

779+
DECLARE_STATIC_KEY_FALSE(bpf_master_redirect_enabled_key);
780+
781+
u32 xdp_master_redirect(struct xdp_buff *xdp);
782+
779783
static __always_inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog,
780784
struct xdp_buff *xdp)
781785
{
782786
/* Driver XDP hooks are invoked within a single NAPI poll cycle and thus
783787
* under local_bh_disable(), which provides the needed RCU protection
784788
* for accessing map entries.
785789
*/
786-
return __BPF_PROG_RUN(prog, xdp, BPF_DISPATCHER_FUNC(xdp));
790+
u32 act = __BPF_PROG_RUN(prog, xdp, BPF_DISPATCHER_FUNC(xdp));
791+
792+
if (static_branch_unlikely(&bpf_master_redirect_enabled_key)) {
793+
if (act == XDP_TX && netif_is_bond_slave(xdp->rxq->dev))
794+
act = xdp_master_redirect(xdp);
795+
}
796+
797+
return act;
787798
}
788799

789800
void bpf_prog_change_xdp(struct bpf_prog *prev_prog, struct bpf_prog *prog);

include/linux/netdevice.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,9 @@ struct netdev_net_notifier {
13301330
* that got dropped are freed/returned via xdp_return_frame().
13311331
* Returns negative number, means general error invoking ndo, meaning
13321332
* no frames were xmit'ed and core-caller will free all frames.
1333+
* struct net_device *(*ndo_xdp_get_xmit_slave)(struct net_device *dev,
1334+
* struct xdp_buff *xdp);
1335+
* Get the xmit slave of master device based on the xdp_buff.
13331336
* int (*ndo_xsk_wakeup)(struct net_device *dev, u32 queue_id, u32 flags);
13341337
* This function is used to wake up the softirq, ksoftirqd or kthread
13351338
* responsible for sending and/or receiving packets on a specific
@@ -1557,6 +1560,8 @@ struct net_device_ops {
15571560
int (*ndo_xdp_xmit)(struct net_device *dev, int n,
15581561
struct xdp_frame **xdp,
15591562
u32 flags);
1563+
struct net_device * (*ndo_xdp_get_xmit_slave)(struct net_device *dev,
1564+
struct xdp_buff *xdp);
15601565
int (*ndo_xsk_wakeup)(struct net_device *dev,
15611566
u32 queue_id, u32 flags);
15621567
struct devlink_port * (*ndo_get_devlink_port)(struct net_device *dev);
@@ -4087,6 +4092,7 @@ typedef int (*bpf_op_t)(struct net_device *dev, struct netdev_bpf *bpf);
40874092
int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
40884093
int fd, int expected_fd, u32 flags);
40894094
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
4095+
u8 dev_xdp_prog_count(struct net_device *dev);
40904096
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
40914097

40924098
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);

net/core/dev.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9380,7 +9380,7 @@ static struct bpf_prog *dev_xdp_prog(struct net_device *dev,
93809380
return dev->xdp_state[mode].prog;
93819381
}
93829382

9383-
static u8 dev_xdp_prog_count(struct net_device *dev)
9383+
u8 dev_xdp_prog_count(struct net_device *dev)
93849384
{
93859385
u8 count = 0;
93869386
int i;
@@ -9390,6 +9390,7 @@ static u8 dev_xdp_prog_count(struct net_device *dev)
93909390
count++;
93919391
return count;
93929392
}
9393+
EXPORT_SYMBOL_GPL(dev_xdp_prog_count);
93939394

93949395
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
93959396
{
@@ -9483,6 +9484,8 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
94839484
{
94849485
unsigned int num_modes = hweight32(flags & XDP_FLAGS_MODES);
94859486
struct bpf_prog *cur_prog;
9487+
struct net_device *upper;
9488+
struct list_head *iter;
94869489
enum bpf_xdp_mode mode;
94879490
bpf_op_t bpf_op;
94889491
int err;
@@ -9521,6 +9524,14 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
95219524
return -EBUSY;
95229525
}
95239526

9527+
/* don't allow if an upper device already has a program */
9528+
netdev_for_each_upper_dev_rcu(dev, upper, iter) {
9529+
if (dev_xdp_prog_count(upper) > 0) {
9530+
NL_SET_ERR_MSG(extack, "Cannot attach when an upper device already has a program");
9531+
return -EEXIST;
9532+
}
9533+
}
9534+
95249535
cur_prog = dev_xdp_prog(dev, mode);
95259536
/* can't replace attached prog with link */
95269537
if (link && cur_prog) {

net/core/filter.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3950,6 +3950,31 @@ void bpf_clear_redirect_map(struct bpf_map *map)
39503950
}
39513951
}
39523952

3953+
DEFINE_STATIC_KEY_FALSE(bpf_master_redirect_enabled_key);
3954+
EXPORT_SYMBOL_GPL(bpf_master_redirect_enabled_key);
3955+
3956+
u32 xdp_master_redirect(struct xdp_buff *xdp)
3957+
{
3958+
struct net_device *master, *slave;
3959+
struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
3960+
3961+
master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev);
3962+
slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp);
3963+
if (slave && slave != xdp->rxq->dev) {
3964+
/* The target device is different from the receiving device, so
3965+
* redirect it to the new device.
3966+
* Using XDP_REDIRECT gets the correct behaviour from XDP enabled
3967+
* drivers to unmap the packet from their rx ring.
3968+
*/
3969+
ri->tgt_index = slave->ifindex;
3970+
ri->map_id = INT_MAX;
3971+
ri->map_type = BPF_MAP_TYPE_UNSPEC;
3972+
return XDP_REDIRECT;
3973+
}
3974+
return XDP_TX;
3975+
}
3976+
EXPORT_SYMBOL_GPL(xdp_master_redirect);
3977+
39533978
int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
39543979
struct bpf_prog *xdp_prog)
39553980
{

0 commit comments

Comments
 (0)