diff options
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 62 | ||||
-rw-r--r-- | include/linux/netdevice.h | 9 | ||||
-rw-r--r-- | include/uapi/linux/if_link.h | 8 | ||||
-rw-r--r-- | net/core/dev.c | 15 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 10 |
6 files changed, 73 insertions, 36 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 02fd8d4e253c..b7446793106d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h | |||
@@ -541,6 +541,8 @@ struct nfp_net_dp { | |||
541 | * @rss_cfg: RSS configuration | 541 | * @rss_cfg: RSS configuration |
542 | * @rss_key: RSS secret key | 542 | * @rss_key: RSS secret key |
543 | * @rss_itbl: RSS indirection table | 543 | * @rss_itbl: RSS indirection table |
544 | * @xdp_flags: Flags with which XDP prog was loaded | ||
545 | * @xdp_prog: XDP prog (for ctrl path, both DRV and HW modes) | ||
544 | * @max_r_vecs: Number of allocated interrupt vectors for RX/TX | 546 | * @max_r_vecs: Number of allocated interrupt vectors for RX/TX |
545 | * @max_tx_rings: Maximum number of TX rings supported by the Firmware | 547 | * @max_tx_rings: Maximum number of TX rings supported by the Firmware |
546 | * @max_rx_rings: Maximum number of RX rings supported by the Firmware | 548 | * @max_rx_rings: Maximum number of RX rings supported by the Firmware |
@@ -590,6 +592,9 @@ struct nfp_net { | |||
590 | u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ]; | 592 | u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ]; |
591 | u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ]; | 593 | u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ]; |
592 | 594 | ||
595 | u32 xdp_flags; | ||
596 | struct bpf_prog *xdp_prog; | ||
597 | |||
593 | unsigned int max_tx_rings; | 598 | unsigned int max_tx_rings; |
594 | unsigned int max_rx_rings; | 599 | unsigned int max_rx_rings; |
595 | 600 | ||
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2bdddd1ae666..2134493ec8a8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c | |||
@@ -3274,19 +3274,14 @@ static void nfp_net_del_vxlan_port(struct net_device *netdev, | |||
3274 | nfp_net_set_vxlan_port(nn, idx, 0); | 3274 | nfp_net_set_vxlan_port(nn, idx, 0); |
3275 | } | 3275 | } |
3276 | 3276 | ||
3277 | static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) | 3277 | static int |
3278 | nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog, | ||
3279 | struct netlink_ext_ack *extack) | ||
3278 | { | 3280 | { |
3279 | struct bpf_prog *old_prog = nn->dp.xdp_prog; | ||
3280 | struct bpf_prog *prog = xdp->prog; | ||
3281 | struct nfp_net_dp *dp; | 3281 | struct nfp_net_dp *dp; |
3282 | int err; | ||
3283 | 3282 | ||
3284 | if (!prog && !nn->dp.xdp_prog) | 3283 | if (!prog == !nn->dp.xdp_prog) { |
3285 | return 0; | 3284 | WRITE_ONCE(nn->dp.xdp_prog, prog); |
3286 | if (prog && nn->dp.xdp_prog) { | ||
3287 | prog = xchg(&nn->dp.xdp_prog, prog); | ||
3288 | bpf_prog_put(prog); | ||
3289 | nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); | ||
3290 | return 0; | 3285 | return 0; |
3291 | } | 3286 | } |
3292 | 3287 | ||
@@ -3300,14 +3295,37 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp) | |||
3300 | dp->rx_dma_off = prog ? XDP_PACKET_HEADROOM - nn->dp.rx_offset : 0; | 3295 | dp->rx_dma_off = prog ? XDP_PACKET_HEADROOM - nn->dp.rx_offset : 0; |
3301 | 3296 | ||
3302 | /* We need RX reconfig to remap the buffers (BIDIR vs FROM_DEV) */ | 3297 | /* We need RX reconfig to remap the buffers (BIDIR vs FROM_DEV) */ |
3303 | err = nfp_net_ring_reconfig(nn, dp, xdp->extack); | 3298 | return nfp_net_ring_reconfig(nn, dp, extack); |
3299 | } | ||
3300 | |||
3301 | static int | ||
3302 | nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, | ||
3303 | struct netlink_ext_ack *extack) | ||
3304 | { | ||
3305 | struct bpf_prog *drv_prog, *offload_prog; | ||
3306 | int err; | ||
3307 | |||
3308 | if (nn->xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) | ||
3309 | return -EBUSY; | ||
3310 | |||
3311 | /* Load both when no flags set to allow easy activation of driver path | ||
3312 | * when program is replaced by one which can't be offloaded. | ||
3313 | */ | ||
3314 | drv_prog = flags & XDP_FLAGS_HW_MODE ? NULL : prog; | ||
3315 | offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog; | ||
3316 | |||
3317 | err = nfp_net_xdp_setup_drv(nn, drv_prog, extack); | ||
3304 | if (err) | 3318 | if (err) |
3305 | return err; | 3319 | return err; |
3306 | 3320 | ||
3307 | if (old_prog) | 3321 | err = nfp_app_xdp_offload(nn->app, nn, offload_prog); |
3308 | bpf_prog_put(old_prog); | 3322 | if (err && flags & XDP_FLAGS_HW_MODE) |
3323 | return err; | ||
3309 | 3324 | ||
3310 | nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); | 3325 | if (nn->xdp_prog) |
3326 | bpf_prog_put(nn->xdp_prog); | ||
3327 | nn->xdp_prog = prog; | ||
3328 | nn->xdp_flags = flags; | ||
3311 | 3329 | ||
3312 | return 0; | 3330 | return 0; |
3313 | } | 3331 | } |
@@ -3318,10 +3336,14 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) | |||
3318 | 3336 | ||
3319 | switch (xdp->command) { | 3337 | switch (xdp->command) { |
3320 | case XDP_SETUP_PROG: | 3338 | case XDP_SETUP_PROG: |
3321 | return nfp_net_xdp_setup(nn, xdp); | 3339 | case XDP_SETUP_PROG_HW: |
3340 | return nfp_net_xdp_setup(nn, xdp->prog, xdp->flags, | ||
3341 | xdp->extack); | ||
3322 | case XDP_QUERY_PROG: | 3342 | case XDP_QUERY_PROG: |
3323 | xdp->prog_attached = !!nn->dp.xdp_prog; | 3343 | xdp->prog_attached = !!nn->xdp_prog; |
3324 | xdp->prog_id = nn->dp.xdp_prog ? nn->dp.xdp_prog->aux->id : 0; | 3344 | if (nn->dp.bpf_offload_xdp) |
3345 | xdp->prog_attached = XDP_ATTACHED_HW; | ||
3346 | xdp->prog_id = nn->xdp_prog ? nn->xdp_prog->aux->id : 0; | ||
3325 | return 0; | 3347 | return 0; |
3326 | default: | 3348 | default: |
3327 | return -EINVAL; | 3349 | return -EINVAL; |
@@ -3479,6 +3501,9 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev, | |||
3479 | */ | 3501 | */ |
3480 | void nfp_net_free(struct nfp_net *nn) | 3502 | void nfp_net_free(struct nfp_net *nn) |
3481 | { | 3503 | { |
3504 | if (nn->xdp_prog) | ||
3505 | bpf_prog_put(nn->xdp_prog); | ||
3506 | |||
3482 | if (nn->dp.netdev) | 3507 | if (nn->dp.netdev) |
3483 | free_netdev(nn->dp.netdev); | 3508 | free_netdev(nn->dp.netdev); |
3484 | else | 3509 | else |
@@ -3736,7 +3761,4 @@ void nfp_net_clean(struct nfp_net *nn) | |||
3736 | return; | 3761 | return; |
3737 | 3762 | ||
3738 | unregister_netdev(nn->dp.netdev); | 3763 | unregister_netdev(nn->dp.netdev); |
3739 | |||
3740 | if (nn->dp.xdp_prog) | ||
3741 | bpf_prog_put(nn->dp.xdp_prog); | ||
3742 | } | 3764 | } |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7c7118b3bd69..68f5d899d1e6 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -807,8 +807,10 @@ enum xdp_netdev_command { | |||
807 | * when it is no longer used. | 807 | * when it is no longer used. |
808 | */ | 808 | */ |
809 | XDP_SETUP_PROG, | 809 | XDP_SETUP_PROG, |
810 | XDP_SETUP_PROG_HW, | ||
810 | /* Check if a bpf program is set on the device. The callee should | 811 | /* Check if a bpf program is set on the device. The callee should |
811 | * return true if a program is currently attached and running. | 812 | * set @prog_attached to one of XDP_ATTACHED_* values, note that "true" |
813 | * is equivalent to XDP_ATTACHED_DRV. | ||
812 | */ | 814 | */ |
813 | XDP_QUERY_PROG, | 815 | XDP_QUERY_PROG, |
814 | }; | 816 | }; |
@@ -820,12 +822,13 @@ struct netdev_xdp { | |||
820 | union { | 822 | union { |
821 | /* XDP_SETUP_PROG */ | 823 | /* XDP_SETUP_PROG */ |
822 | struct { | 824 | struct { |
825 | u32 flags; | ||
823 | struct bpf_prog *prog; | 826 | struct bpf_prog *prog; |
824 | struct netlink_ext_ack *extack; | 827 | struct netlink_ext_ack *extack; |
825 | }; | 828 | }; |
826 | /* XDP_QUERY_PROG */ | 829 | /* XDP_QUERY_PROG */ |
827 | struct { | 830 | struct { |
828 | bool prog_attached; | 831 | u8 prog_attached; |
829 | u32 prog_id; | 832 | u32 prog_id; |
830 | }; | 833 | }; |
831 | }; | 834 | }; |
@@ -3305,7 +3308,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | |||
3305 | typedef int (*xdp_op_t)(struct net_device *dev, struct netdev_xdp *xdp); | 3308 | typedef int (*xdp_op_t)(struct net_device *dev, struct netdev_xdp *xdp); |
3306 | int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, | 3309 | int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, |
3307 | int fd, u32 flags); | 3310 | int fd, u32 flags); |
3308 | bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op, u32 *prog_id); | 3311 | u8 __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op, u32 *prog_id); |
3309 | 3312 | ||
3310 | int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb); | 3313 | int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb); |
3311 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb); | 3314 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb); |
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index dd88375a6580..8d062c58d5cb 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h | |||
@@ -891,15 +891,19 @@ enum { | |||
891 | #define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0) | 891 | #define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0) |
892 | #define XDP_FLAGS_SKB_MODE (1U << 1) | 892 | #define XDP_FLAGS_SKB_MODE (1U << 1) |
893 | #define XDP_FLAGS_DRV_MODE (1U << 2) | 893 | #define XDP_FLAGS_DRV_MODE (1U << 2) |
894 | #define XDP_FLAGS_HW_MODE (1U << 3) | ||
895 | #define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \ | ||
896 | XDP_FLAGS_DRV_MODE | \ | ||
897 | XDP_FLAGS_HW_MODE) | ||
894 | #define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \ | 898 | #define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \ |
895 | XDP_FLAGS_SKB_MODE | \ | 899 | XDP_FLAGS_MODES) |
896 | XDP_FLAGS_DRV_MODE) | ||
897 | 900 | ||
898 | /* These are stored into IFLA_XDP_ATTACHED on dump. */ | 901 | /* These are stored into IFLA_XDP_ATTACHED on dump. */ |
899 | enum { | 902 | enum { |
900 | XDP_ATTACHED_NONE = 0, | 903 | XDP_ATTACHED_NONE = 0, |
901 | XDP_ATTACHED_DRV, | 904 | XDP_ATTACHED_DRV, |
902 | XDP_ATTACHED_SKB, | 905 | XDP_ATTACHED_SKB, |
906 | XDP_ATTACHED_HW, | ||
903 | }; | 907 | }; |
904 | 908 | ||
905 | enum { | 909 | enum { |
diff --git a/net/core/dev.c b/net/core/dev.c index df7637733e3c..a91572aa73d5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -6934,8 +6934,7 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down) | |||
6934 | } | 6934 | } |
6935 | EXPORT_SYMBOL(dev_change_proto_down); | 6935 | EXPORT_SYMBOL(dev_change_proto_down); |
6936 | 6936 | ||
6937 | bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op, | 6937 | u8 __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op, u32 *prog_id) |
6938 | u32 *prog_id) | ||
6939 | { | 6938 | { |
6940 | struct netdev_xdp xdp; | 6939 | struct netdev_xdp xdp; |
6941 | 6940 | ||
@@ -6951,14 +6950,18 @@ bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op, | |||
6951 | } | 6950 | } |
6952 | 6951 | ||
6953 | static int dev_xdp_install(struct net_device *dev, xdp_op_t xdp_op, | 6952 | static int dev_xdp_install(struct net_device *dev, xdp_op_t xdp_op, |
6954 | struct netlink_ext_ack *extack, | 6953 | struct netlink_ext_ack *extack, u32 flags, |
6955 | struct bpf_prog *prog) | 6954 | struct bpf_prog *prog) |
6956 | { | 6955 | { |
6957 | struct netdev_xdp xdp; | 6956 | struct netdev_xdp xdp; |
6958 | 6957 | ||
6959 | memset(&xdp, 0, sizeof(xdp)); | 6958 | memset(&xdp, 0, sizeof(xdp)); |
6960 | xdp.command = XDP_SETUP_PROG; | 6959 | if (flags & XDP_FLAGS_HW_MODE) |
6960 | xdp.command = XDP_SETUP_PROG_HW; | ||
6961 | else | ||
6962 | xdp.command = XDP_SETUP_PROG; | ||
6961 | xdp.extack = extack; | 6963 | xdp.extack = extack; |
6964 | xdp.flags = flags; | ||
6962 | xdp.prog = prog; | 6965 | xdp.prog = prog; |
6963 | 6966 | ||
6964 | return xdp_op(dev, &xdp); | 6967 | return xdp_op(dev, &xdp); |
@@ -6984,7 +6987,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, | |||
6984 | ASSERT_RTNL(); | 6987 | ASSERT_RTNL(); |
6985 | 6988 | ||
6986 | xdp_op = xdp_chk = ops->ndo_xdp; | 6989 | xdp_op = xdp_chk = ops->ndo_xdp; |
6987 | if (!xdp_op && (flags & XDP_FLAGS_DRV_MODE)) | 6990 | if (!xdp_op && (flags & (XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE))) |
6988 | return -EOPNOTSUPP; | 6991 | return -EOPNOTSUPP; |
6989 | if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE)) | 6992 | if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE)) |
6990 | xdp_op = generic_xdp_install; | 6993 | xdp_op = generic_xdp_install; |
@@ -7003,7 +7006,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack, | |||
7003 | return PTR_ERR(prog); | 7006 | return PTR_ERR(prog); |
7004 | } | 7007 | } |
7005 | 7008 | ||
7006 | err = dev_xdp_install(dev, xdp_op, extack, prog); | 7009 | err = dev_xdp_install(dev, xdp_op, extack, flags, prog); |
7007 | if (err < 0 && prog) | 7010 | if (err < 0 && prog) |
7008 | bpf_prog_put(prog); | 7011 | bpf_prog_put(prog); |
7009 | 7012 | ||
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 8da89c1136e5..9a1bd510c812 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * Vitaly E. Lavrov RTA_OK arithmetics was wrong. | 16 | * Vitaly E. Lavrov RTA_OK arithmetics was wrong. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/bitops.h> | ||
19 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
21 | #include <linux/types.h> | 22 | #include <linux/types.h> |
@@ -1264,10 +1265,10 @@ static u8 rtnl_xdp_attached_mode(struct net_device *dev, u32 *prog_id) | |||
1264 | *prog_id = generic_xdp_prog->aux->id; | 1265 | *prog_id = generic_xdp_prog->aux->id; |
1265 | return XDP_ATTACHED_SKB; | 1266 | return XDP_ATTACHED_SKB; |
1266 | } | 1267 | } |
1267 | if (ops->ndo_xdp && __dev_xdp_attached(dev, ops->ndo_xdp, prog_id)) | 1268 | if (!ops->ndo_xdp) |
1268 | return XDP_ATTACHED_DRV; | 1269 | return XDP_ATTACHED_NONE; |
1269 | 1270 | ||
1270 | return XDP_ATTACHED_NONE; | 1271 | return __dev_xdp_attached(dev, ops->ndo_xdp, prog_id); |
1271 | } | 1272 | } |
1272 | 1273 | ||
1273 | static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev) | 1274 | static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev) |
@@ -2253,8 +2254,7 @@ static int do_setlink(const struct sk_buff *skb, | |||
2253 | err = -EINVAL; | 2254 | err = -EINVAL; |
2254 | goto errout; | 2255 | goto errout; |
2255 | } | 2256 | } |
2256 | if ((xdp_flags & XDP_FLAGS_SKB_MODE) && | 2257 | if (hweight32(xdp_flags & XDP_FLAGS_MODES) > 1) { |
2257 | (xdp_flags & XDP_FLAGS_DRV_MODE)) { | ||
2258 | err = -EINVAL; | 2258 | err = -EINVAL; |
2259 | goto errout; | 2259 | goto errout; |
2260 | } | 2260 | } |