1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski * tunnel.c - device tunnel information
3*1b481fc3SMaciej Żenczykowski *
4*1b481fc3SMaciej Żenczykowski * Implementation of "ethtool --show-tunnels <dev>"
5*1b481fc3SMaciej Żenczykowski */
6*1b481fc3SMaciej Żenczykowski
7*1b481fc3SMaciej Żenczykowski #include <errno.h>
8*1b481fc3SMaciej Żenczykowski #include <string.h>
9*1b481fc3SMaciej Żenczykowski #include <stdio.h>
10*1b481fc3SMaciej Żenczykowski #include <arpa/inet.h>
11*1b481fc3SMaciej Żenczykowski
12*1b481fc3SMaciej Żenczykowski #include "../common.h"
13*1b481fc3SMaciej Żenczykowski #include "../internal.h"
14*1b481fc3SMaciej Żenczykowski
15*1b481fc3SMaciej Żenczykowski #include "bitset.h"
16*1b481fc3SMaciej Żenczykowski #include "netlink.h"
17*1b481fc3SMaciej Żenczykowski #include "strset.h"
18*1b481fc3SMaciej Żenczykowski
19*1b481fc3SMaciej Żenczykowski /* TUNNEL_INFO_GET */
20*1b481fc3SMaciej Żenczykowski
21*1b481fc3SMaciej Żenczykowski static int
tunnel_info_strings_load(struct nl_context * nlctx,const struct stringset ** strings)22*1b481fc3SMaciej Żenczykowski tunnel_info_strings_load(struct nl_context *nlctx,
23*1b481fc3SMaciej Żenczykowski const struct stringset **strings)
24*1b481fc3SMaciej Żenczykowski {
25*1b481fc3SMaciej Żenczykowski int ret;
26*1b481fc3SMaciej Żenczykowski
27*1b481fc3SMaciej Żenczykowski if (*strings)
28*1b481fc3SMaciej Żenczykowski return 0;
29*1b481fc3SMaciej Żenczykowski ret = netlink_init_ethnl2_socket(nlctx);
30*1b481fc3SMaciej Żenczykowski if (ret < 0)
31*1b481fc3SMaciej Żenczykowski return ret;
32*1b481fc3SMaciej Żenczykowski *strings = global_stringset(ETH_SS_UDP_TUNNEL_TYPES,
33*1b481fc3SMaciej Żenczykowski nlctx->ethnl2_socket);
34*1b481fc3SMaciej Żenczykowski return 0;
35*1b481fc3SMaciej Żenczykowski }
36*1b481fc3SMaciej Żenczykowski
37*1b481fc3SMaciej Żenczykowski static int
tunnel_info_dump_udp_entry(struct nl_context * nlctx,const struct nlattr * entry,const struct stringset ** strings)38*1b481fc3SMaciej Żenczykowski tunnel_info_dump_udp_entry(struct nl_context *nlctx, const struct nlattr *entry,
39*1b481fc3SMaciej Żenczykowski const struct stringset **strings)
40*1b481fc3SMaciej Żenczykowski {
41*1b481fc3SMaciej Żenczykowski const struct nlattr *entry_tb[ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX + 1] = {};
42*1b481fc3SMaciej Żenczykowski DECLARE_ATTR_TB_INFO(entry_tb);
43*1b481fc3SMaciej Żenczykowski const struct nlattr *attr;
44*1b481fc3SMaciej Żenczykowski unsigned int port, type;
45*1b481fc3SMaciej Żenczykowski int ret;
46*1b481fc3SMaciej Żenczykowski
47*1b481fc3SMaciej Żenczykowski if (tunnel_info_strings_load(nlctx, strings))
48*1b481fc3SMaciej Żenczykowski return 1;
49*1b481fc3SMaciej Żenczykowski
50*1b481fc3SMaciej Żenczykowski ret = mnl_attr_parse_nested(entry, attr_cb, &entry_tb_info);
51*1b481fc3SMaciej Żenczykowski if (ret < 0) {
52*1b481fc3SMaciej Żenczykowski fprintf(stderr, "malformed netlink message (udp entry)\n");
53*1b481fc3SMaciej Żenczykowski return 1;
54*1b481fc3SMaciej Żenczykowski }
55*1b481fc3SMaciej Żenczykowski
56*1b481fc3SMaciej Żenczykowski attr = entry_tb[ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT];
57*1b481fc3SMaciej Żenczykowski if (!attr || mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
58*1b481fc3SMaciej Żenczykowski fprintf(stderr, "malformed netlink message (port)\n");
59*1b481fc3SMaciej Żenczykowski return 1;
60*1b481fc3SMaciej Żenczykowski }
61*1b481fc3SMaciej Żenczykowski port = ntohs(mnl_attr_get_u16(attr));
62*1b481fc3SMaciej Żenczykowski
63*1b481fc3SMaciej Żenczykowski attr = entry_tb[ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE];
64*1b481fc3SMaciej Żenczykowski if (!attr || mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
65*1b481fc3SMaciej Żenczykowski fprintf(stderr, "malformed netlink message (tunnel type)\n");
66*1b481fc3SMaciej Żenczykowski return 1;
67*1b481fc3SMaciej Żenczykowski }
68*1b481fc3SMaciej Żenczykowski type = mnl_attr_get_u32(attr);
69*1b481fc3SMaciej Żenczykowski
70*1b481fc3SMaciej Żenczykowski printf(" port %d, %s\n", port, get_string(*strings, type));
71*1b481fc3SMaciej Żenczykowski
72*1b481fc3SMaciej Żenczykowski return 0;
73*1b481fc3SMaciej Żenczykowski }
74*1b481fc3SMaciej Żenczykowski
tunnel_info_dump_cb(unsigned int idx,const char * name,bool val,void * data)75*1b481fc3SMaciej Żenczykowski static void tunnel_info_dump_cb(unsigned int idx, const char *name, bool val,
76*1b481fc3SMaciej Żenczykowski void *data)
77*1b481fc3SMaciej Żenczykowski {
78*1b481fc3SMaciej Żenczykowski bool *first = data;
79*1b481fc3SMaciej Żenczykowski
80*1b481fc3SMaciej Żenczykowski if (!val)
81*1b481fc3SMaciej Żenczykowski return;
82*1b481fc3SMaciej Żenczykowski
83*1b481fc3SMaciej Żenczykowski if (!*first)
84*1b481fc3SMaciej Żenczykowski putchar(',');
85*1b481fc3SMaciej Żenczykowski *first = false;
86*1b481fc3SMaciej Żenczykowski
87*1b481fc3SMaciej Żenczykowski if (name)
88*1b481fc3SMaciej Żenczykowski printf(" %s", name);
89*1b481fc3SMaciej Żenczykowski else
90*1b481fc3SMaciej Żenczykowski printf(" bit%u", idx);
91*1b481fc3SMaciej Żenczykowski }
92*1b481fc3SMaciej Żenczykowski
93*1b481fc3SMaciej Żenczykowski static int
tunnel_info_dump_list(struct nl_context * nlctx,const struct nlattr * attr,const struct stringset ** strings)94*1b481fc3SMaciej Żenczykowski tunnel_info_dump_list(struct nl_context *nlctx, const struct nlattr *attr,
95*1b481fc3SMaciej Żenczykowski const struct stringset **strings)
96*1b481fc3SMaciej Żenczykowski {
97*1b481fc3SMaciej Żenczykowski bool first = true;
98*1b481fc3SMaciej Żenczykowski int ret;
99*1b481fc3SMaciej Żenczykowski
100*1b481fc3SMaciej Żenczykowski if (bitset_is_empty(attr, false, &ret) || ret) {
101*1b481fc3SMaciej Żenczykowski if (ret)
102*1b481fc3SMaciej Żenczykowski return 1;
103*1b481fc3SMaciej Żenczykowski
104*1b481fc3SMaciej Żenczykowski printf(" Types: none (static entries)\n");
105*1b481fc3SMaciej Żenczykowski return 0;
106*1b481fc3SMaciej Żenczykowski }
107*1b481fc3SMaciej Żenczykowski
108*1b481fc3SMaciej Żenczykowski if (bitset_is_compact(attr) &&
109*1b481fc3SMaciej Żenczykowski tunnel_info_strings_load(nlctx, strings))
110*1b481fc3SMaciej Żenczykowski return 1;
111*1b481fc3SMaciej Żenczykowski
112*1b481fc3SMaciej Żenczykowski printf(" Types:");
113*1b481fc3SMaciej Żenczykowski ret = walk_bitset(attr, *strings, tunnel_info_dump_cb, &first);
114*1b481fc3SMaciej Żenczykowski putchar('\n');
115*1b481fc3SMaciej Żenczykowski return ret;
116*1b481fc3SMaciej Żenczykowski }
117*1b481fc3SMaciej Żenczykowski
118*1b481fc3SMaciej Żenczykowski static int
tunnel_info_dump_udp_table(const struct nlattr * table,struct nl_context * nlctx,const struct stringset ** strings)119*1b481fc3SMaciej Żenczykowski tunnel_info_dump_udp_table(const struct nlattr *table, struct nl_context *nlctx,
120*1b481fc3SMaciej Żenczykowski const struct stringset **strings)
121*1b481fc3SMaciej Żenczykowski {
122*1b481fc3SMaciej Żenczykowski const struct nlattr *table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_MAX + 1] = {};
123*1b481fc3SMaciej Żenczykowski DECLARE_ATTR_TB_INFO(table_tb);
124*1b481fc3SMaciej Żenczykowski const struct nlattr *attr;
125*1b481fc3SMaciej Żenczykowski int i, ret;
126*1b481fc3SMaciej Żenczykowski
127*1b481fc3SMaciej Żenczykowski ret = mnl_attr_parse_nested(table, attr_cb, &table_tb_info);
128*1b481fc3SMaciej Żenczykowski if (ret < 0) {
129*1b481fc3SMaciej Żenczykowski fprintf(stderr, "malformed netlink message (udp table)\n");
130*1b481fc3SMaciej Żenczykowski return 1;
131*1b481fc3SMaciej Żenczykowski }
132*1b481fc3SMaciej Żenczykowski
133*1b481fc3SMaciej Żenczykowski attr = table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE];
134*1b481fc3SMaciej Żenczykowski if (!attr || mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
135*1b481fc3SMaciej Żenczykowski fprintf(stderr, "malformed netlink message (table size)\n");
136*1b481fc3SMaciej Żenczykowski return 1;
137*1b481fc3SMaciej Żenczykowski }
138*1b481fc3SMaciej Żenczykowski printf(" Size: %d\n", mnl_attr_get_u32(attr));
139*1b481fc3SMaciej Żenczykowski
140*1b481fc3SMaciej Żenczykowski attr = table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES];
141*1b481fc3SMaciej Żenczykowski if (!attr || tunnel_info_dump_list(nlctx, attr, strings)) {
142*1b481fc3SMaciej Żenczykowski fprintf(stderr, "malformed netlink message (types)\n");
143*1b481fc3SMaciej Żenczykowski return 1;
144*1b481fc3SMaciej Żenczykowski }
145*1b481fc3SMaciej Żenczykowski
146*1b481fc3SMaciej Żenczykowski if (!table_tb[ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY]) {
147*1b481fc3SMaciej Żenczykowski printf(" No entries\n");
148*1b481fc3SMaciej Żenczykowski return 0;
149*1b481fc3SMaciej Żenczykowski }
150*1b481fc3SMaciej Żenczykowski
151*1b481fc3SMaciej Żenczykowski i = 0;
152*1b481fc3SMaciej Żenczykowski mnl_attr_for_each_nested(attr, table) {
153*1b481fc3SMaciej Żenczykowski if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY)
154*1b481fc3SMaciej Żenczykowski i++;
155*1b481fc3SMaciej Żenczykowski }
156*1b481fc3SMaciej Żenczykowski
157*1b481fc3SMaciej Żenczykowski printf(" Entries (%d):\n", i++);
158*1b481fc3SMaciej Żenczykowski mnl_attr_for_each_nested(attr, table) {
159*1b481fc3SMaciej Żenczykowski if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY)
160*1b481fc3SMaciej Żenczykowski if (tunnel_info_dump_udp_entry(nlctx, attr, strings))
161*1b481fc3SMaciej Żenczykowski return 1;
162*1b481fc3SMaciej Żenczykowski }
163*1b481fc3SMaciej Żenczykowski
164*1b481fc3SMaciej Żenczykowski return 0;
165*1b481fc3SMaciej Żenczykowski }
166*1b481fc3SMaciej Żenczykowski
167*1b481fc3SMaciej Żenczykowski static int
tunnel_info_dump_udp(const struct nlattr * udp_ports,struct nl_context * nlctx)168*1b481fc3SMaciej Żenczykowski tunnel_info_dump_udp(const struct nlattr *udp_ports, struct nl_context *nlctx)
169*1b481fc3SMaciej Żenczykowski {
170*1b481fc3SMaciej Żenczykowski const struct stringset *strings = NULL;
171*1b481fc3SMaciej Żenczykowski const struct nlattr *table;
172*1b481fc3SMaciej Żenczykowski int i, err;
173*1b481fc3SMaciej Żenczykowski
174*1b481fc3SMaciej Żenczykowski i = 0;
175*1b481fc3SMaciej Żenczykowski mnl_attr_for_each_nested(table, udp_ports) {
176*1b481fc3SMaciej Żenczykowski if (mnl_attr_get_type(table) != ETHTOOL_A_TUNNEL_UDP_TABLE)
177*1b481fc3SMaciej Żenczykowski continue;
178*1b481fc3SMaciej Żenczykowski
179*1b481fc3SMaciej Żenczykowski printf(" UDP port table %d: \n", i++);
180*1b481fc3SMaciej Żenczykowski err = tunnel_info_dump_udp_table(table, nlctx, &strings);
181*1b481fc3SMaciej Żenczykowski if (err)
182*1b481fc3SMaciej Żenczykowski return err;
183*1b481fc3SMaciej Żenczykowski }
184*1b481fc3SMaciej Żenczykowski
185*1b481fc3SMaciej Żenczykowski return 0;
186*1b481fc3SMaciej Żenczykowski }
187*1b481fc3SMaciej Żenczykowski
tunnel_info_reply_cb(const struct nlmsghdr * nlhdr,void * data)188*1b481fc3SMaciej Żenczykowski static int tunnel_info_reply_cb(const struct nlmsghdr *nlhdr, void *data)
189*1b481fc3SMaciej Żenczykowski {
190*1b481fc3SMaciej Żenczykowski const struct nlattr *tb[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = {};
191*1b481fc3SMaciej Żenczykowski DECLARE_ATTR_TB_INFO(tb);
192*1b481fc3SMaciej Żenczykowski const struct nlattr *udp_ports;
193*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = data;
194*1b481fc3SMaciej Żenczykowski bool silent;
195*1b481fc3SMaciej Żenczykowski int err_ret;
196*1b481fc3SMaciej Żenczykowski int ret;
197*1b481fc3SMaciej Żenczykowski
198*1b481fc3SMaciej Żenczykowski silent = nlctx->is_dump;
199*1b481fc3SMaciej Żenczykowski err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
200*1b481fc3SMaciej Żenczykowski ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
201*1b481fc3SMaciej Żenczykowski if (ret < 0)
202*1b481fc3SMaciej Żenczykowski return err_ret;
203*1b481fc3SMaciej Żenczykowski nlctx->devname = get_dev_name(tb[ETHTOOL_A_TUNNEL_INFO_HEADER]);
204*1b481fc3SMaciej Żenczykowski if (!dev_ok(nlctx))
205*1b481fc3SMaciej Żenczykowski return err_ret;
206*1b481fc3SMaciej Żenczykowski
207*1b481fc3SMaciej Żenczykowski printf("Tunnel information for %s:\n", nlctx->devname);
208*1b481fc3SMaciej Żenczykowski
209*1b481fc3SMaciej Żenczykowski udp_ports = tb[ETHTOOL_A_TUNNEL_INFO_UDP_PORTS];
210*1b481fc3SMaciej Żenczykowski if (udp_ports)
211*1b481fc3SMaciej Żenczykowski if (tunnel_info_dump_udp(udp_ports, nlctx))
212*1b481fc3SMaciej Żenczykowski return err_ret;
213*1b481fc3SMaciej Żenczykowski
214*1b481fc3SMaciej Żenczykowski return MNL_CB_OK;
215*1b481fc3SMaciej Żenczykowski }
216*1b481fc3SMaciej Żenczykowski
nl_gtunnels(struct cmd_context * ctx)217*1b481fc3SMaciej Żenczykowski int nl_gtunnels(struct cmd_context *ctx)
218*1b481fc3SMaciej Żenczykowski {
219*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = ctx->nlctx;
220*1b481fc3SMaciej Żenczykowski struct nl_socket *nlsk = nlctx->ethnl_socket;
221*1b481fc3SMaciej Żenczykowski int ret;
222*1b481fc3SMaciej Żenczykowski
223*1b481fc3SMaciej Żenczykowski if (netlink_cmd_check(ctx, ETHTOOL_MSG_TUNNEL_INFO_GET, true))
224*1b481fc3SMaciej Żenczykowski return -EOPNOTSUPP;
225*1b481fc3SMaciej Żenczykowski if (ctx->argc > 0) {
226*1b481fc3SMaciej Żenczykowski fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
227*1b481fc3SMaciej Żenczykowski *ctx->argp);
228*1b481fc3SMaciej Żenczykowski return 1;
229*1b481fc3SMaciej Żenczykowski }
230*1b481fc3SMaciej Żenczykowski
231*1b481fc3SMaciej Żenczykowski ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_TUNNEL_INFO_GET,
232*1b481fc3SMaciej Żenczykowski ETHTOOL_A_TUNNEL_INFO_HEADER, 0);
233*1b481fc3SMaciej Żenczykowski if (ret < 0)
234*1b481fc3SMaciej Żenczykowski return ret;
235*1b481fc3SMaciej Żenczykowski return nlsock_send_get_request(nlsk, tunnel_info_reply_cb);
236*1b481fc3SMaciej Żenczykowski }
237