]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/iplink_xdp.c
iplink_can: add Classical CAN frame LEN8_DLC support
[mirror_iproute2.git] / ip / iplink_xdp.c
index 4857f50c80dea59493cd4d5a8589722ff4c67c15..4a490bc8fb66c65448ba860355d8837be2eec3c0 100644 (file)
@@ -14,8 +14,9 @@
 
 #include <linux/bpf.h>
 
-#include "xdp.h"
 #include "bpf_util.h"
+#include "utils.h"
+#include "ip_common.h"
 
 extern int force;
 
@@ -47,9 +48,11 @@ static int xdp_delete(struct xdp_req *xdp)
        return 0;
 }
 
-int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic)
+int xdp_parse(int *argc, char ***argv, struct iplink_req *req,
+             const char *ifname, bool generic, bool drv, bool offload)
 {
        struct bpf_cfg_in cfg = {
+               .type = BPF_PROG_TYPE_XDP,
                .argc = *argc,
                .argv = *argv,
        };
@@ -57,10 +60,22 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic)
                .req = req,
        };
 
+       if (offload) {
+               int ifindex = ll_name_to_index(ifname);
+
+               if (!ifindex)
+                       incomplete_command();
+               cfg.ifindex = ifindex;
+       }
+
        if (!force)
                xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST;
        if (generic)
                xdp.flags |= XDP_FLAGS_SKB_MODE;
+       if (drv)
+               xdp.flags |= XDP_FLAGS_DRV_MODE;
+       if (offload)
+               xdp.flags |= XDP_FLAGS_HW_MODE;
 
        if (*argc == 1) {
                if (strcmp(**argv, "none") == 0 ||
@@ -68,7 +83,7 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic)
                        return xdp_delete(&xdp);
        }
 
-       if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp))
+       if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp))
                return -1;
 
        *argc = cfg.argc;
@@ -76,7 +91,71 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic)
        return 0;
 }
 
-void xdp_dump(FILE *fp, struct rtattr *xdp)
+static void xdp_dump_json_one(struct rtattr *tb[IFLA_XDP_MAX + 1], __u32 attr,
+                             __u8 mode)
+{
+       if (!tb[attr])
+               return;
+
+       open_json_object(NULL);
+       print_uint(PRINT_JSON, "mode", NULL, mode);
+       bpf_dump_prog_info(NULL, rta_getattr_u32(tb[attr]));
+       close_json_object();
+}
+
+static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
+{
+       __u32 prog_id = 0;
+       __u8 mode;
+
+       mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
+       if (tb[IFLA_XDP_PROG_ID])
+               prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
+
+       open_json_object("xdp");
+       print_uint(PRINT_JSON, "mode", NULL, mode);
+       if (prog_id)
+               bpf_dump_prog_info(NULL, prog_id);
+
+       open_json_array(PRINT_JSON, "attached");
+       if (tb[IFLA_XDP_SKB_PROG_ID] ||
+           tb[IFLA_XDP_DRV_PROG_ID] ||
+           tb[IFLA_XDP_HW_PROG_ID]) {
+               xdp_dump_json_one(tb, IFLA_XDP_SKB_PROG_ID, XDP_ATTACHED_SKB);
+               xdp_dump_json_one(tb, IFLA_XDP_DRV_PROG_ID, XDP_ATTACHED_DRV);
+               xdp_dump_json_one(tb, IFLA_XDP_HW_PROG_ID, XDP_ATTACHED_HW);
+       } else if (tb[IFLA_XDP_PROG_ID]) {
+               /* Older kernel - use IFLA_XDP_PROG_ID */
+               xdp_dump_json_one(tb, IFLA_XDP_PROG_ID, mode);
+       }
+       close_json_array(PRINT_JSON, NULL);
+
+       close_json_object();
+}
+
+static void xdp_dump_prog_one(FILE *fp, struct rtattr *tb[IFLA_XDP_MAX + 1],
+                             __u32 attr, bool link, bool details,
+                             const char *pfx)
+{
+       __u32 prog_id;
+
+       if (!tb[attr])
+               return;
+
+       prog_id = rta_getattr_u32(tb[attr]);
+       if (!details) {
+               if (prog_id && !link && attr == IFLA_XDP_PROG_ID)
+                       fprintf(fp, "/id:%u", prog_id);
+               return;
+       }
+
+       if (prog_id) {
+               fprintf(fp, "%s    prog/xdp%s ", _SL_, pfx);
+               bpf_dump_prog_info(fp, prog_id);
+       }
+}
+
+void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
 {
        struct rtattr *tb[IFLA_XDP_MAX + 1];
        __u8 mode;
@@ -89,16 +168,32 @@ void xdp_dump(FILE *fp, struct rtattr *xdp)
        mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
        if (mode == XDP_ATTACHED_NONE)
                return;
+       else if (is_json_context())
+               return details ? (void)0 : xdp_dump_json(tb);
+       else if (details && link)
+               /* don't print mode */;
        else if (mode == XDP_ATTACHED_DRV)
                fprintf(fp, "xdp");
        else if (mode == XDP_ATTACHED_SKB)
                fprintf(fp, "xdpgeneric");
+       else if (mode == XDP_ATTACHED_HW)
+               fprintf(fp, "xdpoffload");
+       else if (mode == XDP_ATTACHED_MULTI)
+               fprintf(fp, "xdpmulti");
        else
                fprintf(fp, "xdp[%u]", mode);
 
-       if (tb[IFLA_XDP_PROG_ID])
-               fprintf(fp, "/id:%u",
-                       rta_getattr_u32(tb[IFLA_XDP_PROG_ID]));
+       xdp_dump_prog_one(fp, tb, IFLA_XDP_PROG_ID, link, details, "");
+
+       if (mode == XDP_ATTACHED_MULTI) {
+               xdp_dump_prog_one(fp, tb, IFLA_XDP_SKB_PROG_ID, link, details,
+                                 "generic");
+               xdp_dump_prog_one(fp, tb, IFLA_XDP_DRV_PROG_ID, link, details,
+                                 "drv");
+               xdp_dump_prog_one(fp, tb, IFLA_XDP_HW_PROG_ID, link, details,
+                                 "offload");
+       }
 
-       fprintf(fp, " ");
+       if (!details || !link)
+               fprintf(fp, " ");
 }