@@ -8716,6 +8716,12 @@ int dev_change_proto_down_generic(struct net_device *dev, bool proto_down)
87168716}
87178717EXPORT_SYMBOL (dev_change_proto_down_generic );
87188718
8719+ struct bpf_xdp_link {
8720+ struct bpf_link link ;
8721+ struct net_device * dev ; /* protected by rtnl_lock, no refcnt held */
8722+ int flags ;
8723+ };
8724+
87198725static enum bpf_xdp_mode dev_xdp_mode (u32 flags )
87208726{
87218727 if (flags & XDP_FLAGS_HW_MODE )
@@ -8738,9 +8744,19 @@ static bpf_op_t dev_xdp_bpf_op(struct net_device *dev, enum bpf_xdp_mode mode)
87388744 };
87398745}
87408746
8747+ static struct bpf_xdp_link * dev_xdp_link (struct net_device * dev ,
8748+ enum bpf_xdp_mode mode )
8749+ {
8750+ return dev -> xdp_state [mode ].link ;
8751+ }
8752+
87418753static struct bpf_prog * dev_xdp_prog (struct net_device * dev ,
87428754 enum bpf_xdp_mode mode )
87438755{
8756+ struct bpf_xdp_link * link = dev_xdp_link (dev , mode );
8757+
8758+ if (link )
8759+ return link -> link .prog ;
87448760 return dev -> xdp_state [mode ].prog ;
87458761}
87468762
@@ -8751,9 +8767,17 @@ u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
87518767 return prog ? prog -> aux -> id : 0 ;
87528768}
87538769
8770+ static void dev_xdp_set_link (struct net_device * dev , enum bpf_xdp_mode mode ,
8771+ struct bpf_xdp_link * link )
8772+ {
8773+ dev -> xdp_state [mode ].link = link ;
8774+ dev -> xdp_state [mode ].prog = NULL ;
8775+ }
8776+
87548777static void dev_xdp_set_prog (struct net_device * dev , enum bpf_xdp_mode mode ,
87558778 struct bpf_prog * prog )
87568779{
8780+ dev -> xdp_state [mode ].link = NULL ;
87578781 dev -> xdp_state [mode ].prog = prog ;
87588782}
87598783
@@ -8793,6 +8817,7 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
87938817
87948818static void dev_xdp_uninstall (struct net_device * dev )
87958819{
8820+ struct bpf_xdp_link * link ;
87968821 struct bpf_prog * prog ;
87978822 enum bpf_xdp_mode mode ;
87988823 bpf_op_t bpf_op ;
@@ -8810,14 +8835,20 @@ static void dev_xdp_uninstall(struct net_device *dev)
88108835
88118836 WARN_ON (dev_xdp_install (dev , mode , bpf_op , NULL , 0 , NULL ));
88128837
8813- bpf_prog_put (prog );
8814- dev_xdp_set_prog (dev , mode , NULL );
8838+ /* auto-detach link from net device */
8839+ link = dev_xdp_link (dev , mode );
8840+ if (link )
8841+ link -> dev = NULL ;
8842+ else
8843+ bpf_prog_put (prog );
8844+
8845+ dev_xdp_set_link (dev , mode , NULL );
88158846 }
88168847}
88178848
88188849static int dev_xdp_attach (struct net_device * dev , struct netlink_ext_ack * extack ,
8819- struct bpf_prog * new_prog , struct bpf_prog * old_prog ,
8820- u32 flags )
8850+ struct bpf_xdp_link * link , struct bpf_prog * new_prog ,
8851+ struct bpf_prog * old_prog , u32 flags )
88218852{
88228853 struct bpf_prog * cur_prog ;
88238854 enum bpf_xdp_mode mode ;
@@ -8826,6 +8857,14 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88268857
88278858 ASSERT_RTNL ();
88288859
8860+ /* either link or prog attachment, never both */
8861+ if (link && (new_prog || old_prog ))
8862+ return - EINVAL ;
8863+ /* link supports only XDP mode flags */
8864+ if (link && (flags & ~XDP_FLAGS_MODES )) {
8865+ NL_SET_ERR_MSG (extack , "Invalid XDP flags for BPF link attachment" );
8866+ return - EINVAL ;
8867+ }
88298868 /* just one XDP mode bit should be set, zero defaults to SKB mode */
88308869 if (hweight32 (flags & XDP_FLAGS_MODES ) > 1 ) {
88318870 NL_SET_ERR_MSG (extack , "Only one XDP mode flag can be set" );
@@ -8838,7 +8877,18 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88388877 }
88398878
88408879 mode = dev_xdp_mode (flags );
8880+ /* can't replace attached link */
8881+ if (dev_xdp_link (dev , mode )) {
8882+ NL_SET_ERR_MSG (extack , "Can't replace active BPF XDP link" );
8883+ return - EBUSY ;
8884+ }
8885+
88418886 cur_prog = dev_xdp_prog (dev , mode );
8887+ /* can't replace attached prog with link */
8888+ if (link && cur_prog ) {
8889+ NL_SET_ERR_MSG (extack , "Can't replace active XDP program with BPF link" );
8890+ return - EBUSY ;
8891+ }
88428892 if ((flags & XDP_FLAGS_REPLACE ) && cur_prog != old_prog ) {
88438893 NL_SET_ERR_MSG (extack , "Active program does not match expected" );
88448894 return - EEXIST ;
@@ -8848,6 +8898,10 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88488898 return - EBUSY ;
88498899 }
88508900
8901+ /* put effective new program into new_prog */
8902+ if (link )
8903+ new_prog = link -> link .prog ;
8904+
88518905 if (new_prog ) {
88528906 bool offload = mode == XDP_MODE_HW ;
88538907 enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB
@@ -8884,13 +8938,116 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
88848938 return err ;
88858939 }
88868940
8887- dev_xdp_set_prog (dev , mode , new_prog );
8941+ if (link )
8942+ dev_xdp_set_link (dev , mode , link );
8943+ else
8944+ dev_xdp_set_prog (dev , mode , new_prog );
88888945 if (cur_prog )
88898946 bpf_prog_put (cur_prog );
88908947
88918948 return 0 ;
88928949}
88938950
8951+ static int dev_xdp_attach_link (struct net_device * dev ,
8952+ struct netlink_ext_ack * extack ,
8953+ struct bpf_xdp_link * link )
8954+ {
8955+ return dev_xdp_attach (dev , extack , link , NULL , NULL , link -> flags );
8956+ }
8957+
8958+ static int dev_xdp_detach_link (struct net_device * dev ,
8959+ struct netlink_ext_ack * extack ,
8960+ struct bpf_xdp_link * link )
8961+ {
8962+ enum bpf_xdp_mode mode ;
8963+ bpf_op_t bpf_op ;
8964+
8965+ ASSERT_RTNL ();
8966+
8967+ mode = dev_xdp_mode (link -> flags );
8968+ if (dev_xdp_link (dev , mode ) != link )
8969+ return - EINVAL ;
8970+
8971+ bpf_op = dev_xdp_bpf_op (dev , mode );
8972+ WARN_ON (dev_xdp_install (dev , mode , bpf_op , NULL , 0 , NULL ));
8973+ dev_xdp_set_link (dev , mode , NULL );
8974+ return 0 ;
8975+ }
8976+
8977+ static void bpf_xdp_link_release (struct bpf_link * link )
8978+ {
8979+ struct bpf_xdp_link * xdp_link = container_of (link , struct bpf_xdp_link , link );
8980+
8981+ rtnl_lock ();
8982+
8983+ /* if racing with net_device's tear down, xdp_link->dev might be
8984+ * already NULL, in which case link was already auto-detached
8985+ */
8986+ if (xdp_link -> dev )
8987+ WARN_ON (dev_xdp_detach_link (xdp_link -> dev , NULL , xdp_link ));
8988+
8989+ rtnl_unlock ();
8990+ }
8991+
8992+ static void bpf_xdp_link_dealloc (struct bpf_link * link )
8993+ {
8994+ struct bpf_xdp_link * xdp_link = container_of (link , struct bpf_xdp_link , link );
8995+
8996+ kfree (xdp_link );
8997+ }
8998+
8999+ static const struct bpf_link_ops bpf_xdp_link_lops = {
9000+ .release = bpf_xdp_link_release ,
9001+ .dealloc = bpf_xdp_link_dealloc ,
9002+ };
9003+
9004+ int bpf_xdp_link_attach (const union bpf_attr * attr , struct bpf_prog * prog )
9005+ {
9006+ struct net * net = current -> nsproxy -> net_ns ;
9007+ struct bpf_link_primer link_primer ;
9008+ struct bpf_xdp_link * link ;
9009+ struct net_device * dev ;
9010+ int err , fd ;
9011+
9012+ dev = dev_get_by_index (net , attr -> link_create .target_ifindex );
9013+ if (!dev )
9014+ return - EINVAL ;
9015+
9016+ link = kzalloc (sizeof (* link ), GFP_USER );
9017+ if (!link ) {
9018+ err = - ENOMEM ;
9019+ goto out_put_dev ;
9020+ }
9021+
9022+ bpf_link_init (& link -> link , BPF_LINK_TYPE_XDP , & bpf_xdp_link_lops , prog );
9023+ link -> dev = dev ;
9024+ link -> flags = attr -> link_create .flags ;
9025+
9026+ err = bpf_link_prime (& link -> link , & link_primer );
9027+ if (err ) {
9028+ kfree (link );
9029+ goto out_put_dev ;
9030+ }
9031+
9032+ rtnl_lock ();
9033+ err = dev_xdp_attach_link (dev , NULL , link );
9034+ rtnl_unlock ();
9035+
9036+ if (err ) {
9037+ bpf_link_cleanup (& link_primer );
9038+ goto out_put_dev ;
9039+ }
9040+
9041+ fd = bpf_link_settle (& link_primer );
9042+ /* link itself doesn't hold dev's refcnt to not complicate shutdown */
9043+ dev_put (dev );
9044+ return fd ;
9045+
9046+ out_put_dev :
9047+ dev_put (dev );
9048+ return err ;
9049+ }
9050+
88949051/**
88959052 * dev_change_xdp_fd - set or clear a bpf program for a device rx path
88969053 * @dev: device
@@ -8927,7 +9084,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
89279084 }
89289085 }
89299086
8930- err = dev_xdp_attach (dev , extack , new_prog , old_prog , flags );
9087+ err = dev_xdp_attach (dev , extack , NULL , new_prog , old_prog , flags );
89319088
89329089err_out :
89339090 if (err && new_prog )
0 commit comments