]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink_bridge_slave.c
Merge branch 'iproute2-master' into iproute2-next
[mirror_iproute2.git] / ip / iplink_bridge_slave.c
CommitLineData
8c39db39
JP
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
a560d850 22static void print_explain(FILE *f)
8c39db39 23{
a560d850 24 fprintf(f,
d1b41236
HL
25 "Usage: ... bridge_slave [ fdb_flush ]\n"
26 " [ state STATE ]\n"
27 " [ priority PRIO ]\n"
28 " [ cost COST ]\n"
8c39db39 29 " [ guard {on | off} ]\n"
56f5daac 30 " [ hairpin {on | off} ]\n"
8c39db39
JP
31 " [ fastleave {on | off} ]\n"
32 " [ root_block {on | off} ]\n"
33 " [ learning {on | off} ]\n"
34 " [ flood {on | off} ]\n"
f6e615de 35 " [ proxy_arp {on | off} ]\n"
38b31a78 36 " [ proxy_arp_wifi {on | off} ]\n"
10759a90 37 " [ mcast_router MULTICAST_ROUTER ]\n"
478a8e59 38 " [ mcast_fast_leave {on | off} ]\n"
9208b4e7 39 " [ mcast_flood {on | off} ]\n"
fdbdd356 40 " [ group_fwd_mask MASK ]\n"
a5e3f41b 41 " [ neigh_suppress {on | off} ]\n"
8cfde5c9 42 " [ vlan_tunnel {on | off} ]\n"
8c39db39
JP
43 );
44}
45
a560d850
ZS
46static void explain(void)
47{
48 print_explain(stderr);
49}
50
8c39db39
JP
51static 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
fdbdd356
NA
59static const char *fwd_mask_tbl[16] = {
60 [0] = "stp",
61 [2] = "lacp",
62 [14] = "lldp"
63};
64
8c39db39
JP
65static void print_portstate(FILE *f, __u8 state)
66{
67 if (state <= BR_STATE_BLOCKING)
165a7039
JF
68 print_string(PRINT_ANY,
69 "state",
70 "state %s ",
71 port_states[state]);
8c39db39 72 else
165a7039 73 print_int(PRINT_ANY, "state_index", "state (%d) ", state);
8c39db39
JP
74}
75
165a7039 76static void _print_onoff(FILE *f, char *json_flag, char *flag, __u8 val)
8c39db39 77{
165a7039
JF
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
165a7039
JF
84static 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 }
8c39db39
JP
99}
100
fdbdd356
NA
101static 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
8c39db39
JP
123static 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])
165a7039
JF
133 print_int(PRINT_ANY,
134 "priority",
135 "priority %d ",
136 rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY]));
8c39db39
JP
137
138 if (tb[IFLA_BRPORT_COST])
165a7039
JF
139 print_int(PRINT_ANY,
140 "cost",
141 "cost %d ",
142 rta_getattr_u32(tb[IFLA_BRPORT_COST]));
8c39db39
JP
143
144 if (tb[IFLA_BRPORT_MODE])
165a7039
JF
145 _print_onoff(f, "mode", "hairpin",
146 rta_getattr_u8(tb[IFLA_BRPORT_MODE]));
8c39db39
JP
147
148 if (tb[IFLA_BRPORT_GUARD])
165a7039
JF
149 _print_onoff(f, "guard", "guard",
150 rta_getattr_u8(tb[IFLA_BRPORT_GUARD]));
8c39db39
JP
151
152 if (tb[IFLA_BRPORT_PROTECT])
165a7039
JF
153 _print_onoff(f, "protect", "root_block",
154 rta_getattr_u8(tb[IFLA_BRPORT_PROTECT]));
8c39db39
JP
155
156 if (tb[IFLA_BRPORT_FAST_LEAVE])
165a7039
JF
157 _print_onoff(f, "fast_leave", "fastleave",
158 rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
8c39db39
JP
159
160 if (tb[IFLA_BRPORT_LEARNING])
165a7039
JF
161 _print_onoff(f, "learning", "learning",
162 rta_getattr_u8(tb[IFLA_BRPORT_LEARNING]));
8c39db39
JP
163
164 if (tb[IFLA_BRPORT_UNICAST_FLOOD])
165a7039
JF
165 _print_onoff(f, "unicast_flood", "flood",
166 rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
3069539f
NA
167
168 if (tb[IFLA_BRPORT_ID])
db2b8b6e
SP
169 print_0xhex(PRINT_ANY, "id", "port_id 0x%x ",
170 rta_getattr_u16(tb[IFLA_BRPORT_ID]));
3069539f
NA
171
172 if (tb[IFLA_BRPORT_NO])
db2b8b6e 173 print_0xhex(PRINT_ANY, "no", "port_no 0x%x ",
165a7039 174 rta_getattr_u16(tb[IFLA_BRPORT_NO]));
3069539f
NA
175
176 if (tb[IFLA_BRPORT_DESIGNATED_PORT])
165a7039
JF
177 print_uint(PRINT_ANY,
178 "designated_port",
179 "designated_port %u ",
180 rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT]));
3069539f
NA
181
182 if (tb[IFLA_BRPORT_DESIGNATED_COST])
165a7039
JF
183 print_uint(PRINT_ANY,
184 "designated_cost",
185 "designated_cost %u ",
186 rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST]));
3069539f
NA
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));
165a7039
JF
193 print_string(PRINT_ANY,
194 "bridge_id",
195 "designated_bridge %s ",
196 bridge_id);
3069539f
NA
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));
165a7039
JF
204 print_string(PRINT_ANY,
205 "root_id",
206 "designated_root %s ", root_id);
3069539f
NA
207 }
208
165a7039
JF
209 if (tb[IFLA_BRPORT_HOLD_TIMER])
210 _print_timer(f, "hold_timer", tb[IFLA_BRPORT_HOLD_TIMER]);
3069539f 211
165a7039
JF
212 if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER])
213 _print_timer(f, "message_age_timer",
214 tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]);
3069539f 215
165a7039
JF
216 if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER])
217 _print_timer(f, "forward_delay_timer",
218 tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]);
3069539f
NA
219
220 if (tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK])
165a7039
JF
221 print_uint(PRINT_ANY,
222 "topology_change_ack",
223 "topology_change_ack %u ",
224 rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]));
3069539f
NA
225
226 if (tb[IFLA_BRPORT_CONFIG_PENDING])
165a7039
JF
227 print_uint(PRINT_ANY,
228 "config_pending",
229 "config_pending %u ",
230 rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING]));
231
f6e615de 232 if (tb[IFLA_BRPORT_PROXYARP])
165a7039
JF
233 _print_onoff(f, "proxyarp", "proxy_arp",
234 rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP]));
38b31a78
NA
235
236 if (tb[IFLA_BRPORT_PROXYARP_WIFI])
165a7039
JF
237 _print_onoff(f, "proxyarp_wifi", "proxy_arp_wifi",
238 rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI]));
10759a90
NA
239
240 if (tb[IFLA_BRPORT_MULTICAST_ROUTER])
165a7039
JF
241 print_uint(PRINT_ANY,
242 "multicast_router",
243 "mcast_router %u ",
244 rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]));
478a8e59
NA
245
246 if (tb[IFLA_BRPORT_FAST_LEAVE])
165a7039
JF
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");
9208b4e7
NA
253
254 if (tb[IFLA_BRPORT_MCAST_FLOOD])
165a7039
JF
255 _print_onoff(f, "mcast_flood", "mcast_flood",
256 rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD]));
41973a47
RP
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]));
fdbdd356
NA
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]);
db2b8b6e
SP
267 print_0xhex(PRINT_ANY, "group_fwd_mask",
268 "group_fwd_mask 0x%x ", fwd_mask);
fdbdd356
NA
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 }
8cfde5c9
RP
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]));
8c39db39
JP
277}
278
279static 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
294static 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) {
d1b41236
HL
302 if (matches(*argv, "fdb_flush") == 0) {
303 addattr(n, 1024, IFLA_BRPORT_FLUSH);
304 } else if (matches(*argv, "state") == 0) {
8c39db39
JP
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);
9208b4e7
NA
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);
f6e615de
NA
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);
38b31a78
NA
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);
10759a90
NA
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);
478a8e59
NA
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);
41973a47
RP
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);
fdbdd356
NA
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);
8cfde5c9
RP
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);
8c39db39
JP
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
a560d850
ZS
397static void bridge_slave_print_help(struct link_util *lu, int argc, char **argv,
398 FILE *f)
399{
400 print_explain(f);
401}
402
8c39db39 403struct link_util bridge_slave_link_util = {
22a84711 404 .id = "bridge_slave",
8c39db39
JP
405 .maxattr = IFLA_BRPORT_MAX,
406 .print_opt = bridge_slave_print_opt,
407 .parse_opt = bridge_slave_parse_opt,
a560d850 408 .print_help = bridge_slave_print_help,
217264a0
NA
409 .parse_ifla_xstats = bridge_parse_xstats,
410 .print_ifla_xstats = bridge_print_xstats,
8c39db39 411};