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