Blob Blame History Raw
From 907e2adbcb6e02453972d5ada93de7bbaefedb2a Mon Sep 17 00:00:00 2001
From: Andrea Claudi <aclaudi@redhat.com>
Date: Thu, 13 Jun 2019 14:37:56 +0200
Subject: [PATCH] iplink: add support for reporting multiple XDP programs

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1716361
Upstream Status: iproute2.git commit da083b5a483bf

commit da083b5a483bfd52dfe72912f62a3bc16d775b87
Author: Jakub Kicinski <jakub.kicinski@netronome.com>
Date:   Fri Jul 13 15:54:51 2018 -0700

    iplink: add support for reporting multiple XDP programs

    Kernel now supports attaching XDP programs in the driver
    and hardware at the same time.  Print that information
    correctly.

    In case there are multiple programs attached kernel will
    not provide IFLA_XDP_PROG_ID, so don't expect it to be
    there (this also improves the printing for very old kernels
    slightly, as it avoids unnecessary "prog/xdp" line).

    In short mode preserve the current outputs but don't print
    IDs if there are multiple.

    6: netdevsim0: <BROADCAST,NOARP> mtu 1500 xdpoffload/id:11 qdisc [...]

    and:

    6: netdevsim0: <BROADCAST,NOARP> mtu 1500 xdpmulti qdisc [...]

    ip link output will keep using prog/xdp prefix if only one program
    is attached, but can also print multiple program lines:

        prog/xdp id 8 tag fc7a51d1a693a99e jited

    vs:

        prog/xdpdrv id 8 tag fc7a51d1a693a99e jited
        prog/xdpoffload id 9 tag fc7a51d1a693a99e

    JSON output gains a new array called "attached" which will
    contain the full list of attached programs along with their
    attachment modes:

            "xdp": {
                "mode": 3,
                "prog": {
                    "id": 11,
                    "tag": "fc7a51d1a693a99e",
                    "jited": 0
                },
                "attached": [ {
                        "mode": 3,
                        "prog": {
                            "id": 11,
                            "tag": "fc7a51d1a693a99e",
                            "jited": 0
                        }
                    } ]
            },

    In case there are multiple programs attached the general "xdp"
    section will not contain program information:

            "xdp": {
                "mode": 4,
                "attached": [ {
                        "mode": 1,
                        "prog": {
                            "id": 10,
                            "tag": "fc7a51d1a693a99e",
                            "jited": 1
                        }
                    },{
                        "mode": 3,
                        "prog": {
                            "id": 11,
                            "tag": "fc7a51d1a693a99e",
                            "jited": 0
                        }
                    } ]
            },

    Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
    Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
    Acked-by: Daniel Borkmann <daniel@iogearbox.net>
    Signed-off-by: David Ahern <dsahern@gmail.com>
---
 ip/iplink_xdp.c | 73 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 61 insertions(+), 12 deletions(-)

diff --git a/ip/iplink_xdp.c b/ip/iplink_xdp.c
index dd4fd1fd3a3b1..4a490bc8fb66c 100644
--- a/ip/iplink_xdp.c
+++ b/ip/iplink_xdp.c
@@ -91,6 +91,18 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req,
 	return 0;
 }
 
+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;
@@ -104,13 +116,48 @@ static void xdp_dump_json(struct rtattr *tb[IFLA_XDP_MAX + 1])
 	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];
-	__u32 prog_id = 0;
 	__u8 mode;
 
 	parse_rtattr_nested(tb, IFLA_XDP_MAX, xdp);
@@ -124,27 +171,29 @@ void xdp_dump(FILE *fp, struct rtattr *xdp, bool link, bool details)
 	else if (is_json_context())
 		return details ? (void)0 : xdp_dump_json(tb);
 	else if (details && link)
-		fprintf(fp, "%s    prog/xdp", _SL_);
+		/* 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])
-		prog_id = rta_getattr_u32(tb[IFLA_XDP_PROG_ID]);
-	if (!details) {
-		if (prog_id && !link)
-			fprintf(fp, "/id:%u", prog_id);
-		fprintf(fp, " ");
-		return;
+	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");
 	}
 
-	if (prog_id) {
+	if (!details || !link)
 		fprintf(fp, " ");
-		bpf_dump_prog_info(fp, prog_id);
-	}
 }
-- 
2.20.1