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