]>
Commit | Line | Data |
---|---|---|
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 | 22 | static 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" |
e4d456f0 | 31 | " [ vlan_filtering VLAN_FILTERING ]\n" |
1eea5c46 TM |
32 | " [ vlan_protocol VLAN_PROTOCOL ]\n" |
33 | "\n" | |
34 | "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" | |
28d84b42 JP |
35 | ); |
36 | } | |
37 | ||
43367ef7 ZS |
38 | static void explain(void) |
39 | { | |
40 | print_explain(stderr); | |
41 | } | |
42 | ||
70dfb0b8 NA |
43 | static void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, |
44 | size_t len) | |
45 | { | |
46 | char eaddr[32]; | |
47 | ||
48 | ether_ntoa_r((const struct ether_addr *)id->addr, eaddr); | |
49 | snprintf(buf, len, "%.2x%.2x.%s", id->prio[0], id->prio[1], eaddr); | |
50 | } | |
51 | ||
28d84b42 JP |
52 | static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, |
53 | struct nlmsghdr *n) | |
54 | { | |
55 | __u32 val; | |
56 | ||
57 | while (argc > 0) { | |
58 | if (matches(*argv, "forward_delay") == 0) { | |
59 | NEXT_ARG(); | |
6a9ce30e | 60 | if (get_u32(&val, *argv, 0)) |
28d84b42 | 61 | invarg("invalid forward_delay", *argv); |
6a9ce30e | 62 | |
28d84b42 JP |
63 | addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val); |
64 | } else if (matches(*argv, "hello_time") == 0) { | |
65 | NEXT_ARG(); | |
6a9ce30e | 66 | if (get_u32(&val, *argv, 0)) |
28d84b42 | 67 | invarg("invalid hello_time", *argv); |
6a9ce30e | 68 | |
28d84b42 JP |
69 | addattr32(n, 1024, IFLA_BR_HELLO_TIME, val); |
70 | } else if (matches(*argv, "max_age") == 0) { | |
71 | NEXT_ARG(); | |
6a9ce30e | 72 | if (get_u32(&val, *argv, 0)) |
28d84b42 | 73 | invarg("invalid max_age", *argv); |
6a9ce30e | 74 | |
28d84b42 | 75 | addattr32(n, 1024, IFLA_BR_MAX_AGE, val); |
6c99fb60 NA |
76 | } else if (matches(*argv, "ageing_time") == 0) { |
77 | NEXT_ARG(); | |
6a9ce30e | 78 | if (get_u32(&val, *argv, 0)) |
6c99fb60 | 79 | invarg("invalid ageing_time", *argv); |
6a9ce30e | 80 | |
6c99fb60 | 81 | addattr32(n, 1024, IFLA_BR_AGEING_TIME, val); |
dab04962 NA |
82 | } else if (matches(*argv, "stp_state") == 0) { |
83 | NEXT_ARG(); | |
6a9ce30e | 84 | if (get_u32(&val, *argv, 0)) |
dab04962 | 85 | invarg("invalid stp_state", *argv); |
6a9ce30e | 86 | |
dab04962 | 87 | addattr32(n, 1024, IFLA_BR_STP_STATE, val); |
b0197a04 NA |
88 | } else if (matches(*argv, "priority") == 0) { |
89 | __u16 prio; | |
90 | ||
91 | NEXT_ARG(); | |
6a9ce30e | 92 | if (get_u16(&prio, *argv, 0)) |
b0197a04 | 93 | invarg("invalid priority", *argv); |
6a9ce30e | 94 | |
b0197a04 | 95 | addattr16(n, 1024, IFLA_BR_PRIORITY, prio); |
e4d456f0 NA |
96 | } else if (matches(*argv, "vlan_filtering") == 0) { |
97 | __u8 vlan_filter; | |
98 | ||
99 | NEXT_ARG(); | |
100 | if (get_u8(&vlan_filter, *argv, 0)) { | |
101 | invarg("invalid vlan_filtering", *argv); | |
102 | return -1; | |
103 | } | |
104 | addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter); | |
1eea5c46 TM |
105 | } else if (matches(*argv, "vlan_protocol") == 0) { |
106 | __u16 vlan_proto; | |
107 | ||
108 | NEXT_ARG(); | |
109 | if (ll_proto_a2n(&vlan_proto, *argv)) { | |
110 | invarg("invalid vlan_protocol", *argv); | |
111 | return -1; | |
112 | } | |
113 | addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto); | |
28d84b42 JP |
114 | } else if (matches(*argv, "help") == 0) { |
115 | explain(); | |
116 | return -1; | |
117 | } else { | |
118 | fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv); | |
119 | explain(); | |
120 | return -1; | |
121 | } | |
122 | argc--, argv++; | |
123 | } | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) | |
129 | { | |
130 | if (!tb) | |
131 | return; | |
132 | ||
133 | if (tb[IFLA_BR_FORWARD_DELAY]) | |
134 | fprintf(f, "forward_delay %u ", | |
135 | rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY])); | |
136 | ||
137 | if (tb[IFLA_BR_HELLO_TIME]) | |
138 | fprintf(f, "hello_time %u ", | |
139 | rta_getattr_u32(tb[IFLA_BR_HELLO_TIME])); | |
140 | ||
141 | if (tb[IFLA_BR_MAX_AGE]) | |
142 | fprintf(f, "max_age %u ", | |
143 | rta_getattr_u32(tb[IFLA_BR_MAX_AGE])); | |
fdba0515 NA |
144 | |
145 | if (tb[IFLA_BR_AGEING_TIME]) | |
146 | fprintf(f, "ageing_time %u ", | |
147 | rta_getattr_u32(tb[IFLA_BR_AGEING_TIME])); | |
148 | ||
149 | if (tb[IFLA_BR_STP_STATE]) | |
150 | fprintf(f, "stp_state %u ", | |
151 | rta_getattr_u32(tb[IFLA_BR_STP_STATE])); | |
152 | ||
153 | if (tb[IFLA_BR_PRIORITY]) | |
154 | fprintf(f, "priority %u ", | |
155 | rta_getattr_u16(tb[IFLA_BR_PRIORITY])); | |
e4d456f0 NA |
156 | |
157 | if (tb[IFLA_BR_VLAN_FILTERING]) | |
158 | fprintf(f, "vlan_filtering %u ", | |
159 | rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING])); | |
1eea5c46 TM |
160 | |
161 | if (tb[IFLA_BR_VLAN_PROTOCOL]) { | |
162 | SPRINT_BUF(b1); | |
163 | ||
164 | fprintf(f, "vlan_protocol %s ", | |
165 | ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]), | |
166 | b1, sizeof(b1))); | |
167 | } | |
70dfb0b8 NA |
168 | |
169 | if (tb[IFLA_BR_BRIDGE_ID]) { | |
170 | char bridge_id[32]; | |
171 | ||
172 | br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id, | |
173 | sizeof(bridge_id)); | |
174 | fprintf(f, "bridge_id %s ", bridge_id); | |
175 | } | |
176 | ||
177 | if (tb[IFLA_BR_ROOT_ID]) { | |
178 | char root_id[32]; | |
179 | ||
180 | br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id, | |
181 | sizeof(root_id)); | |
182 | fprintf(f, "designated_root %s ", root_id); | |
183 | } | |
4e3bbc66 NA |
184 | |
185 | if (tb[IFLA_BR_ROOT_PORT]) | |
186 | fprintf(f, "root_port %u ", | |
187 | rta_getattr_u16(tb[IFLA_BR_ROOT_PORT])); | |
188 | ||
189 | if (tb[IFLA_BR_ROOT_PATH_COST]) | |
190 | fprintf(f, "root_path_cost %u ", | |
191 | rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST])); | |
192 | ||
193 | if (tb[IFLA_BR_TOPOLOGY_CHANGE]) | |
194 | fprintf(f, "topology_change %u ", | |
195 | rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE])); | |
196 | ||
197 | if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]) | |
198 | fprintf(f, "topology_change_detected %u ", | |
199 | rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])); | |
28d84b42 JP |
200 | } |
201 | ||
43367ef7 ZS |
202 | static void bridge_print_help(struct link_util *lu, int argc, char **argv, |
203 | FILE *f) | |
204 | { | |
205 | print_explain(f); | |
206 | } | |
207 | ||
28d84b42 JP |
208 | struct link_util bridge_link_util = { |
209 | .id = "bridge", | |
210 | .maxattr = IFLA_BR_MAX, | |
211 | .parse_opt = bridge_parse_opt, | |
212 | .print_opt = bridge_print_opt, | |
43367ef7 | 213 | .print_help = bridge_print_help, |
28d84b42 | 214 | }; |