blob: 2ee4bd690a28e3d14f84b6572c60b3bdda09d4b9 [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 Aleksandrove4d456f2015-08-12 09:19:06 -070032 " [ vlan_filtering VLAN_FILTERING ]\n"
Toshiaki Makita1eea5c42015-08-31 18:48:46 +090033 " [ vlan_protocol VLAN_PROTOCOL ]\n"
34 "\n"
35 "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n"
Jiri Pirko28d84b42014-09-28 16:33:29 -070036 );
37}
38
Zhang Shengju43367ef2015-08-12 06:03:23 +000039static void explain(void)
40{
41 print_explain(stderr);
42}
43
Nikolay Aleksandrov70dfb0b2016-02-09 00:14:19 +010044static void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf,
45 size_t len)
46{
47 char eaddr[32];
48
49 ether_ntoa_r((const struct ether_addr *)id->addr, eaddr);
50 snprintf(buf, len, "%.2x%.2x.%s", id->prio[0], id->prio[1], eaddr);
51}
52
Jiri Pirko28d84b42014-09-28 16:33:29 -070053static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
54 struct nlmsghdr *n)
55{
56 __u32 val;
57
58 while (argc > 0) {
59 if (matches(*argv, "forward_delay") == 0) {
60 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000061 if (get_u32(&val, *argv, 0))
Jiri Pirko28d84b42014-09-28 16:33:29 -070062 invarg("invalid forward_delay", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000063
Jiri Pirko28d84b42014-09-28 16:33:29 -070064 addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
65 } else if (matches(*argv, "hello_time") == 0) {
66 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000067 if (get_u32(&val, *argv, 0))
Jiri Pirko28d84b42014-09-28 16:33:29 -070068 invarg("invalid hello_time", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000069
Jiri Pirko28d84b42014-09-28 16:33:29 -070070 addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
71 } else if (matches(*argv, "max_age") == 0) {
72 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000073 if (get_u32(&val, *argv, 0))
Jiri Pirko28d84b42014-09-28 16:33:29 -070074 invarg("invalid max_age", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000075
Jiri Pirko28d84b42014-09-28 16:33:29 -070076 addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
Nikolay Aleksandrov6c99fb62015-06-16 13:38:47 +030077 } else if (matches(*argv, "ageing_time") == 0) {
78 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000079 if (get_u32(&val, *argv, 0))
Nikolay Aleksandrov6c99fb62015-06-16 13:38:47 +030080 invarg("invalid ageing_time", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000081
Nikolay Aleksandrov6c99fb62015-06-16 13:38:47 +030082 addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
Nikolay Aleksandrovdab04962015-06-16 13:38:48 +030083 } else if (matches(*argv, "stp_state") == 0) {
84 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000085 if (get_u32(&val, *argv, 0))
Nikolay Aleksandrovdab04962015-06-16 13:38:48 +030086 invarg("invalid stp_state", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000087
Nikolay Aleksandrovdab04962015-06-16 13:38:48 +030088 addattr32(n, 1024, IFLA_BR_STP_STATE, val);
Nikolay Aleksandrovb0197a02015-06-16 13:38:49 +030089 } else if (matches(*argv, "priority") == 0) {
90 __u16 prio;
91
92 NEXT_ARG();
Zhang Shengju6a9ce302015-08-13 07:48:15 +000093 if (get_u16(&prio, *argv, 0))
Nikolay Aleksandrovb0197a02015-06-16 13:38:49 +030094 invarg("invalid priority", *argv);
Zhang Shengju6a9ce302015-08-13 07:48:15 +000095
Nikolay Aleksandrovb0197a02015-06-16 13:38:49 +030096 addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
Nikolay Aleksandrove4d456f2015-08-12 09:19:06 -070097 } else if (matches(*argv, "vlan_filtering") == 0) {
98 __u8 vlan_filter;
99
100 NEXT_ARG();
101 if (get_u8(&vlan_filter, *argv, 0)) {
102 invarg("invalid vlan_filtering", *argv);
103 return -1;
104 }
105 addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
Toshiaki Makita1eea5c42015-08-31 18:48:46 +0900106 } else if (matches(*argv, "vlan_protocol") == 0) {
107 __u16 vlan_proto;
108
109 NEXT_ARG();
110 if (ll_proto_a2n(&vlan_proto, *argv)) {
111 invarg("invalid vlan_protocol", *argv);
112 return -1;
113 }
114 addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
Nikolay Aleksandrov8caaf332016-02-09 00:14:22 +0100115 } else if (matches(*argv, "group_fwd_mask") == 0) {
116 __u16 fwd_mask;
117
118 NEXT_ARG();
119 if (get_u16(&fwd_mask, *argv, 0))
120 invarg("invalid group_fwd_mask", *argv);
121
122 addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask);
Jiri Pirko28d84b42014-09-28 16:33:29 -0700123 } else if (matches(*argv, "help") == 0) {
124 explain();
125 return -1;
126 } else {
127 fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
128 explain();
129 return -1;
130 }
131 argc--, argv++;
132 }
133
134 return 0;
135}
136
137static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
138{
139 if (!tb)
140 return;
141
142 if (tb[IFLA_BR_FORWARD_DELAY])
143 fprintf(f, "forward_delay %u ",
144 rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
145
146 if (tb[IFLA_BR_HELLO_TIME])
147 fprintf(f, "hello_time %u ",
148 rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
149
150 if (tb[IFLA_BR_MAX_AGE])
151 fprintf(f, "max_age %u ",
152 rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
Nikolay Aleksandrovfdba0512015-08-12 09:11:30 -0700153
154 if (tb[IFLA_BR_AGEING_TIME])
155 fprintf(f, "ageing_time %u ",
156 rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
157
158 if (tb[IFLA_BR_STP_STATE])
159 fprintf(f, "stp_state %u ",
160 rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
161
162 if (tb[IFLA_BR_PRIORITY])
163 fprintf(f, "priority %u ",
164 rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
Nikolay Aleksandrove4d456f2015-08-12 09:19:06 -0700165
166 if (tb[IFLA_BR_VLAN_FILTERING])
167 fprintf(f, "vlan_filtering %u ",
168 rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
Toshiaki Makita1eea5c42015-08-31 18:48:46 +0900169
170 if (tb[IFLA_BR_VLAN_PROTOCOL]) {
171 SPRINT_BUF(b1);
172
173 fprintf(f, "vlan_protocol %s ",
174 ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
175 b1, sizeof(b1)));
176 }
Nikolay Aleksandrov70dfb0b2016-02-09 00:14:19 +0100177
178 if (tb[IFLA_BR_BRIDGE_ID]) {
179 char bridge_id[32];
180
181 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
182 sizeof(bridge_id));
183 fprintf(f, "bridge_id %s ", bridge_id);
184 }
185
186 if (tb[IFLA_BR_ROOT_ID]) {
187 char root_id[32];
188
189 br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
190 sizeof(root_id));
191 fprintf(f, "designated_root %s ", root_id);
192 }
Nikolay Aleksandrov4e3bbc62016-02-09 00:14:20 +0100193
194 if (tb[IFLA_BR_ROOT_PORT])
195 fprintf(f, "root_port %u ",
196 rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
197
198 if (tb[IFLA_BR_ROOT_PATH_COST])
199 fprintf(f, "root_path_cost %u ",
200 rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
201
202 if (tb[IFLA_BR_TOPOLOGY_CHANGE])
203 fprintf(f, "topology_change %u ",
204 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
205
206 if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
207 fprintf(f, "topology_change_detected %u ",
208 rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
Nikolay Aleksandrov8c0f7a12016-02-09 00:14:21 +0100209
210 if (tb[IFLA_BR_HELLO_TIMER]) {
211 struct timeval tv;
212
213 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER]));
214 fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec,
215 (int)tv.tv_usec/10000);
216 }
217
218 if (tb[IFLA_BR_TCN_TIMER]) {
219 struct timeval tv;
220
221 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER]));
222 fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec,
223 (int)tv.tv_usec/10000);
224 }
225
226 if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) {
227 unsigned long jiffies;
228 struct timeval tv;
229
230 jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
231 __jiffies_to_tv(&tv, jiffies);
232 fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec,
233 (int)tv.tv_usec/10000);
234 }
235
236 if (tb[IFLA_BR_GC_TIMER]) {
237 struct timeval tv;
238
239 __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER]));
240 fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec,
241 (int)tv.tv_usec/10000);
242 }
Nikolay Aleksandrov8caaf332016-02-09 00:14:22 +0100243
244 if (tb[IFLA_BR_GROUP_FWD_MASK])
245 fprintf(f, "group_fwd_mask %#x ",
246 rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
Jiri Pirko28d84b42014-09-28 16:33:29 -0700247}
248
Zhang Shengju43367ef2015-08-12 06:03:23 +0000249static void bridge_print_help(struct link_util *lu, int argc, char **argv,
250 FILE *f)
251{
252 print_explain(f);
253}
254
Jiri Pirko28d84b42014-09-28 16:33:29 -0700255struct link_util bridge_link_util = {
256 .id = "bridge",
257 .maxattr = IFLA_BR_MAX,
258 .parse_opt = bridge_parse_opt,
259 .print_opt = bridge_print_opt,
Zhang Shengju43367ef2015-08-12 06:03:23 +0000260 .print_help = bridge_print_help,
Jiri Pirko28d84b42014-09-28 16:33:29 -0700261};