xdp: add flag to enforce driver mode
authorDaniel Borkmann <daniel@iogearbox.net>
Thu, 11 May 2017 23:04:45 +0000 (01:04 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 12 May 2017 01:30:57 +0000 (21:30 -0400)
After commit b5cdae3291f7 ("net: Generic XDP") we automatically fall
back to a generic XDP variant if the driver does not support native
XDP. Allow for an option where the user can specify that always the
native XDP variant should be selected and in case it's not supported
by a driver, just bail out.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/if_link.h
net/core/dev.c
net/core/rtnetlink.c
samples/bpf/xdp1_user.c
samples/bpf/xdp_tx_iptunnel_user.c

index 8e56ac70e0d1a3536a43aff83370e5b3bd5bb0b4..549ac8a98b447e616e5c9f99430085e30be95a74 100644 (file)
@@ -888,9 +888,11 @@ enum {
 /* XDP section */
 
 #define XDP_FLAGS_UPDATE_IF_NOEXIST    (1U << 0)
-#define XDP_FLAGS_SKB_MODE             (2U << 0)
+#define XDP_FLAGS_SKB_MODE             (1U << 1)
+#define XDP_FLAGS_DRV_MODE             (1U << 2)
 #define XDP_FLAGS_MASK                 (XDP_FLAGS_UPDATE_IF_NOEXIST | \
-                                        XDP_FLAGS_SKB_MODE)
+                                        XDP_FLAGS_SKB_MODE | \
+                                        XDP_FLAGS_DRV_MODE)
 
 enum {
        IFLA_XDP_UNSPEC,
index 96cf83da0d66b2db07d5504c4c3aec7da735ea46..e56cb71351d4d6a48878a4e70cdd331dfba95ac0 100644 (file)
@@ -6873,6 +6873,8 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
        ASSERT_RTNL();
 
        xdp_op = ops->ndo_xdp;
+       if (!xdp_op && (flags & XDP_FLAGS_DRV_MODE))
+               return -EOPNOTSUPP;
        if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE))
                xdp_op = generic_xdp_install;
 
index bcb0f610ee422a12ad6b8ae41763296ba0fa3c6a..dda9f1636356890943d2788015f2723339685014 100644 (file)
@@ -2199,6 +2199,11 @@ static int do_setlink(const struct sk_buff *skb,
                                err = -EINVAL;
                                goto errout;
                        }
+                       if ((xdp_flags & XDP_FLAGS_SKB_MODE) &&
+                           (xdp_flags & XDP_FLAGS_DRV_MODE)) {
+                               err = -EINVAL;
+                               goto errout;
+                       }
                }
 
                if (xdp[IFLA_XDP_FD]) {
index 378850c70eb81afdbc5283611573f89ea4d8923e..17be9ea3ecb2f80389f37996fdab277727ecc5ed 100644 (file)
@@ -62,13 +62,14 @@ static void usage(const char *prog)
        fprintf(stderr,
                "usage: %s [OPTS] IFINDEX\n\n"
                "OPTS:\n"
-               "    -S    use skb-mode\n",
+               "    -S    use skb-mode\n"
+               "    -N    enforce native mode\n",
                prog);
 }
 
 int main(int argc, char **argv)
 {
-       const char *optstr = "S";
+       const char *optstr = "SN";
        char filename[256];
        int opt;
 
@@ -77,6 +78,9 @@ int main(int argc, char **argv)
                case 'S':
                        xdp_flags |= XDP_FLAGS_SKB_MODE;
                        break;
+               case 'N':
+                       xdp_flags |= XDP_FLAGS_DRV_MODE;
+                       break;
                default:
                        usage(basename(argv[0]));
                        return 1;
index 92b8bde9337c8cec6128e73d23d307b628ba5a38..631cdcc41c97e957166f1b46cb46041ba4f2b528 100644 (file)
@@ -79,6 +79,8 @@ static void usage(const char *cmd)
        printf("    -m <dest-MAC> Used in sending the IP Tunneled pkt\n");
        printf("    -T <stop-after-X-seconds> Default: 0 (forever)\n");
        printf("    -P <IP-Protocol> Default is TCP\n");
+       printf("    -S use skb-mode\n");
+       printf("    -N enforce native mode\n");
        printf("    -h Display this help\n");
 }
 
@@ -138,7 +140,7 @@ int main(int argc, char **argv)
 {
        unsigned char opt_flags[256] = {};
        unsigned int kill_after_s = 0;
-       const char *optstr = "i:a:p:s:d:m:T:P:Sh";
+       const char *optstr = "i:a:p:s:d:m:T:P:SNh";
        int min_port = 0, max_port = 0;
        struct iptnl_info tnl = {};
        struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
@@ -206,6 +208,9 @@ int main(int argc, char **argv)
                case 'S':
                        xdp_flags |= XDP_FLAGS_SKB_MODE;
                        break;
+               case 'N':
+                       xdp_flags |= XDP_FLAGS_DRV_MODE;
+                       break;
                default:
                        usage(argv[0]);
                        return 1;