1
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <time.h>
7#include <sys/socket.h>
8#include <sys/time.h>
9#include <netinet/in.h>
10#include <linux/if.h>
11#include <linux/if_bridge.h>
12#include <string.h>
13#include <stdbool.h>
14
15#include "json_print.h"
16#include "libnetlink.h"
17#include "utils.h"
18#include "br_common.h"
19
20static unsigned int filter_index;
21
22static const char *stp_states[] = {
23 [BR_STATE_DISABLED] = "disabled",
24 [BR_STATE_LISTENING] = "listening",
25 [BR_STATE_LEARNING] = "learning",
26 [BR_STATE_FORWARDING] = "forwarding",
27 [BR_STATE_BLOCKING] = "blocking",
28};
29
30static const char *hw_mode[] = {
31 "VEB", "VEPA"
32};
33
34static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
35{
36 open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
37 if (flags & IFF_UP && !(flags & IFF_RUNNING))
38 print_string(PRINT_ANY, NULL,
39 flags ? "%s," : "%s", "NO-CARRIER");
40 flags &= ~IFF_RUNNING;
41
42#define _PF(f) if (flags&IFF_##f) { \
43 flags &= ~IFF_##f ; \
44 print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); }
45 _PF(LOOPBACK);
46 _PF(BROADCAST);
47 _PF(POINTOPOINT);
48 _PF(MULTICAST);
49 _PF(NOARP);
50 _PF(ALLMULTI);
51 _PF(PROMISC);
52 _PF(MASTER);
53 _PF(SLAVE);
54 _PF(DEBUG);
55 _PF(DYNAMIC);
56 _PF(AUTOMEDIA);
57 _PF(PORTSEL);
58 _PF(NOTRAILERS);
59 _PF(UP);
60 _PF(LOWER_UP);
61 _PF(DORMANT);
62 _PF(ECHO);
63#undef _PF
64 if (flags)
65 print_hex(PRINT_ANY, NULL, "%x", flags);
66 if (mdown)
67 print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
68 close_json_array(PRINT_ANY, "> ");
69}
70
71void print_stp_state(__u8 state)
72{
73 if (state <= BR_STATE_BLOCKING)
74 print_string(PRINT_ANY, "state",
75 "state %s ", stp_states[state]);
76 else
77 print_uint(PRINT_ANY, "state",
78 "state (%d) ", state);
79}
80
81int parse_stp_state(const char *arg)
82{
83 size_t nstates = ARRAY_SIZE(stp_states);
84 int state;
85
86 for (state = 0; state < nstates; state++)
87 if (strcmp(stp_states[state], arg) == 0)
88 break;
89
90 if (state == nstates)
91 state = -1;
92
93 return state;
94}
95
96static void print_hwmode(__u16 mode)
97{
98 if (mode >= ARRAY_SIZE(hw_mode))
99 print_0xhex(PRINT_ANY, "hwmode",
100 "hwmode %#llx ", mode);
101 else
102 print_string(PRINT_ANY, "hwmode",
103 "hwmode %s ", hw_mode[mode]);
104}
105
106static void print_protinfo(FILE *fp, struct rtattr *attr)
107{
108 if (attr->rta_type & NLA_F_NESTED) {
109 struct rtattr *prtb[IFLA_BRPORT_MAX + 1];
110
111 parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
112
113 if (prtb[IFLA_BRPORT_STATE])
114 print_stp_state(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
115
116 if (prtb[IFLA_BRPORT_PRIORITY])
117 print_uint(PRINT_ANY, "priority",
118 "priority %u ",
119 rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
120
121 if (prtb[IFLA_BRPORT_COST])
122 print_uint(PRINT_ANY, "cost",
123 "cost %u ",
124 rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
125
126 if (!show_details)
127 return;
128
129 if (!is_json_context())
130 fprintf(fp, "%s ", _SL_);
131
132 if (prtb[IFLA_BRPORT_MODE])
133 print_on_off(PRINT_ANY, "hairpin", "hairpin %s ",
134 rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
135 if (prtb[IFLA_BRPORT_GUARD])
136 print_on_off(PRINT_ANY, "guard", "guard %s ",
137 rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
138 if (prtb[IFLA_BRPORT_PROTECT])
139 print_on_off(PRINT_ANY, "root_block", "root_block %s ",
140 rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
141 if (prtb[IFLA_BRPORT_FAST_LEAVE])
142 print_on_off(PRINT_ANY, "fastleave", "fastleave %s ",
143 rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
144 if (prtb[IFLA_BRPORT_LEARNING])
145 print_on_off(PRINT_ANY, "learning", "learning %s ",
146 rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
147 if (prtb[IFLA_BRPORT_LEARNING_SYNC])
148 print_on_off(PRINT_ANY, "learning_sync", "learning_sync %s ",
149 rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
150 if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
151 print_on_off(PRINT_ANY, "flood", "flood %s ",
152 rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
153 if (prtb[IFLA_BRPORT_MCAST_FLOOD])
154 print_on_off(PRINT_ANY, "mcast_flood", "mcast_flood %s ",
155 rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
156 if (prtb[IFLA_BRPORT_MCAST_TO_UCAST])
157 print_on_off(PRINT_ANY, "mcast_to_unicast", "mcast_to_unicast %s ",
158 rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_TO_UCAST]));
159 if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
160 print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
161 rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
162 if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
163 print_on_off(PRINT_ANY, "vlan_tunnel", "vlan_tunnel %s ",
164 rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
165
166 if (prtb[IFLA_BRPORT_BACKUP_PORT]) {
167 int ifidx;
168
169 ifidx = rta_getattr_u32(prtb[IFLA_BRPORT_BACKUP_PORT]);
170 print_string(PRINT_ANY,
171 "backup_port", "backup_port %s ",
172 ll_index_to_name(ifidx));
173 }
174
175 if (prtb[IFLA_BRPORT_ISOLATED])
176 print_on_off(PRINT_ANY, "isolated", "isolated %s ",
177 rta_getattr_u8(prtb[IFLA_BRPORT_ISOLATED]));
178 } else
179 print_stp_state(rta_getattr_u8(attr));
180}
181
182
183
184
185
186
187static void print_af_spec(struct rtattr *attr, int ifindex)
188{
189 struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
190
191 parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, attr);
192
193 if (aftb[IFLA_BRIDGE_MODE])
194 print_hwmode(rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
195
196 if (!show_details)
197 return;
198
199 if (aftb[IFLA_BRIDGE_VLAN_INFO])
200 print_vlan_info(aftb[IFLA_BRIDGE_VLAN_INFO], ifindex);
201}
202
203int print_linkinfo(struct nlmsghdr *n, void *arg)
204{
205 FILE *fp = arg;
206 struct ifinfomsg *ifi = NLMSG_DATA(n);
207 struct rtattr *tb[IFLA_MAX+1];
208 unsigned int m_flag = 0;
209 int len = n->nlmsg_len;
210 const char *name;
211
212 len -= NLMSG_LENGTH(sizeof(*ifi));
213 if (len < 0) {
214 fprintf(stderr, "Message too short!\n");
215 return -1;
216 }
217
218 if (!(ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_UNSPEC))
219 return 0;
220
221 if (filter_index && filter_index != ifi->ifi_index)
222 return 0;
223
224 parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
225
226 name = get_ifname_rta(ifi->ifi_index, tb[IFLA_IFNAME]);
227 if (!name)
228 return -1;
229
230 open_json_object(NULL);
231 if (n->nlmsg_type == RTM_DELLINK)
232 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
233
234 print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
235 m_flag = print_name_and_link("%s: ", name, tb);
236 print_link_flags(fp, ifi->ifi_flags, m_flag);
237
238 if (tb[IFLA_MTU])
239 print_int(PRINT_ANY,
240 "mtu", "mtu %u ",
241 rta_getattr_u32(tb[IFLA_MTU]));
242
243 if (tb[IFLA_MASTER]) {
244 int master = rta_getattr_u32(tb[IFLA_MASTER]);
245
246 print_string(PRINT_ANY, "master", "master %s ",
247 ll_index_to_name(master));
248 }
249
250 if (tb[IFLA_PROTINFO])
251 print_protinfo(fp, tb[IFLA_PROTINFO]);
252
253 if (tb[IFLA_AF_SPEC])
254 print_af_spec(tb[IFLA_AF_SPEC], ifi->ifi_index);
255
256 print_string(PRINT_FP, NULL, "%s", "\n");
257 close_json_object();
258 fflush(fp);
259 return 0;
260}
261
262static void usage(void)
263{
264 fprintf(stderr,
265 "Usage: bridge link set dev DEV [ cost COST ] [ priority PRIO ] [ state STATE ]\n"
266 " [ guard {on | off} ]\n"
267 " [ hairpin {on | off} ]\n"
268 " [ fastleave {on | off} ]\n"
269 " [ root_block {on | off} ]\n"
270 " [ learning {on | off} ]\n"
271 " [ learning_sync {on | off} ]\n"
272 " [ flood {on | off} ]\n"
273 " [ mcast_flood {on | off} ]\n"
274 " [ mcast_to_unicast {on | off} ]\n"
275 " [ neigh_suppress {on | off} ]\n"
276 " [ vlan_tunnel {on | off} ]\n"
277 " [ isolated {on | off} ]\n"
278 " [ hwmode {vepa | veb} ]\n"
279 " [ backup_port DEVICE ] [ nobackup_port ]\n"
280 " [ self ] [ master ]\n"
281 " bridge link show [dev DEV]\n");
282 exit(-1);
283}
284
285static int brlink_modify(int argc, char **argv)
286{
287 struct {
288 struct nlmsghdr n;
289 struct ifinfomsg ifm;
290 char buf[512];
291 } req = {
292 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
293 .n.nlmsg_flags = NLM_F_REQUEST,
294 .n.nlmsg_type = RTM_SETLINK,
295 .ifm.ifi_family = PF_BRIDGE,
296 };
297 char *d = NULL;
298 int backup_port_idx = -1;
299 __s8 neigh_suppress = -1;
300 __s8 learning = -1;
301 __s8 learning_sync = -1;
302 __s8 flood = -1;
303 __s8 vlan_tunnel = -1;
304 __s8 mcast_flood = -1;
305 __s8 mcast_to_unicast = -1;
306 __s8 isolated = -1;
307 __s8 hairpin = -1;
308 __s8 bpdu_guard = -1;
309 __s8 fast_leave = -1;
310 __s8 root_block = -1;
311 __u32 cost = 0;
312 __s16 priority = -1;
313 __s8 state = -1;
314 __s16 mode = -1;
315 __u16 flags = 0;
316 struct rtattr *nest;
317 int ret;
318
319 while (argc > 0) {
320 if (strcmp(*argv, "dev") == 0) {
321 NEXT_ARG();
322 d = *argv;
323 } else if (strcmp(*argv, "guard") == 0) {
324 NEXT_ARG();
325 bpdu_guard = parse_on_off("guard", *argv, &ret);
326 if (ret)
327 return ret;
328 } else if (strcmp(*argv, "hairpin") == 0) {
329 NEXT_ARG();
330 hairpin = parse_on_off("hairpin", *argv, &ret);
331 if (ret)
332 return ret;
333 } else if (strcmp(*argv, "fastleave") == 0) {
334 NEXT_ARG();
335 fast_leave = parse_on_off("fastleave", *argv, &ret);
336 if (ret)
337 return ret;
338 } else if (strcmp(*argv, "root_block") == 0) {
339 NEXT_ARG();
340 root_block = parse_on_off("root_block", *argv, &ret);
341 if (ret)
342 return ret;
343 } else if (strcmp(*argv, "learning") == 0) {
344 NEXT_ARG();
345 learning = parse_on_off("learning", *argv, &ret);
346 if (ret)
347 return ret;
348 } else if (strcmp(*argv, "learning_sync") == 0) {
349 NEXT_ARG();
350 learning_sync = parse_on_off("learning_sync", *argv, &ret);
351 if (ret)
352 return ret;
353 } else if (strcmp(*argv, "flood") == 0) {
354 NEXT_ARG();
355 flood = parse_on_off("flood", *argv, &ret);
356 if (ret)
357 return ret;
358 } else if (strcmp(*argv, "mcast_flood") == 0) {
359 NEXT_ARG();
360 mcast_flood = parse_on_off("mcast_flood", *argv, &ret);
361 if (ret)
362 return ret;
363 } else if (strcmp(*argv, "mcast_to_unicast") == 0) {
364 NEXT_ARG();
365 mcast_to_unicast = parse_on_off("mcast_to_unicast", *argv, &ret);
366 if (ret)
367 return ret;
368 } else if (strcmp(*argv, "cost") == 0) {
369 NEXT_ARG();
370 cost = atoi(*argv);
371 } else if (strcmp(*argv, "priority") == 0) {
372 NEXT_ARG();
373 priority = atoi(*argv);
374 } else if (strcmp(*argv, "state") == 0) {
375 NEXT_ARG();
376 char *endptr;
377
378 state = strtol(*argv, &endptr, 10);
379 if (!(**argv != '\0' && *endptr == '\0')) {
380 state = parse_stp_state(*argv);
381 if (state == -1) {
382 fprintf(stderr,
383 "Error: invalid STP port state\n");
384 return -1;
385 }
386 }
387 } else if (strcmp(*argv, "hwmode") == 0) {
388 NEXT_ARG();
389 flags = BRIDGE_FLAGS_SELF;
390 if (strcmp(*argv, "vepa") == 0)
391 mode = BRIDGE_MODE_VEPA;
392 else if (strcmp(*argv, "veb") == 0)
393 mode = BRIDGE_MODE_VEB;
394 else {
395 fprintf(stderr,
396 "Mode argument must be \"vepa\" or \"veb\".\n");
397 return -1;
398 }
399 } else if (strcmp(*argv, "self") == 0) {
400 flags |= BRIDGE_FLAGS_SELF;
401 } else if (strcmp(*argv, "master") == 0) {
402 flags |= BRIDGE_FLAGS_MASTER;
403 } else if (strcmp(*argv, "neigh_suppress") == 0) {
404 NEXT_ARG();
405 neigh_suppress = parse_on_off("neigh_suppress", *argv, &ret);
406 if (ret)
407 return ret;
408 } else if (strcmp(*argv, "vlan_tunnel") == 0) {
409 NEXT_ARG();
410 vlan_tunnel = parse_on_off("vlan_tunnel", *argv, &ret);
411 if (ret)
412 return ret;
413 } else if (strcmp(*argv, "isolated") == 0) {
414 NEXT_ARG();
415 isolated = parse_on_off("isolated", *argv, &ret);
416 if (ret)
417 return ret;
418 } else if (strcmp(*argv, "backup_port") == 0) {
419 NEXT_ARG();
420 backup_port_idx = ll_name_to_index(*argv);
421 if (!backup_port_idx) {
422 fprintf(stderr, "Error: device %s does not exist\n",
423 *argv);
424 return -1;
425 }
426 } else if (strcmp(*argv, "nobackup_port") == 0) {
427 backup_port_idx = 0;
428 } else {
429 usage();
430 }
431 argc--; argv++;
432 }
433 if (d == NULL) {
434 fprintf(stderr, "Device is a required argument.\n");
435 return -1;
436 }
437
438
439 req.ifm.ifi_index = ll_name_to_index(d);
440 if (req.ifm.ifi_index == 0) {
441 fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
442 return -1;
443 }
444
445
446
447
448 nest = addattr_nest(&req.n, sizeof(req),
449 IFLA_PROTINFO | NLA_F_NESTED);
450
451 if (bpdu_guard >= 0)
452 addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard);
453 if (hairpin >= 0)
454 addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin);
455 if (fast_leave >= 0)
456 addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE,
457 fast_leave);
458 if (root_block >= 0)
459 addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block);
460 if (flood >= 0)
461 addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood);
462 if (mcast_flood >= 0)
463 addattr8(&req.n, sizeof(req), IFLA_BRPORT_MCAST_FLOOD,
464 mcast_flood);
465 if (mcast_to_unicast >= 0)
466 addattr8(&req.n, sizeof(req), IFLA_BRPORT_MCAST_TO_UCAST,
467 mcast_to_unicast);
468 if (learning >= 0)
469 addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning);
470 if (learning_sync >= 0)
471 addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC,
472 learning_sync);
473
474 if (cost > 0)
475 addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost);
476
477 if (priority >= 0)
478 addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority);
479
480 if (state >= 0)
481 addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state);
482
483 if (neigh_suppress != -1)
484 addattr8(&req.n, sizeof(req), IFLA_BRPORT_NEIGH_SUPPRESS,
485 neigh_suppress);
486 if (vlan_tunnel != -1)
487 addattr8(&req.n, sizeof(req), IFLA_BRPORT_VLAN_TUNNEL,
488 vlan_tunnel);
489 if (isolated != -1)
490 addattr8(&req.n, sizeof(req), IFLA_BRPORT_ISOLATED, isolated);
491
492 if (backup_port_idx != -1)
493 addattr32(&req.n, sizeof(req), IFLA_BRPORT_BACKUP_PORT,
494 backup_port_idx);
495
496 addattr_nest_end(&req.n, nest);
497
498
499
500
501
502
503 if (mode >= 0 || flags > 0) {
504 nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
505
506 if (flags > 0)
507 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
508
509 if (mode >= 0)
510 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode);
511
512 addattr_nest_end(&req.n, nest);
513 }
514
515 if (rtnl_talk(&rth, &req.n, NULL) < 0)
516 return -1;
517
518 return 0;
519}
520
521static int brlink_show(int argc, char **argv)
522{
523 char *filter_dev = NULL;
524
525 while (argc > 0) {
526 if (strcmp(*argv, "dev") == 0) {
527 NEXT_ARG();
528 if (filter_dev)
529 duparg("dev", *argv);
530 filter_dev = *argv;
531 }
532 argc--; argv++;
533 }
534
535 if (filter_dev) {
536 filter_index = ll_name_to_index(filter_dev);
537 if (!filter_index)
538 return nodev(filter_dev);
539 }
540
541 if (show_details) {
542 if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE,
543 (compress_vlans ?
544 RTEXT_FILTER_BRVLAN_COMPRESSED :
545 RTEXT_FILTER_BRVLAN)) < 0) {
546 perror("Cannon send dump request");
547 exit(1);
548 }
549 } else {
550 if (rtnl_linkdump_req(&rth, PF_BRIDGE) < 0) {
551 perror("Cannon send dump request");
552 exit(1);
553 }
554 }
555
556 new_json_obj(json);
557 if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
558 fprintf(stderr, "Dump terminated\n");
559 exit(1);
560 }
561
562 delete_json_obj();
563 fflush(stdout);
564 return 0;
565}
566
567int do_link(int argc, char **argv)
568{
569 ll_init_map(&rth);
570 if (argc > 0) {
571 if (matches(*argv, "set") == 0 ||
572 matches(*argv, "change") == 0)
573 return brlink_modify(argc-1, argv+1);
574 if (matches(*argv, "show") == 0 ||
575 matches(*argv, "lst") == 0 ||
576 matches(*argv, "list") == 0)
577 return brlink_show(argc-1, argv+1);
578 if (matches(*argv, "help") == 0)
579 usage();
580 } else
581 return brlink_show(0, NULL);
582
583 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge link help\".\n", *argv);
584 exit(-1);
585}
586