@@ -8716,84 +8716,103 @@ int dev_change_proto_down_generic(struct net_device *dev, bool proto_down)
8716
8716
}
8717
8717
EXPORT_SYMBOL (dev_change_proto_down_generic );
8718
8718
8719
- u32 __dev_xdp_query (struct net_device * dev , bpf_op_t bpf_op ,
8720
- enum bpf_netdev_command cmd )
8719
+ static enum bpf_xdp_mode dev_xdp_mode (u32 flags )
8721
8720
{
8722
- struct netdev_bpf xdp ;
8721
+ if (flags & XDP_FLAGS_HW_MODE )
8722
+ return XDP_MODE_HW ;
8723
+ if (flags & XDP_FLAGS_DRV_MODE )
8724
+ return XDP_MODE_DRV ;
8725
+ return XDP_MODE_SKB ;
8726
+ }
8723
8727
8724
- if (!bpf_op )
8725
- return 0 ;
8728
+ static bpf_op_t dev_xdp_bpf_op (struct net_device * dev , enum bpf_xdp_mode mode )
8729
+ {
8730
+ switch (mode ) {
8731
+ case XDP_MODE_SKB :
8732
+ return generic_xdp_install ;
8733
+ case XDP_MODE_DRV :
8734
+ case XDP_MODE_HW :
8735
+ return dev -> netdev_ops -> ndo_bpf ;
8736
+ default :
8737
+ return NULL ;
8738
+ };
8739
+ }
8726
8740
8727
- memset (& xdp , 0 , sizeof (xdp ));
8728
- xdp .command = cmd ;
8741
+ static struct bpf_prog * dev_xdp_prog (struct net_device * dev ,
8742
+ enum bpf_xdp_mode mode )
8743
+ {
8744
+ return dev -> xdp_state [mode ].prog ;
8745
+ }
8746
+
8747
+ u32 dev_xdp_prog_id (struct net_device * dev , enum bpf_xdp_mode mode )
8748
+ {
8749
+ struct bpf_prog * prog = dev_xdp_prog (dev , mode );
8729
8750
8730
- /* Query must always succeed. */
8731
- WARN_ON ( bpf_op ( dev , & xdp ) < 0 && cmd == XDP_QUERY_PROG );
8751
+ return prog ? prog -> aux -> id : 0 ;
8752
+ }
8732
8753
8733
- return xdp .prog_id ;
8754
+ static void dev_xdp_set_prog (struct net_device * dev , enum bpf_xdp_mode mode ,
8755
+ struct bpf_prog * prog )
8756
+ {
8757
+ dev -> xdp_state [mode ].prog = prog ;
8734
8758
}
8735
8759
8736
- static int dev_xdp_install (struct net_device * dev , bpf_op_t bpf_op ,
8737
- struct netlink_ext_ack * extack , u32 flags ,
8738
- struct bpf_prog * prog )
8760
+ static int dev_xdp_install (struct net_device * dev , enum bpf_xdp_mode mode ,
8761
+ bpf_op_t bpf_op , struct netlink_ext_ack * extack ,
8762
+ u32 flags , struct bpf_prog * prog )
8739
8763
{
8740
- bool non_hw = !(flags & XDP_FLAGS_HW_MODE );
8741
- struct bpf_prog * prev_prog = NULL ;
8742
8764
struct netdev_bpf xdp ;
8743
8765
int err ;
8744
8766
8745
- if (non_hw ) {
8746
- prev_prog = bpf_prog_by_id (__dev_xdp_query (dev , bpf_op ,
8747
- XDP_QUERY_PROG ));
8748
- if (IS_ERR (prev_prog ))
8749
- prev_prog = NULL ;
8750
- }
8751
-
8752
8767
memset (& xdp , 0 , sizeof (xdp ));
8753
- if (flags & XDP_FLAGS_HW_MODE )
8754
- xdp .command = XDP_SETUP_PROG_HW ;
8755
- else
8756
- xdp .command = XDP_SETUP_PROG ;
8768
+ xdp .command = mode == XDP_MODE_HW ? XDP_SETUP_PROG_HW : XDP_SETUP_PROG ;
8757
8769
xdp .extack = extack ;
8758
8770
xdp .flags = flags ;
8759
8771
xdp .prog = prog ;
8760
8772
8773
+ /* Drivers assume refcnt is already incremented (i.e, prog pointer is
8774
+ * "moved" into driver), so they don't increment it on their own, but
8775
+ * they do decrement refcnt when program is detached or replaced.
8776
+ * Given net_device also owns link/prog, we need to bump refcnt here
8777
+ * to prevent drivers from underflowing it.
8778
+ */
8779
+ if (prog )
8780
+ bpf_prog_inc (prog );
8761
8781
err = bpf_op (dev , & xdp );
8762
- if (!err && non_hw )
8763
- bpf_prog_change_xdp (prev_prog , prog );
8782
+ if (err ) {
8783
+ if (prog )
8784
+ bpf_prog_put (prog );
8785
+ return err ;
8786
+ }
8764
8787
8765
- if (prev_prog )
8766
- bpf_prog_put ( prev_prog );
8788
+ if (mode != XDP_MODE_HW )
8789
+ bpf_prog_change_xdp ( dev_xdp_prog ( dev , mode ), prog );
8767
8790
8768
- return err ;
8791
+ return 0 ;
8769
8792
}
8770
8793
8771
8794
static void dev_xdp_uninstall (struct net_device * dev )
8772
8795
{
8773
- struct netdev_bpf xdp ;
8774
- bpf_op_t ndo_bpf ;
8796
+ struct bpf_prog * prog ;
8797
+ enum bpf_xdp_mode mode ;
8798
+ bpf_op_t bpf_op ;
8775
8799
8776
- /* Remove generic XDP */
8777
- WARN_ON (dev_xdp_install (dev , generic_xdp_install , NULL , 0 , NULL ));
8800
+ ASSERT_RTNL ();
8778
8801
8779
- /* Remove from the driver */
8780
- ndo_bpf = dev -> netdev_ops -> ndo_bpf ;
8781
- if (!ndo_bpf )
8782
- return ;
8802
+ for ( mode = XDP_MODE_SKB ; mode < __MAX_XDP_MODE ; mode ++ ) {
8803
+ prog = dev_xdp_prog ( dev , mode ) ;
8804
+ if (!prog )
8805
+ continue ;
8783
8806
8784
- memset (& xdp , 0 , sizeof (xdp ));
8785
- xdp .command = XDP_QUERY_PROG ;
8786
- WARN_ON (ndo_bpf (dev , & xdp ));
8787
- if (xdp .prog_id )
8788
- WARN_ON (dev_xdp_install (dev , ndo_bpf , NULL , xdp .prog_flags ,
8789
- NULL ));
8807
+ bpf_op = dev_xdp_bpf_op (dev , mode );
8808
+ if (!bpf_op )
8809
+ continue ;
8790
8810
8791
- /* Remove HW offload */
8792
- memset (& xdp , 0 , sizeof (xdp ));
8793
- xdp .command = XDP_QUERY_PROG_HW ;
8794
- if (!ndo_bpf (dev , & xdp ) && xdp .prog_id )
8795
- WARN_ON (dev_xdp_install (dev , ndo_bpf , NULL , xdp .prog_flags ,
8796
- NULL ));
8811
+ WARN_ON (dev_xdp_install (dev , mode , bpf_op , NULL , 0 , NULL ));
8812
+
8813
+ bpf_prog_put (prog );
8814
+ dev_xdp_set_prog (dev , mode , NULL );
8815
+ }
8797
8816
}
8798
8817
8799
8818
/**
@@ -8810,29 +8829,22 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
8810
8829
int fd , int expected_fd , u32 flags )
8811
8830
{
8812
8831
const struct net_device_ops * ops = dev -> netdev_ops ;
8813
- enum bpf_netdev_command query ;
8832
+ enum bpf_xdp_mode mode = dev_xdp_mode (flags );
8833
+ bool offload = mode == XDP_MODE_HW ;
8814
8834
u32 prog_id , expected_id = 0 ;
8815
- bpf_op_t bpf_op , bpf_chk ;
8816
8835
struct bpf_prog * prog ;
8817
- bool offload ;
8836
+ bpf_op_t bpf_op ;
8818
8837
int err ;
8819
8838
8820
8839
ASSERT_RTNL ();
8821
8840
8822
- offload = flags & XDP_FLAGS_HW_MODE ;
8823
- query = offload ? XDP_QUERY_PROG_HW : XDP_QUERY_PROG ;
8824
-
8825
- bpf_op = bpf_chk = ops -> ndo_bpf ;
8826
- if (!bpf_op && (flags & (XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE ))) {
8841
+ bpf_op = dev_xdp_bpf_op (dev , mode );
8842
+ if (!bpf_op ) {
8827
8843
NL_SET_ERR_MSG (extack , "underlying driver does not support XDP in native mode" );
8828
8844
return - EOPNOTSUPP ;
8829
8845
}
8830
- if (!bpf_op || (flags & XDP_FLAGS_SKB_MODE ))
8831
- bpf_op = generic_xdp_install ;
8832
- if (bpf_op == bpf_chk )
8833
- bpf_chk = generic_xdp_install ;
8834
8846
8835
- prog_id = __dev_xdp_query (dev , bpf_op , query );
8847
+ prog_id = dev_xdp_prog_id (dev , mode );
8836
8848
if (flags & XDP_FLAGS_REPLACE ) {
8837
8849
if (expected_fd >= 0 ) {
8838
8850
prog = bpf_prog_get_type_dev (expected_fd ,
@@ -8850,8 +8862,11 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
8850
8862
}
8851
8863
}
8852
8864
if (fd >= 0 ) {
8853
- if (!offload && __dev_xdp_query (dev , bpf_chk , XDP_QUERY_PROG )) {
8854
- NL_SET_ERR_MSG (extack , "native and generic XDP can't be active at the same time" );
8865
+ enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB
8866
+ ? XDP_MODE_DRV : XDP_MODE_SKB ;
8867
+
8868
+ if (!offload && dev_xdp_prog_id (dev , other_mode )) {
8869
+ NL_SET_ERR_MSG (extack , "Native and generic XDP can't be active at the same time" );
8855
8870
return - EEXIST ;
8856
8871
}
8857
8872
@@ -8866,7 +8881,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
8866
8881
return PTR_ERR (prog );
8867
8882
8868
8883
if (!offload && bpf_prog_is_dev_bound (prog -> aux )) {
8869
- NL_SET_ERR_MSG (extack , "using device-bound program without HW_MODE flag is not supported" );
8884
+ NL_SET_ERR_MSG (extack , "Using device-bound program without HW_MODE flag is not supported" );
8870
8885
bpf_prog_put (prog );
8871
8886
return - EINVAL ;
8872
8887
}
@@ -8895,11 +8910,14 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
8895
8910
prog = NULL ;
8896
8911
}
8897
8912
8898
- err = dev_xdp_install (dev , bpf_op , extack , flags , prog );
8899
- if (err < 0 && prog )
8913
+ err = dev_xdp_install (dev , mode , bpf_op , extack , flags , prog );
8914
+ if (err < 0 && prog ) {
8900
8915
bpf_prog_put (prog );
8916
+ return err ;
8917
+ }
8918
+ dev_xdp_set_prog (dev , mode , prog );
8901
8919
8902
- return err ;
8920
+ return 0 ;
8903
8921
}
8904
8922
8905
8923
/**
0 commit comments