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