blob: 7a945ed2ae6329ccc185f982312c041ae6fe5338 [file] [log] [blame]
Jiri Pirko28d84b42014-09-28 16:33:29 -07001/*
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>
Nikolay Aleksandrov70dfb0b2016-02-09 00:14:19 +010016#include <netinet/ether.h>
Jiri Pirko28d84b42014-09-28 16:33:29 -070017
Toshiaki Makita1eea5c42015-08-31 18:48:46 +090018#include "rt_names.h"
Jiri Pirko28d84b42014-09-28 16:33:29 -070019#include "utils.h"
20#include "ip_common.h"
21
Zhang Shengju43367ef2015-08-12 06:03:23 +000022static void print_explain(FILE *f)
Jiri Pirko28d84b42014-09-28 16:33:29 -070023{
Zhang Shengju43367ef2015-08-12 06:03:23 +000024 fprintf(f,
Jiri Pirko28d84b42014-09-28 16:33:29 -070025 "Usage: ... bridge [ forward_delay FORWARD_DELAY ]\n"
26 " [ hello_time HELLO_TIME ]\n"
27 " [ max_age MAX_AGE ]\n"
Nikolay Aleksandrov6c99fb62015-06-16 13:38:47 +030028 " [ ageing_time AGEING_TIME ]\n"
Nikolay Aleksandrovdab04962015-06-16 13:38:48 +030029 " [ stp_state STP_STATE ]\n"
Nikolay Aleksandrovb0197a02015-06-16 13:38:49 +030030 " [ priority PRIORITY ]\n"
Nikolay Aleksandrov8caaf332016-02-09 00:14:22 +010031 " [ group_fwd_mask MASK ]\n"
Nikolay Aleksandrov0a61aa32016-02-09 00:14:23 +010032 " [ group_address ADDRESS ]\n"
Nikolay Aleksandrove4d456f2015-08-12 09:19:06 -070033 " [ vlan_filtering VLAN_FILTERING ]\n"
Toshiaki Makita1eea5c42015-08-31 18:48:46 +090034 " [ vlan_protocol VLAN_PROTOCOL ]\n"
Nikolay Aleksandrov719832a2016-02-09 00:14:24 +010035 " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n"
Nikolay Aleksandrov963d1372016-02-09 00:14:25 +010036 " [ mcast_router MULTICAST_ROUTER ]\n"
Toshiaki Makita1eea5c42015-08-31 18:48:46 +090037 "\n"
38 "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
Jiri Pirko28d84b42014-09-28 16:33:29 -070039 );
40}
41
Zhang Shengju43367ef2015-08-12 06:03:23 +000042static void explain(void)
43{
44 print_explain(stderr);
45}
46
Nikolay Aleksandrov70dfb0b2016-02-09 00:14:19 +010047static void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf,
48 size_t len)
49{
50 char eaddr[32];
51
52 ether_ntoa_r((const struct ether_addr *)id->addr, eaddr);
53 snprintf(buf, len, "%.2x%.2x.%s", id->prio[0], id->prio[1], eaddr);
54}
55
Jiri Pirko28d84b42014-09-28 16:33:29 -070056static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
57 struct nlmsghdr *n)
58{
59 __u32 val;
60
61 while (argc > 0) {
62 if (matches(*argv, "forward_delay") == 0) {
63 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000064 if (get_u32(&val, *argv, 0))
Jiri Pirko28d84b42014-09-28 16:33:29 -070065 invarg("invalid forward_delay", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000066
Jiri Pirko28d84b42014-09-28 16:33:29 -070067 addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
68 } else if (matches(*argv, "hello_time") == 0) {
69 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000070 if (get_u32(&val, *argv, 0))
Jiri Pirko28d84b42014-09-28 16:33:29 -070071 invarg("invalid hello_time", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000072
Jiri Pirko28d84b42014-09-28 16:33:29 -070073 addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
74 } else if (matches(*argv, "max_age") == 0) {
75 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000076 if (get_u32(&val, *argv, 0))
Jiri Pirko28d84b42014-09-28 16:33:29 -070077 invarg("invalid max_age", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000078
Jiri Pirko28d84b42014-09-28 16:33:29 -070079 addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
Nikolay Aleksandrov6c99fb62015-06-16 13:38:47 +030080 } else if (matches(*argv, "ageing_time") == 0) {
81 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000082 if (get_u32(&val, *argv, 0))
Nikolay Aleksandrov6c99fb62015-06-16 13:38:47 +030083 invarg("invalid ageing_time", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000084
Nikolay Aleksandrov6c99fb62015-06-16 13:38:47 +030085 addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
Nikolay Aleksandrovdab04962015-06-16 13:38:48 +030086 } else if (matches(*argv, "stp_state") == 0) {
87 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000088 if (get_u32(&val, *argv, 0))
Nikolay Aleksandrovdab04962015-06-16 13:38:48 +030089 invarg("invalid stp_state", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000090
Nikolay Aleksandrovdab04962015-06-16 13:38:48 +030091 addattr32(n, 1024, IFLA_BR_STP_STATE, val);
Nikolay Aleksandrovb0197a02015-06-16 13:38:49 +030092 } else if (matches(*argv, "priority") == 0) {
93 __u16 prio;
94
95 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000096 if (get_u16(&prio, *argv, 0))
Nikolay Aleksandrovb0197a02015-06-16 13:38:49 +030097 invarg("invalid priority", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000098
Nikolay Aleksandrovb0197a02015-06-16 13:38:49 +030099 addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
Nikolay Aleksandrove4d456f2015-08-12 09:19:06 -0700100 } else if (matches(*argv, "vlan_filtering") == 0) {
101 __u8 vlan_filter;
102
103 NEXT_ARG();
104 if (get_u8(&vlan_filter, *argv, 0)) {
105 invarg("invalid vlan_filtering", *argv);
106 return -1;
107 }
108 addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
Toshiaki Makita1eea5c42015-08-31 18:48:46 +0900109 } else if (matches(*argv, "vlan_protocol") == 0) {
110 __u16 vlan_proto;
111
112 NEXT_ARG();
113 if (ll_proto_a2n(&vlan_proto, *argv)) {
114 invarg("invalid vlan_protocol", *argv);
115 return -1;
116 }
117 addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
Nikolay Aleksandrov8caaf332016-02-09 00:14:22 +0100118 } else if (matches(*argv, "group_fwd_mask") == 0) {
119 __u16 fwd_mask;
120
121 NEXT_ARG();
122 if (get_u16(&fwd_mask, *argv, 0))
123 invarg("invalid group_fwd_mask", *argv);
124
125 addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask);
Nikolay Aleksandrov0a61aa32016-02-09 00:14:23 +0100126 } else if (matches(*argv, "group_address") == 0) {
127 char llabuf[32];
128 int len;
129
130 NEXT_ARG();
131 len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv);
132 if (len < 0)
133 return -1;
134 addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len);
Nikolay Aleksandrov719832a2016-02-09 00:14:24 +0100135 } else if (matches(*argv, "vlan_default_pvid") == 0) {
136 __u16 default_pvid;
137
138 NEXT_ARG();
139 if (get_u16(&default_pvid, *argv, 0))
140 invarg("invalid vlan_default_pvid", *argv);
141
142 addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID,
143 default_pvid);
Nikolay Aleksandrov963d1372016-02-09 00:14:25 +0100144 } else if (matches(*argv, "mcast_router") == 0) {
145 __u8 mcast_router;
146
147 NEXT_ARG();
148 if (get_u8(&mcast_router, *argv, 0))
149 invarg("invalid mcast_router", *argv);
150
151 addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router);
Jiri Pirko28d84b42014-09-28 16:33:29 -0700152 } else if (matches(*argv, "help") == 0) {
153 explain();
154 return -1;
155 } else {
156 fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
157 explain();
158 return -1;
159 }
160 argc--, argv++;
161 }
162
163 return 0;
164}
165
166static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
167{
168 if (!tb)
169 return;
170
171 if (tb[IFLA_BR_FORWARD_DELAY])
172 fprintf(f, "forward_delay %u ",
173 rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
174
175 if (tb[IFLA_BR_HELLO_TIME])
176 fprintf(f, "hello_time %u ",
177 rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
178
179 if (tb[IFLA_BR_MAX_AGE])
180 fprintf(f, "max_age %u ",
181 rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
Nikolay Aleksandrovfdba0512015-08-12 09:11:30 -0700182
183 if (tb[IFLA_BR_AGEING_TIME])
184 fprintf(f, "ageing_time %u ",
185 rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
186
187 if (tb[IFLA_BR_STP_STATE])
188 fprintf(f, "stp_state %u ",
189 rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
190
191 if (tb[IFLA_BR_PRIORITY])
192 fprintf(f, "priority %u ",
193 rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
Nikolay Aleksandrove4d456f2015-08-12 09:19:06 -0700194
195 if (tb[IFLA_BR_VLAN_FILTERING])
196 fprintf(f, "vlan_filtering %u ",
197 rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
Toshiaki Makita1eea5c42015-08-31 18:48:46 +0900198
199 if (tb[IFLA_BR_VLAN_PROTOCOL]) {
200 SPRINT_BUF(b1);
201
202 fprintf(f, "vlan_protocol %s ",
203 ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
204 b1, sizeof(b1)));
205 }
Nikolay Aleksandrov70dfb0b2016-02-09 00:14:19 +0100206
207 if (tb[IFLA_BR_BRIDGE_ID]) {
208 char bridge_id[32];
209
210 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
211 sizeof(bridge_id));
212 fprintf(f, "bridge_id %s ", bridge_id);
213 }
214
215 if (tb[IFLA_BR_ROOT_ID]) {
216 char root_id[32];
217
218 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
219 sizeof(root_id));
220 fprintf(f, "designated_root %s ", root_id);
221 }
Nikolay Aleksandrov4e3bbc62016-02-09 00:14:20 +0100222
223 if (tb[IFLA_BR_ROOT_PORT])
224 fprintf(f, "root_port %u ",
225 rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
226
227 if (tb[IFLA_BR_ROOT_PATH_COST])
228 fprintf(f, "root_path_cost %u ",
229 rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
230
231 if (tb[IFLA_BR_TOPOLOGY_CHANGE])
232 fprintf(f, "topology_change %u ",
233 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
234
235 if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
236 fprintf(f, "topology_change_detected %u ",
237 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
Nikolay Aleksandrov8c0f7a12016-02-09 00:14:21 +0100238
239 if (tb[IFLA_BR_HELLO_TIMER]) {
240 struct timeval tv;
241
242 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER]));
243 fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec,
244 (int)tv.tv_usec/10000);
245 }
246
247 if (tb[IFLA_BR_TCN_TIMER]) {
248 struct timeval tv;
249
250 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER]));
251 fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec,
252 (int)tv.tv_usec/10000);
253 }
254
255 if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) {
256 unsigned long jiffies;
257 struct timeval tv;
258
259 jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
260 __jiffies_to_tv(&tv, jiffies);
261 fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec,
262 (int)tv.tv_usec/10000);
263 }
264
265 if (tb[IFLA_BR_GC_TIMER]) {
266 struct timeval tv;
267
268 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER]));
269 fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec,
270 (int)tv.tv_usec/10000);
271 }
Nikolay Aleksandrov8caaf332016-02-09 00:14:22 +0100272
Nikolay Aleksandrov719832a2016-02-09 00:14:24 +0100273 if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
274 fprintf(f, "vlan_default_pvid %u ",
275 rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
276
Nikolay Aleksandrov8caaf332016-02-09 00:14:22 +0100277 if (tb[IFLA_BR_GROUP_FWD_MASK])
278 fprintf(f, "group_fwd_mask %#x ",
279 rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
Nikolay Aleksandrov0a61aa32016-02-09 00:14:23 +0100280
281 if (tb[IFLA_BR_GROUP_ADDR]) {
282 SPRINT_BUF(mac);
283
284 fprintf(f, "group_address %s ",
285 ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
286 RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
287 1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
288 }
Nikolay Aleksandrov963d1372016-02-09 00:14:25 +0100289
290 if (tb[IFLA_BR_MCAST_ROUTER])
291 fprintf(f, "mcast_router %u ",
292 rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
Jiri Pirko28d84b42014-09-28 16:33:29 -0700293}
294
Zhang Shengju43367ef2015-08-12 06:03:23 +0000295static void bridge_print_help(struct link_util *lu, int argc, char **argv,
296 FILE *f)
297{
298 print_explain(f);
299}
300
Jiri Pirko28d84b42014-09-28 16:33:29 -0700301struct link_util bridge_link_util = {
302 .id = "bridge",
303 .maxattr = IFLA_BR_MAX,
304 .parse_opt = bridge_parse_opt,
305 .print_opt = bridge_print_opt,
Zhang Shengju43367ef2015-08-12 06:03:23 +0000306 .print_help = bridge_print_help,
Jiri Pirko28d84b42014-09-28 16:33:29 -0700307};