0001
0002
0003
0004 #include <stdlib.h>
0005 #include <string.h>
0006 #include <bpf/libbpf.h>
0007 #include <linux/rtnetlink.h>
0008 #include <linux/tc_act/tc_bpf.h>
0009
0010 #include "bpf/nlattr.h"
0011 #include "main.h"
0012 #include "netlink_dumper.h"
0013
0014 static void xdp_dump_prog_id(struct nlattr **tb, int attr,
0015 const char *mode,
0016 bool new_json_object)
0017 {
0018 if (!tb[attr])
0019 return;
0020
0021 if (new_json_object)
0022 NET_START_OBJECT
0023 NET_DUMP_STR("mode", " %s", mode);
0024 NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr]))
0025 if (new_json_object)
0026 NET_END_OBJECT
0027 }
0028
0029 static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex,
0030 const char *name)
0031 {
0032 struct nlattr *tb[IFLA_XDP_MAX + 1];
0033 unsigned char mode;
0034
0035 if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0)
0036 return -1;
0037
0038 if (!tb[IFLA_XDP_ATTACHED])
0039 return 0;
0040
0041 mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]);
0042 if (mode == XDP_ATTACHED_NONE)
0043 return 0;
0044
0045 NET_START_OBJECT;
0046 if (name)
0047 NET_DUMP_STR("devname", "%s", name);
0048 NET_DUMP_UINT("ifindex", "(%d)", ifindex);
0049
0050 if (mode == XDP_ATTACHED_MULTI) {
0051 if (json_output) {
0052 jsonw_name(json_wtr, "multi_attachments");
0053 jsonw_start_array(json_wtr);
0054 }
0055 xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true);
0056 xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true);
0057 xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true);
0058 if (json_output)
0059 jsonw_end_array(json_wtr);
0060 } else if (mode == XDP_ATTACHED_DRV) {
0061 xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false);
0062 } else if (mode == XDP_ATTACHED_SKB) {
0063 xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false);
0064 } else if (mode == XDP_ATTACHED_HW) {
0065 xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false);
0066 }
0067
0068 NET_END_OBJECT_FINAL;
0069 return 0;
0070 }
0071
0072 int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb)
0073 {
0074 if (!tb[IFLA_XDP])
0075 return 0;
0076
0077 return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index,
0078 libbpf_nla_getattr_str(tb[IFLA_IFNAME]));
0079 }
0080
0081 static int do_bpf_dump_one_act(struct nlattr *attr)
0082 {
0083 struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
0084
0085 if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0)
0086 return -LIBBPF_ERRNO__NLPARSE;
0087
0088 if (!tb[TCA_ACT_BPF_PARMS])
0089 return -LIBBPF_ERRNO__NLPARSE;
0090
0091 NET_START_OBJECT_NESTED2;
0092 if (tb[TCA_ACT_BPF_NAME])
0093 NET_DUMP_STR("name", "%s",
0094 libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME]));
0095 if (tb[TCA_ACT_BPF_ID])
0096 NET_DUMP_UINT("id", " id %u",
0097 libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID]));
0098 NET_END_OBJECT_NESTED;
0099 return 0;
0100 }
0101
0102 static int do_dump_one_act(struct nlattr *attr)
0103 {
0104 struct nlattr *tb[TCA_ACT_MAX + 1];
0105
0106 if (!attr)
0107 return 0;
0108
0109 if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0)
0110 return -LIBBPF_ERRNO__NLPARSE;
0111
0112 if (tb[TCA_ACT_KIND] &&
0113 strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0)
0114 return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]);
0115
0116 return 0;
0117 }
0118
0119 static int do_bpf_act_dump(struct nlattr *attr)
0120 {
0121 struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
0122 int act, ret;
0123
0124 if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0)
0125 return -LIBBPF_ERRNO__NLPARSE;
0126
0127 NET_START_ARRAY("act", " %s [");
0128 for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) {
0129 ret = do_dump_one_act(tb[act]);
0130 if (ret)
0131 break;
0132 }
0133 NET_END_ARRAY("] ");
0134
0135 return ret;
0136 }
0137
0138 static int do_bpf_filter_dump(struct nlattr *attr)
0139 {
0140 struct nlattr *tb[TCA_BPF_MAX + 1];
0141 int ret;
0142
0143 if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0)
0144 return -LIBBPF_ERRNO__NLPARSE;
0145
0146 if (tb[TCA_BPF_NAME])
0147 NET_DUMP_STR("name", " %s",
0148 libbpf_nla_getattr_str(tb[TCA_BPF_NAME]));
0149 if (tb[TCA_BPF_ID])
0150 NET_DUMP_UINT("id", " id %u",
0151 libbpf_nla_getattr_u32(tb[TCA_BPF_ID]));
0152 if (tb[TCA_BPF_ACT]) {
0153 ret = do_bpf_act_dump(tb[TCA_BPF_ACT]);
0154 if (ret)
0155 return ret;
0156 }
0157
0158 return 0;
0159 }
0160
0161 int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind,
0162 const char *devname, int ifindex)
0163 {
0164 int ret = 0;
0165
0166 if (tb[TCA_OPTIONS] &&
0167 strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) {
0168 NET_START_OBJECT;
0169 if (devname[0] != '\0')
0170 NET_DUMP_STR("devname", "%s", devname);
0171 NET_DUMP_UINT("ifindex", "(%u)", ifindex);
0172 NET_DUMP_STR("kind", " %s", kind);
0173 ret = do_bpf_filter_dump(tb[TCA_OPTIONS]);
0174 NET_END_OBJECT_FINAL;
0175 }
0176
0177 return ret;
0178 }