linux/tools/bpf/bpftool/netlink_dumper.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2// Copyright (C) 2018 Facebook
   3
   4#include <stdlib.h>
   5#include <string.h>
   6#include <bpf/libbpf.h>
   7#include <linux/rtnetlink.h>
   8#include <linux/tc_act/tc_bpf.h>
   9
  10#include "bpf/nlattr.h"
  11#include "main.h"
  12#include "netlink_dumper.h"
  13
  14static void xdp_dump_prog_id(struct nlattr **tb, int attr,
  15                             const char *mode,
  16                             bool new_json_object)
  17{
  18        if (!tb[attr])
  19                return;
  20
  21        if (new_json_object)
  22                NET_START_OBJECT
  23        NET_DUMP_STR("mode", " %s", mode);
  24        NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr]))
  25        if (new_json_object)
  26                NET_END_OBJECT
  27}
  28
  29static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex,
  30                           const char *name)
  31{
  32        struct nlattr *tb[IFLA_XDP_MAX + 1];
  33        unsigned char mode;
  34
  35        if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0)
  36                return -1;
  37
  38        if (!tb[IFLA_XDP_ATTACHED])
  39                return 0;
  40
  41        mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]);
  42        if (mode == XDP_ATTACHED_NONE)
  43                return 0;
  44
  45        NET_START_OBJECT;
  46        if (name)
  47                NET_DUMP_STR("devname", "%s", name);
  48        NET_DUMP_UINT("ifindex", "(%d)", ifindex);
  49
  50        if (mode == XDP_ATTACHED_MULTI) {
  51                if (json_output) {
  52                        jsonw_name(json_wtr, "multi_attachments");
  53                        jsonw_start_array(json_wtr);
  54                }
  55                xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true);
  56                xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true);
  57                xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true);
  58                if (json_output)
  59                        jsonw_end_array(json_wtr);
  60        } else if (mode == XDP_ATTACHED_DRV) {
  61                xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false);
  62        } else if (mode == XDP_ATTACHED_SKB) {
  63                xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false);
  64        } else if (mode == XDP_ATTACHED_HW) {
  65                xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false);
  66        }
  67
  68        NET_END_OBJECT_FINAL;
  69        return 0;
  70}
  71
  72int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb)
  73{
  74        if (!tb[IFLA_XDP])
  75                return 0;
  76
  77        return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index,
  78                               libbpf_nla_getattr_str(tb[IFLA_IFNAME]));
  79}
  80
  81static int do_bpf_dump_one_act(struct nlattr *attr)
  82{
  83        struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
  84
  85        if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0)
  86                return -LIBBPF_ERRNO__NLPARSE;
  87
  88        if (!tb[TCA_ACT_BPF_PARMS])
  89                return -LIBBPF_ERRNO__NLPARSE;
  90
  91        NET_START_OBJECT_NESTED2;
  92        if (tb[TCA_ACT_BPF_NAME])
  93                NET_DUMP_STR("name", "%s",
  94                             libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME]));
  95        if (tb[TCA_ACT_BPF_ID])
  96                NET_DUMP_UINT("id", " id %u",
  97                              libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID]));
  98        NET_END_OBJECT_NESTED;
  99        return 0;
 100}
 101
 102static int do_dump_one_act(struct nlattr *attr)
 103{
 104        struct nlattr *tb[TCA_ACT_MAX + 1];
 105
 106        if (!attr)
 107                return 0;
 108
 109        if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0)
 110                return -LIBBPF_ERRNO__NLPARSE;
 111
 112        if (tb[TCA_ACT_KIND] &&
 113            strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0)
 114                return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]);
 115
 116        return 0;
 117}
 118
 119static int do_bpf_act_dump(struct nlattr *attr)
 120{
 121        struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 122        int act, ret;
 123
 124        if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0)
 125                return -LIBBPF_ERRNO__NLPARSE;
 126
 127        NET_START_ARRAY("act", " %s [");
 128        for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) {
 129                ret = do_dump_one_act(tb[act]);
 130                if (ret)
 131                        break;
 132        }
 133        NET_END_ARRAY("] ");
 134
 135        return ret;
 136}
 137
 138static int do_bpf_filter_dump(struct nlattr *attr)
 139{
 140        struct nlattr *tb[TCA_BPF_MAX + 1];
 141        int ret;
 142
 143        if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0)
 144                return -LIBBPF_ERRNO__NLPARSE;
 145
 146        if (tb[TCA_BPF_NAME])
 147                NET_DUMP_STR("name", " %s",
 148                             libbpf_nla_getattr_str(tb[TCA_BPF_NAME]));
 149        if (tb[TCA_BPF_ID])
 150                NET_DUMP_UINT("id", " id %u",
 151                              libbpf_nla_getattr_u32(tb[TCA_BPF_ID]));
 152        if (tb[TCA_BPF_ACT]) {
 153                ret = do_bpf_act_dump(tb[TCA_BPF_ACT]);
 154                if (ret)
 155                        return ret;
 156        }
 157
 158        return 0;
 159}
 160
 161int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind,
 162                   const char *devname, int ifindex)
 163{
 164        int ret = 0;
 165
 166        if (tb[TCA_OPTIONS] &&
 167            strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) {
 168                NET_START_OBJECT;
 169                if (devname[0] != '\0')
 170                        NET_DUMP_STR("devname", "%s", devname);
 171                NET_DUMP_UINT("ifindex", "(%u)", ifindex);
 172                NET_DUMP_STR("kind", " %s", kind);
 173                ret = do_bpf_filter_dump(tb[TCA_OPTIONS]);
 174                NET_END_OBJECT_FINAL;
 175        }
 176
 177        return ret;
 178}
 179