]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink_bridge.c
iplink: bridge: add support for IFLA_BR_MCAST_LAST_MEMBER_CNT
[mirror_iproute2.git] / ip / iplink_bridge.c
CommitLineData
28d84b42
JP
1/*
2 * iplink_bridge.c Bridge device support
3 *
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.
8 *
9 * Authors: Jiri Pirko <jiri@resnulli.us>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <linux/if_link.h>
70dfb0b8 16#include <netinet/ether.h>
28d84b42 17
1eea5c46 18#include "rt_names.h"
28d84b42
JP
19#include "utils.h"
20#include "ip_common.h"
21
43367ef7 22static void print_explain(FILE *f)
28d84b42 23{
43367ef7 24 fprintf(f,
28d84b42
JP
25 "Usage: ... bridge [ forward_delay FORWARD_DELAY ]\n"
26 " [ hello_time HELLO_TIME ]\n"
27 " [ max_age MAX_AGE ]\n"
6c99fb60 28 " [ ageing_time AGEING_TIME ]\n"
dab04962 29 " [ stp_state STP_STATE ]\n"
b0197a04 30 " [ priority PRIORITY ]\n"
8caaf33b 31 " [ group_fwd_mask MASK ]\n"
0a61aa39 32 " [ group_address ADDRESS ]\n"
e4d456f0 33 " [ vlan_filtering VLAN_FILTERING ]\n"
1eea5c46 34 " [ vlan_protocol VLAN_PROTOCOL ]\n"
719832af 35 " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n"
7ddd2d94 36 " [ mcast_snooping MULTICAST_SNOOPING ]\n"
963d137c 37 " [ mcast_router MULTICAST_ROUTER ]\n"
449843d1 38 " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n"
0778b741 39 " [ mcast_querier MULTICAST_QUERIER ]\n"
92c0ef70 40 " [ mcast_hash_elasticity HASH_ELASTICITY ]\n"
8b9eb7cd 41 " [ mcast_hash_max HASH_MAX ]\n"
fb44cadb 42 " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
1eea5c46
TM
43 "\n"
44 "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
28d84b42
JP
45 );
46}
47
43367ef7
ZS
48static void explain(void)
49{
50 print_explain(stderr);
51}
52
70dfb0b8
NA
53static void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf,
54 size_t len)
55{
56 char eaddr[32];
57
58 ether_ntoa_r((const struct ether_addr *)id->addr, eaddr);
59 snprintf(buf, len, "%.2x%.2x.%s", id->prio[0], id->prio[1], eaddr);
60}
61
28d84b42
JP
62static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
63 struct nlmsghdr *n)
64{
65 __u32 val;
66
67 while (argc > 0) {
68 if (matches(*argv, "forward_delay") == 0) {
69 NEXT_ARG();
6a9ce30e 70 if (get_u32(&val, *argv, 0))
28d84b42 71 invarg("invalid forward_delay", *argv);
6a9ce30e 72
28d84b42
JP
73 addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
74 } else if (matches(*argv, "hello_time") == 0) {
75 NEXT_ARG();
6a9ce30e 76 if (get_u32(&val, *argv, 0))
28d84b42 77 invarg("invalid hello_time", *argv);
6a9ce30e 78
28d84b42
JP
79 addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
80 } else if (matches(*argv, "max_age") == 0) {
81 NEXT_ARG();
6a9ce30e 82 if (get_u32(&val, *argv, 0))
28d84b42 83 invarg("invalid max_age", *argv);
6a9ce30e 84
28d84b42 85 addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
6c99fb60
NA
86 } else if (matches(*argv, "ageing_time") == 0) {
87 NEXT_ARG();
6a9ce30e 88 if (get_u32(&val, *argv, 0))
6c99fb60 89 invarg("invalid ageing_time", *argv);
6a9ce30e 90
6c99fb60 91 addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
dab04962
NA
92 } else if (matches(*argv, "stp_state") == 0) {
93 NEXT_ARG();
6a9ce30e 94 if (get_u32(&val, *argv, 0))
dab04962 95 invarg("invalid stp_state", *argv);
6a9ce30e 96
dab04962 97 addattr32(n, 1024, IFLA_BR_STP_STATE, val);
b0197a04
NA
98 } else if (matches(*argv, "priority") == 0) {
99 __u16 prio;
100
101 NEXT_ARG();
6a9ce30e 102 if (get_u16(&prio, *argv, 0))
b0197a04 103 invarg("invalid priority", *argv);
6a9ce30e 104
b0197a04 105 addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
e4d456f0
NA
106 } else if (matches(*argv, "vlan_filtering") == 0) {
107 __u8 vlan_filter;
108
109 NEXT_ARG();
110 if (get_u8(&vlan_filter, *argv, 0)) {
111 invarg("invalid vlan_filtering", *argv);
112 return -1;
113 }
114 addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
1eea5c46
TM
115 } else if (matches(*argv, "vlan_protocol") == 0) {
116 __u16 vlan_proto;
117
118 NEXT_ARG();
119 if (ll_proto_a2n(&vlan_proto, *argv)) {
120 invarg("invalid vlan_protocol", *argv);
121 return -1;
122 }
123 addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
8caaf33b
NA
124 } else if (matches(*argv, "group_fwd_mask") == 0) {
125 __u16 fwd_mask;
126
127 NEXT_ARG();
128 if (get_u16(&fwd_mask, *argv, 0))
129 invarg("invalid group_fwd_mask", *argv);
130
131 addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask);
0a61aa39
NA
132 } else if (matches(*argv, "group_address") == 0) {
133 char llabuf[32];
134 int len;
135
136 NEXT_ARG();
137 len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv);
138 if (len < 0)
139 return -1;
140 addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len);
719832af
NA
141 } else if (matches(*argv, "vlan_default_pvid") == 0) {
142 __u16 default_pvid;
143
144 NEXT_ARG();
145 if (get_u16(&default_pvid, *argv, 0))
146 invarg("invalid vlan_default_pvid", *argv);
147
148 addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID,
149 default_pvid);
963d137c
NA
150 } else if (matches(*argv, "mcast_router") == 0) {
151 __u8 mcast_router;
152
153 NEXT_ARG();
154 if (get_u8(&mcast_router, *argv, 0))
155 invarg("invalid mcast_router", *argv);
156
157 addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router);
7ddd2d94
NA
158 } else if (matches(*argv, "mcast_snooping") == 0) {
159 __u8 mcast_snoop;
160
161 NEXT_ARG();
162 if (get_u8(&mcast_snoop, *argv, 0))
163 invarg("invalid mcast_snooping", *argv);
164
165 addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop);
449843d1
NA
166 } else if (matches(*argv, "mcast_query_use_ifaddr") == 0) {
167 __u8 mcast_qui;
168
169 NEXT_ARG();
170 if (get_u8(&mcast_qui, *argv, 0))
171 invarg("invalid mcast_query_use_ifaddr",
172 *argv);
173
174 addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR,
175 mcast_qui);
0778b741
NA
176 } else if (matches(*argv, "mcast_querier") == 0) {
177 __u8 mcast_querier;
178
179 NEXT_ARG();
180 if (get_u8(&mcast_querier, *argv, 0))
181 invarg("invalid mcast_querier", *argv);
182
183 addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier);
92c0ef70
NA
184 } else if (matches(*argv, "mcast_hash_elasticity") == 0) {
185 __u32 mcast_hash_el;
186
187 NEXT_ARG();
188 if (get_u32(&mcast_hash_el, *argv, 0))
189 invarg("invalid mcast_hash_elasticity",
190 *argv);
191
192 addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY,
193 mcast_hash_el);
8b9eb7cd
NA
194 } else if (matches(*argv, "mcast_hash_max") == 0) {
195 __u32 mcast_hash_max;
196
197 NEXT_ARG();
198 if (get_u32(&mcast_hash_max, *argv, 0))
199 invarg("invalid mcast_hash_max", *argv);
200
201 addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX,
202 mcast_hash_max);
fb44cadb
NA
203 } else if (matches(*argv, "mcast_last_member_count") == 0) {
204 __u32 mcast_lmc;
205
206 NEXT_ARG();
207 if (get_u32(&mcast_lmc, *argv, 0))
208 invarg("invalid mcast_last_member_count",
209 *argv);
210
211 addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT,
212 mcast_lmc);
28d84b42
JP
213 } else if (matches(*argv, "help") == 0) {
214 explain();
215 return -1;
216 } else {
217 fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
218 explain();
219 return -1;
220 }
221 argc--, argv++;
222 }
223
224 return 0;
225}
226
227static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
228{
229 if (!tb)
230 return;
231
232 if (tb[IFLA_BR_FORWARD_DELAY])
233 fprintf(f, "forward_delay %u ",
234 rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
235
236 if (tb[IFLA_BR_HELLO_TIME])
237 fprintf(f, "hello_time %u ",
238 rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
239
240 if (tb[IFLA_BR_MAX_AGE])
241 fprintf(f, "max_age %u ",
242 rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
fdba0515
NA
243
244 if (tb[IFLA_BR_AGEING_TIME])
245 fprintf(f, "ageing_time %u ",
246 rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
247
248 if (tb[IFLA_BR_STP_STATE])
249 fprintf(f, "stp_state %u ",
250 rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
251
252 if (tb[IFLA_BR_PRIORITY])
253 fprintf(f, "priority %u ",
254 rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
e4d456f0
NA
255
256 if (tb[IFLA_BR_VLAN_FILTERING])
257 fprintf(f, "vlan_filtering %u ",
258 rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
1eea5c46
TM
259
260 if (tb[IFLA_BR_VLAN_PROTOCOL]) {
261 SPRINT_BUF(b1);
262
263 fprintf(f, "vlan_protocol %s ",
264 ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
265 b1, sizeof(b1)));
266 }
70dfb0b8
NA
267
268 if (tb[IFLA_BR_BRIDGE_ID]) {
269 char bridge_id[32];
270
271 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
272 sizeof(bridge_id));
273 fprintf(f, "bridge_id %s ", bridge_id);
274 }
275
276 if (tb[IFLA_BR_ROOT_ID]) {
277 char root_id[32];
278
279 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
280 sizeof(root_id));
281 fprintf(f, "designated_root %s ", root_id);
282 }
4e3bbc66
NA
283
284 if (tb[IFLA_BR_ROOT_PORT])
285 fprintf(f, "root_port %u ",
286 rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
287
288 if (tb[IFLA_BR_ROOT_PATH_COST])
289 fprintf(f, "root_path_cost %u ",
290 rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
291
292 if (tb[IFLA_BR_TOPOLOGY_CHANGE])
293 fprintf(f, "topology_change %u ",
294 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
295
296 if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
297 fprintf(f, "topology_change_detected %u ",
298 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
8c0f7a16
NA
299
300 if (tb[IFLA_BR_HELLO_TIMER]) {
301 struct timeval tv;
302
303 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER]));
304 fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec,
305 (int)tv.tv_usec/10000);
306 }
307
308 if (tb[IFLA_BR_TCN_TIMER]) {
309 struct timeval tv;
310
311 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER]));
312 fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec,
313 (int)tv.tv_usec/10000);
314 }
315
316 if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) {
317 unsigned long jiffies;
318 struct timeval tv;
319
320 jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
321 __jiffies_to_tv(&tv, jiffies);
322 fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec,
323 (int)tv.tv_usec/10000);
324 }
325
326 if (tb[IFLA_BR_GC_TIMER]) {
327 struct timeval tv;
328
329 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER]));
330 fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec,
331 (int)tv.tv_usec/10000);
332 }
8caaf33b 333
719832af
NA
334 if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
335 fprintf(f, "vlan_default_pvid %u ",
336 rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
337
8caaf33b
NA
338 if (tb[IFLA_BR_GROUP_FWD_MASK])
339 fprintf(f, "group_fwd_mask %#x ",
340 rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
0a61aa39
NA
341
342 if (tb[IFLA_BR_GROUP_ADDR]) {
343 SPRINT_BUF(mac);
344
345 fprintf(f, "group_address %s ",
346 ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
347 RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
348 1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
349 }
963d137c 350
7ddd2d94
NA
351 if (tb[IFLA_BR_MCAST_SNOOPING])
352 fprintf(f, "mcast_snooping %u ",
353 rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
354
963d137c
NA
355 if (tb[IFLA_BR_MCAST_ROUTER])
356 fprintf(f, "mcast_router %u ",
357 rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
449843d1
NA
358
359 if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])
360 fprintf(f, "mcast_query_use_ifaddr %u ",
361 rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
0778b741
NA
362
363 if (tb[IFLA_BR_MCAST_QUERIER])
364 fprintf(f, "mcast_querier %u ",
365 rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
92c0ef70
NA
366
367 if (tb[IFLA_BR_MCAST_HASH_ELASTICITY])
368 fprintf(f, "mcast_hash_elasticity %u ",
369 rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
8b9eb7cd
NA
370
371 if (tb[IFLA_BR_MCAST_HASH_MAX])
372 fprintf(f, "mcast_hash_max %u ",
373 rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
fb44cadb
NA
374
375 if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])
376 fprintf(f, "mcast_last_member_count %u ",
377 rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
28d84b42
JP
378}
379
43367ef7
ZS
380static void bridge_print_help(struct link_util *lu, int argc, char **argv,
381 FILE *f)
382{
383 print_explain(f);
384}
385
28d84b42
JP
386struct link_util bridge_link_util = {
387 .id = "bridge",
388 .maxattr = IFLA_BR_MAX,
389 .parse_opt = bridge_parse_opt,
390 .print_opt = bridge_print_opt,
43367ef7 391 .print_help = bridge_print_help,
28d84b42 392};