1
2
3
4
5
6
7
8
9
10
11
12#include <stdio.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
15#include <linux/if_link.h>
16#include <linux/if_bridge.h>
17
18#include "rt_names.h"
19#include "utils.h"
20#include "ip_common.h"
21
22static void print_explain(FILE *f)
23{
24 fprintf(f,
25 "Usage: ... bridge_slave [ fdb_flush ]\n"
26 " [ state STATE ]\n"
27 " [ priority PRIO ]\n"
28 " [ cost COST ]\n"
29 " [ guard {on | off} ]\n"
30 " [ hairpin {on | off} ]\n"
31 " [ fastleave {on | off} ]\n"
32 " [ root_block {on | off} ]\n"
33 " [ learning {on | off} ]\n"
34 " [ flood {on | off} ]\n"
35 " [ proxy_arp {on | off} ]\n"
36 " [ proxy_arp_wifi {on | off} ]\n"
37 " [ mcast_router MULTICAST_ROUTER ]\n"
38 " [ mcast_fast_leave {on | off} ]\n"
39 " [ mcast_flood {on | off} ]\n"
40 " [ mcast_to_unicast {on | off} ]\n"
41 " [ group_fwd_mask MASK ]\n"
42 " [ neigh_suppress {on | off} ]\n"
43 " [ vlan_tunnel {on | off} ]\n"
44 " [ isolated {on | off} ]\n"
45 " [ backup_port DEVICE ] [ nobackup_port ]\n"
46 );
47}
48
49static void explain(void)
50{
51 print_explain(stderr);
52}
53
54static const char *port_states[] = {
55 [BR_STATE_DISABLED] = "disabled",
56 [BR_STATE_LISTENING] = "listening",
57 [BR_STATE_LEARNING] = "learning",
58 [BR_STATE_FORWARDING] = "forwarding",
59 [BR_STATE_BLOCKING] = "blocking",
60};
61
62static const char *fwd_mask_tbl[16] = {
63 [0] = "stp",
64 [2] = "lacp",
65 [14] = "lldp"
66};
67
68static void print_portstate(FILE *f, __u8 state)
69{
70 if (state <= BR_STATE_BLOCKING)
71 print_string(PRINT_ANY,
72 "state",
73 "state %s ",
74 port_states[state]);
75 else
76 print_int(PRINT_ANY, "state_index", "state (%d) ", state);
77}
78
79static void _print_onoff(FILE *f, char *json_flag, char *flag, __u8 val)
80{
81 if (is_json_context())
82 print_bool(PRINT_JSON, flag, NULL, val);
83 else
84 fprintf(f, "%s %s ", flag, val ? "on" : "off");
85}
86
87static void _print_timer(FILE *f, const char *attr, struct rtattr *timer)
88{
89 struct timeval tv;
90
91 __jiffies_to_tv(&tv, rta_getattr_u64(timer));
92 if (is_json_context()) {
93 json_writer_t *jw = get_json_writer();
94
95 jsonw_name(jw, attr);
96 jsonw_printf(jw, "%i.%.2i",
97 (int)tv.tv_sec, (int)tv.tv_usec / 10000);
98 } else {
99 fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
100 (int)tv.tv_usec / 10000);
101 }
102}
103
104static void _bitmask2str(__u16 bitmask, char *dst, size_t dst_size,
105 const char **tbl)
106{
107 int len, i;
108
109 for (i = 0, len = 0; bitmask; i++, bitmask >>= 1) {
110 if (bitmask & 0x1) {
111 if (tbl[i])
112 len += snprintf(dst + len, dst_size - len, "%s,",
113 tbl[i]);
114 else
115 len += snprintf(dst + len, dst_size - len, "0x%x,",
116 (1 << i));
117 }
118 }
119
120 if (!len)
121 snprintf(dst, dst_size, "0x0");
122 else
123 dst[len - 1] = 0;
124}
125
126static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
127 struct rtattr *tb[])
128{
129 if (!tb)
130 return;
131
132 if (tb[IFLA_BRPORT_STATE])
133 print_portstate(f, rta_getattr_u8(tb[IFLA_BRPORT_STATE]));
134
135 if (tb[IFLA_BRPORT_PRIORITY])
136 print_int(PRINT_ANY,
137 "priority",
138 "priority %d ",
139 rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY]));
140
141 if (tb[IFLA_BRPORT_COST])
142 print_int(PRINT_ANY,
143 "cost",
144 "cost %d ",
145 rta_getattr_u32(tb[IFLA_BRPORT_COST]));
146
147 if (tb[IFLA_BRPORT_MODE])
148 _print_onoff(f, "mode", "hairpin",
149 rta_getattr_u8(tb[IFLA_BRPORT_MODE]));
150
151 if (tb[IFLA_BRPORT_GUARD])
152 _print_onoff(f, "guard", "guard",
153 rta_getattr_u8(tb[IFLA_BRPORT_GUARD]));
154
155 if (tb[IFLA_BRPORT_PROTECT])
156 _print_onoff(f, "protect", "root_block",
157 rta_getattr_u8(tb[IFLA_BRPORT_PROTECT]));
158
159 if (tb[IFLA_BRPORT_FAST_LEAVE])
160 _print_onoff(f, "fast_leave", "fastleave",
161 rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
162
163 if (tb[IFLA_BRPORT_LEARNING])
164 _print_onoff(f, "learning", "learning",
165 rta_getattr_u8(tb[IFLA_BRPORT_LEARNING]));
166
167 if (tb[IFLA_BRPORT_UNICAST_FLOOD])
168 _print_onoff(f, "unicast_flood", "flood",
169 rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
170
171 if (tb[IFLA_BRPORT_ID])
172 print_0xhex(PRINT_ANY, "id", "port_id %#llx ",
173 rta_getattr_u16(tb[IFLA_BRPORT_ID]));
174
175 if (tb[IFLA_BRPORT_NO])
176 print_0xhex(PRINT_ANY, "no", "port_no %#llx ",
177 rta_getattr_u16(tb[IFLA_BRPORT_NO]));
178
179 if (tb[IFLA_BRPORT_DESIGNATED_PORT])
180 print_uint(PRINT_ANY,
181 "designated_port",
182 "designated_port %u ",
183 rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT]));
184
185 if (tb[IFLA_BRPORT_DESIGNATED_COST])
186 print_uint(PRINT_ANY,
187 "designated_cost",
188 "designated_cost %u ",
189 rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST]));
190
191 if (tb[IFLA_BRPORT_BRIDGE_ID]) {
192 char bridge_id[32];
193
194 br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_BRIDGE_ID]),
195 bridge_id, sizeof(bridge_id));
196 print_string(PRINT_ANY,
197 "bridge_id",
198 "designated_bridge %s ",
199 bridge_id);
200 }
201
202 if (tb[IFLA_BRPORT_ROOT_ID]) {
203 char root_id[32];
204
205 br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_ROOT_ID]),
206 root_id, sizeof(root_id));
207 print_string(PRINT_ANY,
208 "root_id",
209 "designated_root %s ", root_id);
210 }
211
212 if (tb[IFLA_BRPORT_HOLD_TIMER])
213 _print_timer(f, "hold_timer", tb[IFLA_BRPORT_HOLD_TIMER]);
214
215 if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER])
216 _print_timer(f, "message_age_timer",
217 tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]);
218
219 if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER])
220 _print_timer(f, "forward_delay_timer",
221 tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]);
222
223 if (tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK])
224 print_uint(PRINT_ANY,
225 "topology_change_ack",
226 "topology_change_ack %u ",
227 rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]));
228
229 if (tb[IFLA_BRPORT_CONFIG_PENDING])
230 print_uint(PRINT_ANY,
231 "config_pending",
232 "config_pending %u ",
233 rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING]));
234
235 if (tb[IFLA_BRPORT_PROXYARP])
236 _print_onoff(f, "proxyarp", "proxy_arp",
237 rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP]));
238
239 if (tb[IFLA_BRPORT_PROXYARP_WIFI])
240 _print_onoff(f, "proxyarp_wifi", "proxy_arp_wifi",
241 rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI]));
242
243 if (tb[IFLA_BRPORT_MULTICAST_ROUTER])
244 print_uint(PRINT_ANY,
245 "multicast_router",
246 "mcast_router %u ",
247 rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]));
248
249 if (tb[IFLA_BRPORT_FAST_LEAVE])
250
251
252 print_string(PRINT_FP,
253 NULL,
254 "mcast_fast_leave %s ",
255 rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]) ? "on" : "off");
256
257 if (tb[IFLA_BRPORT_MCAST_FLOOD])
258 _print_onoff(f, "mcast_flood", "mcast_flood",
259 rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD]));
260
261 if (tb[IFLA_BRPORT_MCAST_TO_UCAST])
262 _print_onoff(f, "mcast_to_unicast", "mcast_to_unicast",
263 rta_getattr_u8(tb[IFLA_BRPORT_MCAST_TO_UCAST]));
264
265 if (tb[IFLA_BRPORT_NEIGH_SUPPRESS])
266 _print_onoff(f, "neigh_suppress", "neigh_suppress",
267 rta_getattr_u8(tb[IFLA_BRPORT_NEIGH_SUPPRESS]));
268
269 if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) {
270 char convbuf[256];
271 __u16 fwd_mask;
272
273 fwd_mask = rta_getattr_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);
274 print_0xhex(PRINT_ANY, "group_fwd_mask",
275 "group_fwd_mask %#llx ", fwd_mask);
276 _bitmask2str(fwd_mask, convbuf, sizeof(convbuf), fwd_mask_tbl);
277 print_string(PRINT_ANY, "group_fwd_mask_str",
278 "group_fwd_mask_str %s ", convbuf);
279 }
280
281 if (tb[IFLA_BRPORT_VLAN_TUNNEL])
282 _print_onoff(f, "vlan_tunnel", "vlan_tunnel",
283 rta_getattr_u8(tb[IFLA_BRPORT_VLAN_TUNNEL]));
284
285 if (tb[IFLA_BRPORT_ISOLATED])
286 _print_onoff(f, "isolated", "isolated",
287 rta_getattr_u8(tb[IFLA_BRPORT_ISOLATED]));
288
289 if (tb[IFLA_BRPORT_BACKUP_PORT]) {
290 int backup_p = rta_getattr_u32(tb[IFLA_BRPORT_BACKUP_PORT]);
291
292 print_string(PRINT_ANY, "backup_port", "backup_port %s ",
293 ll_index_to_name(backup_p));
294 }
295}
296
297static void bridge_slave_parse_on_off(char *arg_name, char *arg_val,
298 struct nlmsghdr *n, int type)
299{
300 __u8 val;
301
302 if (strcmp(arg_val, "on") == 0)
303 val = 1;
304 else if (strcmp(arg_val, "off") == 0)
305 val = 0;
306 else
307 invarg("should be \"on\" or \"off\"", arg_name);
308
309 addattr8(n, 1024, type, val);
310}
311
312static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv,
313 struct nlmsghdr *n)
314{
315 __u8 state;
316 __u16 priority;
317 __u32 cost;
318
319 while (argc > 0) {
320 if (matches(*argv, "fdb_flush") == 0) {
321 addattr(n, 1024, IFLA_BRPORT_FLUSH);
322 } else if (matches(*argv, "state") == 0) {
323 NEXT_ARG();
324 if (get_u8(&state, *argv, 0))
325 invarg("state is invalid", *argv);
326 addattr8(n, 1024, IFLA_BRPORT_STATE, state);
327 } else if (matches(*argv, "priority") == 0) {
328 NEXT_ARG();
329 if (get_u16(&priority, *argv, 0))
330 invarg("priority is invalid", *argv);
331 addattr16(n, 1024, IFLA_BRPORT_PRIORITY, priority);
332 } else if (matches(*argv, "cost") == 0) {
333 NEXT_ARG();
334 if (get_u32(&cost, *argv, 0))
335 invarg("cost is invalid", *argv);
336 addattr32(n, 1024, IFLA_BRPORT_COST, cost);
337 } else if (matches(*argv, "hairpin") == 0) {
338 NEXT_ARG();
339 bridge_slave_parse_on_off("hairpin", *argv, n,
340 IFLA_BRPORT_MODE);
341 } else if (matches(*argv, "guard") == 0) {
342 NEXT_ARG();
343 bridge_slave_parse_on_off("guard", *argv, n,
344 IFLA_BRPORT_GUARD);
345 } else if (matches(*argv, "root_block") == 0) {
346 NEXT_ARG();
347 bridge_slave_parse_on_off("root_block", *argv, n,
348 IFLA_BRPORT_PROTECT);
349 } else if (matches(*argv, "fastleave") == 0) {
350 NEXT_ARG();
351 bridge_slave_parse_on_off("fastleave", *argv, n,
352 IFLA_BRPORT_FAST_LEAVE);
353 } else if (matches(*argv, "learning") == 0) {
354 NEXT_ARG();
355 bridge_slave_parse_on_off("learning", *argv, n,
356 IFLA_BRPORT_LEARNING);
357 } else if (matches(*argv, "flood") == 0) {
358 NEXT_ARG();
359 bridge_slave_parse_on_off("flood", *argv, n,
360 IFLA_BRPORT_UNICAST_FLOOD);
361 } else if (matches(*argv, "mcast_flood") == 0) {
362 NEXT_ARG();
363 bridge_slave_parse_on_off("mcast_flood", *argv, n,
364 IFLA_BRPORT_MCAST_FLOOD);
365 } else if (matches(*argv, "mcast_to_unicast") == 0) {
366 NEXT_ARG();
367 bridge_slave_parse_on_off("mcast_to_unicast", *argv, n,
368 IFLA_BRPORT_MCAST_TO_UCAST);
369 } else if (matches(*argv, "proxy_arp") == 0) {
370 NEXT_ARG();
371 bridge_slave_parse_on_off("proxy_arp", *argv, n,
372 IFLA_BRPORT_PROXYARP);
373 } else if (matches(*argv, "proxy_arp_wifi") == 0) {
374 NEXT_ARG();
375 bridge_slave_parse_on_off("proxy_arp_wifi", *argv, n,
376 IFLA_BRPORT_PROXYARP_WIFI);
377 } else if (matches(*argv, "mcast_router") == 0) {
378 __u8 mcast_router;
379
380 NEXT_ARG();
381 if (get_u8(&mcast_router, *argv, 0))
382 invarg("invalid mcast_router", *argv);
383 addattr8(n, 1024, IFLA_BRPORT_MULTICAST_ROUTER,
384 mcast_router);
385 } else if (matches(*argv, "mcast_fast_leave") == 0) {
386 NEXT_ARG();
387 bridge_slave_parse_on_off("mcast_fast_leave", *argv, n,
388 IFLA_BRPORT_FAST_LEAVE);
389 } else if (matches(*argv, "neigh_suppress") == 0) {
390 NEXT_ARG();
391 bridge_slave_parse_on_off("neigh_suppress", *argv, n,
392 IFLA_BRPORT_NEIGH_SUPPRESS);
393 } else if (matches(*argv, "group_fwd_mask") == 0) {
394 __u16 mask;
395
396 NEXT_ARG();
397 if (get_u16(&mask, *argv, 0))
398 invarg("invalid group_fwd_mask", *argv);
399 addattr16(n, 1024, IFLA_BRPORT_GROUP_FWD_MASK, mask);
400 } else if (matches(*argv, "vlan_tunnel") == 0) {
401 NEXT_ARG();
402 bridge_slave_parse_on_off("vlan_tunnel", *argv, n,
403 IFLA_BRPORT_VLAN_TUNNEL);
404 } else if (matches(*argv, "isolated") == 0) {
405 NEXT_ARG();
406 bridge_slave_parse_on_off("isolated", *argv, n,
407 IFLA_BRPORT_ISOLATED);
408 } else if (matches(*argv, "backup_port") == 0) {
409 int ifindex;
410
411 NEXT_ARG();
412 ifindex = ll_name_to_index(*argv);
413 if (!ifindex)
414 invarg("Device does not exist\n", *argv);
415 addattr32(n, 1024, IFLA_BRPORT_BACKUP_PORT, ifindex);
416 } else if (matches(*argv, "nobackup_port") == 0) {
417 addattr32(n, 1024, IFLA_BRPORT_BACKUP_PORT, 0);
418 } else if (matches(*argv, "help") == 0) {
419 explain();
420 return -1;
421 } else {
422 fprintf(stderr, "bridge_slave: unknown option \"%s\"?\n",
423 *argv);
424 explain();
425 return -1;
426 }
427 argc--, argv++;
428 }
429
430 return 0;
431}
432
433static void bridge_slave_print_help(struct link_util *lu, int argc, char **argv,
434 FILE *f)
435{
436 print_explain(f);
437}
438
439struct link_util bridge_slave_link_util = {
440 .id = "bridge_slave",
441 .maxattr = IFLA_BRPORT_MAX,
442 .print_opt = bridge_slave_print_opt,
443 .parse_opt = bridge_slave_parse_opt,
444 .print_help = bridge_slave_print_help,
445 .parse_ifla_xstats = bridge_parse_xstats,
446 .print_ifla_xstats = bridge_print_xstats,
447};
448