2 * iplink_bridge.c Bridge device support
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Jiri Pirko <jiri@resnulli.us>
15 #include <linux/if_link.h>
16 #include <netinet/ether.h>
20 #include "ip_common.h"
22 static void print_explain(FILE *f
)
25 "Usage: ... bridge [ fdb_flush ]\n"
26 " [ forward_delay FORWARD_DELAY ]\n"
27 " [ hello_time HELLO_TIME ]\n"
28 " [ max_age MAX_AGE ]\n"
29 " [ ageing_time AGEING_TIME ]\n"
30 " [ stp_state STP_STATE ]\n"
31 " [ priority PRIORITY ]\n"
32 " [ group_fwd_mask MASK ]\n"
33 " [ group_address ADDRESS ]\n"
34 " [ vlan_filtering VLAN_FILTERING ]\n"
35 " [ vlan_protocol VLAN_PROTOCOL ]\n"
36 " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n"
37 " [ vlan_stats_enabled VLAN_STATS_ENABLED ]\n"
38 " [ mcast_snooping MULTICAST_SNOOPING ]\n"
39 " [ mcast_router MULTICAST_ROUTER ]\n"
40 " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n"
41 " [ mcast_querier MULTICAST_QUERIER ]\n"
42 " [ mcast_hash_elasticity HASH_ELASTICITY ]\n"
43 " [ mcast_hash_max HASH_MAX ]\n"
44 " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
45 " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
46 " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
47 " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
48 " [ mcast_querier_interval QUERIER_INTERVAL ]\n"
49 " [ mcast_query_interval QUERY_INTERVAL ]\n"
50 " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
51 " [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
52 " [ mcast_stats_enabled MCAST_STATS_ENABLED ]\n"
53 " [ mcast_igmp_version IGMP_VERSION ]\n"
54 " [ mcast_mld_version MLD_VERSION ]\n"
55 " [ nf_call_iptables NF_CALL_IPTABLES ]\n"
56 " [ nf_call_ip6tables NF_CALL_IP6TABLES ]\n"
57 " [ nf_call_arptables NF_CALL_ARPTABLES ]\n"
59 "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
63 static void explain(void)
65 print_explain(stderr
);
68 void br_dump_bridge_id(const struct ifla_bridge_id
*id
, char *buf
, size_t len
)
72 ether_ntoa_r((const struct ether_addr
*)id
->addr
, eaddr
);
73 snprintf(buf
, len
, "%.2x%.2x.%s", id
->prio
[0], id
->prio
[1], eaddr
);
76 static int bridge_parse_opt(struct link_util
*lu
, int argc
, char **argv
,
82 if (matches(*argv
, "forward_delay") == 0) {
84 if (get_u32(&val
, *argv
, 0))
85 invarg("invalid forward_delay", *argv
);
87 addattr32(n
, 1024, IFLA_BR_FORWARD_DELAY
, val
);
88 } else if (matches(*argv
, "hello_time") == 0) {
90 if (get_u32(&val
, *argv
, 0))
91 invarg("invalid hello_time", *argv
);
93 addattr32(n
, 1024, IFLA_BR_HELLO_TIME
, val
);
94 } else if (matches(*argv
, "max_age") == 0) {
96 if (get_u32(&val
, *argv
, 0))
97 invarg("invalid max_age", *argv
);
99 addattr32(n
, 1024, IFLA_BR_MAX_AGE
, val
);
100 } else if (matches(*argv
, "ageing_time") == 0) {
102 if (get_u32(&val
, *argv
, 0))
103 invarg("invalid ageing_time", *argv
);
105 addattr32(n
, 1024, IFLA_BR_AGEING_TIME
, val
);
106 } else if (matches(*argv
, "stp_state") == 0) {
108 if (get_u32(&val
, *argv
, 0))
109 invarg("invalid stp_state", *argv
);
111 addattr32(n
, 1024, IFLA_BR_STP_STATE
, val
);
112 } else if (matches(*argv
, "priority") == 0) {
116 if (get_u16(&prio
, *argv
, 0))
117 invarg("invalid priority", *argv
);
119 addattr16(n
, 1024, IFLA_BR_PRIORITY
, prio
);
120 } else if (matches(*argv
, "vlan_filtering") == 0) {
124 if (get_u8(&vlan_filter
, *argv
, 0))
125 invarg("invalid vlan_filtering", *argv
);
127 addattr8(n
, 1024, IFLA_BR_VLAN_FILTERING
, vlan_filter
);
128 } else if (matches(*argv
, "vlan_protocol") == 0) {
132 if (ll_proto_a2n(&vlan_proto
, *argv
))
133 invarg("invalid vlan_protocol", *argv
);
135 addattr16(n
, 1024, IFLA_BR_VLAN_PROTOCOL
, vlan_proto
);
136 } else if (matches(*argv
, "group_fwd_mask") == 0) {
140 if (get_u16(&fwd_mask
, *argv
, 0))
141 invarg("invalid group_fwd_mask", *argv
);
143 addattr16(n
, 1024, IFLA_BR_GROUP_FWD_MASK
, fwd_mask
);
144 } else if (matches(*argv
, "group_address") == 0) {
149 len
= ll_addr_a2n(llabuf
, sizeof(llabuf
), *argv
);
152 addattr_l(n
, 1024, IFLA_BR_GROUP_ADDR
, llabuf
, len
);
153 } else if (matches(*argv
, "fdb_flush") == 0) {
154 addattr(n
, 1024, IFLA_BR_FDB_FLUSH
);
155 } else if (matches(*argv
, "vlan_default_pvid") == 0) {
159 if (get_u16(&default_pvid
, *argv
, 0))
160 invarg("invalid vlan_default_pvid", *argv
);
162 addattr16(n
, 1024, IFLA_BR_VLAN_DEFAULT_PVID
,
164 } else if (matches(*argv
, "vlan_stats_enabled") == 0) {
165 __u8 vlan_stats_enabled
;
168 if (get_u8(&vlan_stats_enabled
, *argv
, 0))
169 invarg("invalid vlan_stats_enabled", *argv
);
170 addattr8(n
, 1024, IFLA_BR_VLAN_STATS_ENABLED
,
172 } else if (matches(*argv
, "mcast_router") == 0) {
176 if (get_u8(&mcast_router
, *argv
, 0))
177 invarg("invalid mcast_router", *argv
);
179 addattr8(n
, 1024, IFLA_BR_MCAST_ROUTER
, mcast_router
);
180 } else if (matches(*argv
, "mcast_snooping") == 0) {
184 if (get_u8(&mcast_snoop
, *argv
, 0))
185 invarg("invalid mcast_snooping", *argv
);
187 addattr8(n
, 1024, IFLA_BR_MCAST_SNOOPING
, mcast_snoop
);
188 } else if (matches(*argv
, "mcast_query_use_ifaddr") == 0) {
192 if (get_u8(&mcast_qui
, *argv
, 0))
193 invarg("invalid mcast_query_use_ifaddr",
196 addattr8(n
, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR
,
198 } else if (matches(*argv
, "mcast_querier") == 0) {
202 if (get_u8(&mcast_querier
, *argv
, 0))
203 invarg("invalid mcast_querier", *argv
);
205 addattr8(n
, 1024, IFLA_BR_MCAST_QUERIER
, mcast_querier
);
206 } else if (matches(*argv
, "mcast_hash_elasticity") == 0) {
210 if (get_u32(&mcast_hash_el
, *argv
, 0))
211 invarg("invalid mcast_hash_elasticity",
214 addattr32(n
, 1024, IFLA_BR_MCAST_HASH_ELASTICITY
,
216 } else if (matches(*argv
, "mcast_hash_max") == 0) {
217 __u32 mcast_hash_max
;
220 if (get_u32(&mcast_hash_max
, *argv
, 0))
221 invarg("invalid mcast_hash_max", *argv
);
223 addattr32(n
, 1024, IFLA_BR_MCAST_HASH_MAX
,
225 } else if (matches(*argv
, "mcast_last_member_count") == 0) {
229 if (get_u32(&mcast_lmc
, *argv
, 0))
230 invarg("invalid mcast_last_member_count",
233 addattr32(n
, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT
,
235 } else if (matches(*argv
, "mcast_startup_query_count") == 0) {
239 if (get_u32(&mcast_sqc
, *argv
, 0))
240 invarg("invalid mcast_startup_query_count",
243 addattr32(n
, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT
,
245 } else if (matches(*argv
, "mcast_last_member_interval") == 0) {
246 __u64 mcast_last_member_intvl
;
249 if (get_u64(&mcast_last_member_intvl
, *argv
, 0))
250 invarg("invalid mcast_last_member_interval",
253 addattr64(n
, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL
,
254 mcast_last_member_intvl
);
255 } else if (matches(*argv
, "mcast_membership_interval") == 0) {
256 __u64 mcast_membership_intvl
;
259 if (get_u64(&mcast_membership_intvl
, *argv
, 0))
260 invarg("invalid mcast_membership_interval",
263 addattr64(n
, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL
,
264 mcast_membership_intvl
);
265 } else if (matches(*argv
, "mcast_querier_interval") == 0) {
266 __u64 mcast_querier_intvl
;
269 if (get_u64(&mcast_querier_intvl
, *argv
, 0))
270 invarg("invalid mcast_querier_interval",
273 addattr64(n
, 1024, IFLA_BR_MCAST_QUERIER_INTVL
,
274 mcast_querier_intvl
);
275 } else if (matches(*argv
, "mcast_query_interval") == 0) {
276 __u64 mcast_query_intvl
;
279 if (get_u64(&mcast_query_intvl
, *argv
, 0))
280 invarg("invalid mcast_query_interval",
283 addattr64(n
, 1024, IFLA_BR_MCAST_QUERY_INTVL
,
285 } else if (!matches(*argv
, "mcast_query_response_interval")) {
286 __u64 mcast_query_resp_intvl
;
289 if (get_u64(&mcast_query_resp_intvl
, *argv
, 0))
290 invarg("invalid mcast_query_response_interval",
293 addattr64(n
, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
,
294 mcast_query_resp_intvl
);
295 } else if (!matches(*argv
, "mcast_startup_query_interval")) {
296 __u64 mcast_startup_query_intvl
;
299 if (get_u64(&mcast_startup_query_intvl
, *argv
, 0))
300 invarg("invalid mcast_startup_query_interval",
303 addattr64(n
, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL
,
304 mcast_startup_query_intvl
);
305 } else if (matches(*argv
, "mcast_stats_enabled") == 0) {
306 __u8 mcast_stats_enabled
;
309 if (get_u8(&mcast_stats_enabled
, *argv
, 0))
310 invarg("invalid mcast_stats_enabled", *argv
);
311 addattr8(n
, 1024, IFLA_BR_MCAST_STATS_ENABLED
,
312 mcast_stats_enabled
);
313 } else if (matches(*argv
, "mcast_igmp_version") == 0) {
317 if (get_u8(&igmp_version
, *argv
, 0))
318 invarg("invalid mcast_igmp_version", *argv
);
319 addattr8(n
, 1024, IFLA_BR_MCAST_IGMP_VERSION
,
321 } else if (matches(*argv
, "mcast_mld_version") == 0) {
325 if (get_u8(&mld_version
, *argv
, 0))
326 invarg("invalid mcast_mld_version", *argv
);
327 addattr8(n
, 1024, IFLA_BR_MCAST_MLD_VERSION
,
329 } else if (matches(*argv
, "nf_call_iptables") == 0) {
333 if (get_u8(&nf_call_ipt
, *argv
, 0))
334 invarg("invalid nf_call_iptables", *argv
);
336 addattr8(n
, 1024, IFLA_BR_NF_CALL_IPTABLES
,
338 } else if (matches(*argv
, "nf_call_ip6tables") == 0) {
342 if (get_u8(&nf_call_ip6t
, *argv
, 0))
343 invarg("invalid nf_call_ip6tables", *argv
);
345 addattr8(n
, 1024, IFLA_BR_NF_CALL_IP6TABLES
,
347 } else if (matches(*argv
, "nf_call_arptables") == 0) {
351 if (get_u8(&nf_call_arpt
, *argv
, 0))
352 invarg("invalid nf_call_arptables", *argv
);
354 addattr8(n
, 1024, IFLA_BR_NF_CALL_ARPTABLES
,
356 } else if (matches(*argv
, "help") == 0) {
360 fprintf(stderr
, "bridge: unknown command \"%s\"?\n", *argv
);
370 static void bridge_print_opt(struct link_util
*lu
, FILE *f
, struct rtattr
*tb
[])
375 if (tb
[IFLA_BR_FORWARD_DELAY
])
376 fprintf(f
, "forward_delay %u ",
377 rta_getattr_u32(tb
[IFLA_BR_FORWARD_DELAY
]));
379 if (tb
[IFLA_BR_HELLO_TIME
])
380 fprintf(f
, "hello_time %u ",
381 rta_getattr_u32(tb
[IFLA_BR_HELLO_TIME
]));
383 if (tb
[IFLA_BR_MAX_AGE
])
384 fprintf(f
, "max_age %u ",
385 rta_getattr_u32(tb
[IFLA_BR_MAX_AGE
]));
387 if (tb
[IFLA_BR_AGEING_TIME
])
388 fprintf(f
, "ageing_time %u ",
389 rta_getattr_u32(tb
[IFLA_BR_AGEING_TIME
]));
391 if (tb
[IFLA_BR_STP_STATE
])
392 fprintf(f
, "stp_state %u ",
393 rta_getattr_u32(tb
[IFLA_BR_STP_STATE
]));
395 if (tb
[IFLA_BR_PRIORITY
])
396 fprintf(f
, "priority %u ",
397 rta_getattr_u16(tb
[IFLA_BR_PRIORITY
]));
399 if (tb
[IFLA_BR_VLAN_FILTERING
])
400 fprintf(f
, "vlan_filtering %u ",
401 rta_getattr_u8(tb
[IFLA_BR_VLAN_FILTERING
]));
403 if (tb
[IFLA_BR_VLAN_PROTOCOL
]) {
406 fprintf(f
, "vlan_protocol %s ",
407 ll_proto_n2a(rta_getattr_u16(tb
[IFLA_BR_VLAN_PROTOCOL
]),
411 if (tb
[IFLA_BR_BRIDGE_ID
]) {
414 br_dump_bridge_id(RTA_DATA(tb
[IFLA_BR_BRIDGE_ID
]), bridge_id
,
416 fprintf(f
, "bridge_id %s ", bridge_id
);
419 if (tb
[IFLA_BR_ROOT_ID
]) {
422 br_dump_bridge_id(RTA_DATA(tb
[IFLA_BR_BRIDGE_ID
]), root_id
,
424 fprintf(f
, "designated_root %s ", root_id
);
427 if (tb
[IFLA_BR_ROOT_PORT
])
428 fprintf(f
, "root_port %u ",
429 rta_getattr_u16(tb
[IFLA_BR_ROOT_PORT
]));
431 if (tb
[IFLA_BR_ROOT_PATH_COST
])
432 fprintf(f
, "root_path_cost %u ",
433 rta_getattr_u32(tb
[IFLA_BR_ROOT_PATH_COST
]));
435 if (tb
[IFLA_BR_TOPOLOGY_CHANGE
])
436 fprintf(f
, "topology_change %u ",
437 rta_getattr_u8(tb
[IFLA_BR_TOPOLOGY_CHANGE
]));
439 if (tb
[IFLA_BR_TOPOLOGY_CHANGE_DETECTED
])
440 fprintf(f
, "topology_change_detected %u ",
441 rta_getattr_u8(tb
[IFLA_BR_TOPOLOGY_CHANGE_DETECTED
]));
443 if (tb
[IFLA_BR_HELLO_TIMER
]) {
446 __jiffies_to_tv(&tv
, rta_getattr_u64(tb
[IFLA_BR_HELLO_TIMER
]));
447 fprintf(f
, "hello_timer %4i.%.2i ", (int)tv
.tv_sec
,
448 (int)tv
.tv_usec
/10000);
451 if (tb
[IFLA_BR_TCN_TIMER
]) {
454 __jiffies_to_tv(&tv
, rta_getattr_u64(tb
[IFLA_BR_TCN_TIMER
]));
455 fprintf(f
, "tcn_timer %4i.%.2i ", (int)tv
.tv_sec
,
456 (int)tv
.tv_usec
/10000);
459 if (tb
[IFLA_BR_TOPOLOGY_CHANGE_TIMER
]) {
460 unsigned long jiffies
;
463 jiffies
= rta_getattr_u64(tb
[IFLA_BR_TOPOLOGY_CHANGE_TIMER
]);
464 __jiffies_to_tv(&tv
, jiffies
);
465 fprintf(f
, "topology_change_timer %4i.%.2i ", (int)tv
.tv_sec
,
466 (int)tv
.tv_usec
/10000);
469 if (tb
[IFLA_BR_GC_TIMER
]) {
472 __jiffies_to_tv(&tv
, rta_getattr_u64(tb
[IFLA_BR_GC_TIMER
]));
473 fprintf(f
, "gc_timer %4i.%.2i ", (int)tv
.tv_sec
,
474 (int)tv
.tv_usec
/10000);
477 if (tb
[IFLA_BR_VLAN_DEFAULT_PVID
])
478 fprintf(f
, "vlan_default_pvid %u ",
479 rta_getattr_u16(tb
[IFLA_BR_VLAN_DEFAULT_PVID
]));
481 if (tb
[IFLA_BR_VLAN_STATS_ENABLED
])
482 fprintf(f
, "vlan_stats_enabled %u ",
483 rta_getattr_u8(tb
[IFLA_BR_VLAN_STATS_ENABLED
]));
485 if (tb
[IFLA_BR_GROUP_FWD_MASK
])
486 fprintf(f
, "group_fwd_mask %#x ",
487 rta_getattr_u16(tb
[IFLA_BR_GROUP_FWD_MASK
]));
489 if (tb
[IFLA_BR_GROUP_ADDR
]) {
492 fprintf(f
, "group_address %s ",
493 ll_addr_n2a(RTA_DATA(tb
[IFLA_BR_GROUP_ADDR
]),
494 RTA_PAYLOAD(tb
[IFLA_BR_GROUP_ADDR
]),
495 1 /*ARPHDR_ETHER*/, mac
, sizeof(mac
)));
498 if (tb
[IFLA_BR_MCAST_SNOOPING
])
499 fprintf(f
, "mcast_snooping %u ",
500 rta_getattr_u8(tb
[IFLA_BR_MCAST_SNOOPING
]));
502 if (tb
[IFLA_BR_MCAST_ROUTER
])
503 fprintf(f
, "mcast_router %u ",
504 rta_getattr_u8(tb
[IFLA_BR_MCAST_ROUTER
]));
506 if (tb
[IFLA_BR_MCAST_QUERY_USE_IFADDR
])
507 fprintf(f
, "mcast_query_use_ifaddr %u ",
508 rta_getattr_u8(tb
[IFLA_BR_MCAST_QUERY_USE_IFADDR
]));
510 if (tb
[IFLA_BR_MCAST_QUERIER
])
511 fprintf(f
, "mcast_querier %u ",
512 rta_getattr_u8(tb
[IFLA_BR_MCAST_QUERIER
]));
514 if (tb
[IFLA_BR_MCAST_HASH_ELASTICITY
])
515 fprintf(f
, "mcast_hash_elasticity %u ",
516 rta_getattr_u32(tb
[IFLA_BR_MCAST_HASH_ELASTICITY
]));
518 if (tb
[IFLA_BR_MCAST_HASH_MAX
])
519 fprintf(f
, "mcast_hash_max %u ",
520 rta_getattr_u32(tb
[IFLA_BR_MCAST_HASH_MAX
]));
522 if (tb
[IFLA_BR_MCAST_LAST_MEMBER_CNT
])
523 fprintf(f
, "mcast_last_member_count %u ",
524 rta_getattr_u32(tb
[IFLA_BR_MCAST_LAST_MEMBER_CNT
]));
526 if (tb
[IFLA_BR_MCAST_STARTUP_QUERY_CNT
])
527 fprintf(f
, "mcast_startup_query_count %u ",
528 rta_getattr_u32(tb
[IFLA_BR_MCAST_STARTUP_QUERY_CNT
]));
530 if (tb
[IFLA_BR_MCAST_LAST_MEMBER_INTVL
])
531 fprintf(f
, "mcast_last_member_interval %llu ",
532 rta_getattr_u64(tb
[IFLA_BR_MCAST_LAST_MEMBER_INTVL
]));
534 if (tb
[IFLA_BR_MCAST_MEMBERSHIP_INTVL
])
535 fprintf(f
, "mcast_membership_interval %llu ",
536 rta_getattr_u64(tb
[IFLA_BR_MCAST_MEMBERSHIP_INTVL
]));
538 if (tb
[IFLA_BR_MCAST_QUERIER_INTVL
])
539 fprintf(f
, "mcast_querier_interval %llu ",
540 rta_getattr_u64(tb
[IFLA_BR_MCAST_QUERIER_INTVL
]));
542 if (tb
[IFLA_BR_MCAST_QUERY_INTVL
])
543 fprintf(f
, "mcast_query_interval %llu ",
544 rta_getattr_u64(tb
[IFLA_BR_MCAST_QUERY_INTVL
]));
546 if (tb
[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
])
547 fprintf(f
, "mcast_query_response_interval %llu ",
548 rta_getattr_u64(tb
[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
]));
550 if (tb
[IFLA_BR_MCAST_STARTUP_QUERY_INTVL
])
551 fprintf(f
, "mcast_startup_query_interval %llu ",
552 rta_getattr_u64(tb
[IFLA_BR_MCAST_STARTUP_QUERY_INTVL
]));
554 if (tb
[IFLA_BR_MCAST_STATS_ENABLED
])
555 fprintf(f
, "mcast_stats_enabled %u ",
556 rta_getattr_u8(tb
[IFLA_BR_MCAST_STATS_ENABLED
]));
558 if (tb
[IFLA_BR_MCAST_IGMP_VERSION
])
559 fprintf(f
, "mcast_igmp_version %u ",
560 rta_getattr_u8(tb
[IFLA_BR_MCAST_IGMP_VERSION
]));
562 if (tb
[IFLA_BR_MCAST_MLD_VERSION
])
563 fprintf(f
, "mcast_mld_version %u ",
564 rta_getattr_u8(tb
[IFLA_BR_MCAST_MLD_VERSION
]));
566 if (tb
[IFLA_BR_NF_CALL_IPTABLES
])
567 fprintf(f
, "nf_call_iptables %u ",
568 rta_getattr_u8(tb
[IFLA_BR_NF_CALL_IPTABLES
]));
570 if (tb
[IFLA_BR_NF_CALL_IP6TABLES
])
571 fprintf(f
, "nf_call_ip6tables %u ",
572 rta_getattr_u8(tb
[IFLA_BR_NF_CALL_IP6TABLES
]));
574 if (tb
[IFLA_BR_NF_CALL_ARPTABLES
])
575 fprintf(f
, "nf_call_arptables %u ",
576 rta_getattr_u8(tb
[IFLA_BR_NF_CALL_ARPTABLES
]));
579 static void bridge_print_help(struct link_util
*lu
, int argc
, char **argv
,
585 struct link_util bridge_link_util
= {
587 .maxattr
= IFLA_BR_MAX
,
588 .parse_opt
= bridge_parse_opt
,
589 .print_opt
= bridge_print_opt
,
590 .print_help
= bridge_print_help
,