Merge tag 'amd-drm-fixes-5.11-2020-12-23' of git://people.freedesktop.org/~agd5f...
[linux-2.6-microblaze.git] / net / core / dev.c
index 8588ade..38412e7 100644 (file)
@@ -8917,6 +8917,17 @@ static struct bpf_prog *dev_xdp_prog(struct net_device *dev,
        return dev->xdp_state[mode].prog;
 }
 
+static u8 dev_xdp_prog_count(struct net_device *dev)
+{
+       u8 count = 0;
+       int i;
+
+       for (i = 0; i < __MAX_XDP_MODE; i++)
+               if (dev->xdp_state[i].prog || dev->xdp_state[i].link)
+                       count++;
+       return count;
+}
+
 u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
 {
        struct bpf_prog *prog = dev_xdp_prog(dev, mode);
@@ -9007,6 +9018,7 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
                          struct bpf_xdp_link *link, struct bpf_prog *new_prog,
                          struct bpf_prog *old_prog, u32 flags)
 {
+       unsigned int num_modes = hweight32(flags & XDP_FLAGS_MODES);
        struct bpf_prog *cur_prog;
        enum bpf_xdp_mode mode;
        bpf_op_t bpf_op;
@@ -9022,11 +9034,17 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
                NL_SET_ERR_MSG(extack, "Invalid XDP flags for BPF link attachment");
                return -EINVAL;
        }
-       /* just one XDP mode bit should be set, zero defaults to SKB mode */
-       if (hweight32(flags & XDP_FLAGS_MODES) > 1) {
+       /* just one XDP mode bit should be set, zero defaults to drv/skb mode */
+       if (num_modes > 1) {
                NL_SET_ERR_MSG(extack, "Only one XDP mode flag can be set");
                return -EINVAL;
        }
+       /* avoid ambiguity if offload + drv/skb mode progs are both loaded */
+       if (!num_modes && dev_xdp_prog_count(dev) > 1) {
+               NL_SET_ERR_MSG(extack,
+                              "More than one program loaded, unset mode is ambiguous");
+               return -EINVAL;
+       }
        /* old_prog != NULL implies XDP_FLAGS_REPLACE is set */
        if (old_prog && !(flags & XDP_FLAGS_REPLACE)) {
                NL_SET_ERR_MSG(extack, "XDP_FLAGS_REPLACE is not specified");