1
2
3
4
5
6#include <stdio.h>
7#include <sys/time.h>
8#include <netinet/in.h>
9#include <linux/if_bridge.h>
10#include <net/if.h>
11
12#include "libnetlink.h"
13#include "json_print.h"
14#include "utils.h"
15
16#include "br_common.h"
17
18#define MST_ID_LEN 9
19
20#define __stringify_1(x...) #x
21#define __stringify(x...) __stringify_1(x)
22
23static unsigned int filter_index;
24
25static void usage(void)
26{
27 fprintf(stderr,
28 "Usage: bridge mst set dev DEV msti MSTI state STATE\n"
29 " bridge mst {show} [ dev DEV ]\n");
30 exit(-1);
31}
32
33static void print_mst_entry(struct rtattr *a, FILE *fp)
34{
35 struct rtattr *tb[IFLA_BRIDGE_MST_ENTRY_MAX + 1];
36 __u16 msti = 0;
37 __u8 state = 0;
38
39 parse_rtattr_flags(tb, IFLA_BRIDGE_MST_ENTRY_MAX, RTA_DATA(a),
40 RTA_PAYLOAD(a), NLA_F_NESTED);
41
42
43 if (!(tb[IFLA_BRIDGE_MST_ENTRY_MSTI] &&
44 tb[IFLA_BRIDGE_MST_ENTRY_STATE])) {
45 fprintf(stderr, "BUG: broken MST entry");
46 return;
47 }
48
49 msti = rta_getattr_u16(tb[IFLA_BRIDGE_MST_ENTRY_MSTI]);
50 state = rta_getattr_u8(tb[IFLA_BRIDGE_MST_ENTRY_STATE]);
51
52 open_json_object(NULL);
53 print_uint(PRINT_ANY, "msti", "%u", msti);
54 print_nl();
55 print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
56 print_stp_state(state);
57 print_nl();
58 close_json_object();
59}
60
61static int print_msts(struct nlmsghdr *n, void *arg)
62{
63 struct ifinfomsg *ifi = NLMSG_DATA(n);
64 struct rtattr *af_spec, *mst, *a;
65 int rem = n->nlmsg_len;
66 bool opened = false;
67
68 rem -= NLMSG_LENGTH(sizeof(*ifi));
69 if (rem < 0) {
70 fprintf(stderr, "BUG: wrong nlmsg len %d\n", rem);
71 return -1;
72 }
73
74 af_spec = parse_rtattr_one(IFLA_AF_SPEC, IFLA_RTA(ifi), rem);
75 if (!af_spec)
76 return -1;
77
78 if (filter_index && filter_index != ifi->ifi_index)
79 return 0;
80
81 mst = parse_rtattr_one_nested(NLA_F_NESTED | IFLA_BRIDGE_MST, af_spec);
82 if (!mst)
83 return 0;
84
85 rem = RTA_PAYLOAD(mst);
86 for (a = RTA_DATA(mst); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
87 unsigned short rta_type = a->rta_type & NLA_TYPE_MASK;
88
89 if (rta_type > IFLA_BRIDGE_MST_MAX)
90 continue;
91
92 switch (rta_type) {
93 case IFLA_BRIDGE_MST_ENTRY:
94 if (!opened) {
95 open_json_object(NULL);
96 print_color_string(PRINT_ANY, COLOR_IFNAME,
97 "ifname",
98 "%-" __stringify(IFNAMSIZ) "s ",
99 ll_index_to_name(ifi->ifi_index));
100 open_json_array(PRINT_JSON, "mst");
101 opened = true;
102 } else {
103 print_string(PRINT_FP, NULL, "%-"
104 __stringify(IFNAMSIZ) "s ", "");
105 }
106
107 print_mst_entry(a, arg);
108 break;
109 }
110 }
111
112 if (opened) {
113 close_json_array(PRINT_JSON, NULL);
114 close_json_object();
115 }
116
117 return 0;
118}
119
120static int mst_show(int argc, char **argv)
121{
122 char *filter_dev = NULL;
123
124 while (argc > 0) {
125 if (strcmp(*argv, "dev") == 0) {
126 NEXT_ARG();
127 if (filter_dev)
128 duparg("dev", *argv);
129 filter_dev = *argv;
130 }
131 argc--; argv++;
132 }
133
134 if (filter_dev) {
135 filter_index = ll_name_to_index(filter_dev);
136 if (!filter_index)
137 return nodev(filter_dev);
138 }
139
140 if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE, RTEXT_FILTER_MST) < 0) {
141 perror("Cannon send dump request");
142 exit(1);
143 }
144
145 new_json_obj(json);
146
147 if (!is_json_context()) {
148 printf("%-" __stringify(IFNAMSIZ) "s "
149 "%-" __stringify(MST_ID_LEN) "s",
150 "port", "msti");
151 printf("\n");
152 }
153
154 if (rtnl_dump_filter(&rth, print_msts, stdout) < 0) {
155 fprintf(stderr, "Dump terminated\n");
156 delete_json_obj();
157 return -1;
158 }
159
160 delete_json_obj();
161 fflush(stdout);
162 return 0;
163}
164
165static int mst_set(int argc, char **argv)
166{
167 struct {
168 struct nlmsghdr n;
169 struct ifinfomsg ifi;
170 char buf[512];
171 } req = {
172 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
173 .n.nlmsg_flags = NLM_F_REQUEST,
174 .n.nlmsg_type = RTM_SETLINK,
175 .ifi.ifi_family = PF_BRIDGE,
176 };
177 char *d = NULL, *m = NULL, *s = NULL, *endptr;
178 struct rtattr *af_spec, *mst, *entry;
179 __u16 msti;
180 int state;
181
182 while (argc > 0) {
183 if (strcmp(*argv, "dev") == 0) {
184 NEXT_ARG();
185 d = *argv;
186 } else if (strcmp(*argv, "msti") == 0) {
187 NEXT_ARG();
188 m = *argv;
189 } else if (strcmp(*argv, "state") == 0) {
190 NEXT_ARG();
191 s = *argv;
192 } else {
193 if (matches(*argv, "help") == 0)
194 usage();
195 }
196 argc--; argv++;
197 }
198
199 if (d == NULL || m == NULL || s == NULL) {
200 fprintf(stderr, "Device, MSTI and state are required arguments.\n");
201 return -1;
202 }
203
204 req.ifi.ifi_index = ll_name_to_index(d);
205 if (!req.ifi.ifi_index)
206 return nodev(d);
207
208 msti = strtol(m, &endptr, 10);
209 if (!(*s != '\0' && *endptr == '\0')) {
210 fprintf(stderr,
211 "Error: invalid MSTI\n");
212 return -1;
213 }
214
215 state = strtol(s, &endptr, 10);
216 if (!(*s != '\0' && *endptr == '\0'))
217 state = parse_stp_state(s);
218
219 if (state < 0 || state > UINT8_MAX) {
220 fprintf(stderr, "Error: invalid STP port state\n");
221 return -1;
222 }
223
224 af_spec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
225 mst = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST);
226
227 entry = addattr_nest(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY);
228 entry->rta_type |= NLA_F_NESTED;
229
230 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_MSTI, msti);
231 addattr8(&req.n, sizeof(req), IFLA_BRIDGE_MST_ENTRY_STATE, state);
232
233 addattr_nest_end(&req.n, entry);
234
235 addattr_nest_end(&req.n, mst);
236 addattr_nest_end(&req.n, af_spec);
237
238
239 if (rtnl_talk(&rth, &req.n, NULL) < 0)
240 return -1;
241
242 return 0;
243}
244
245int do_mst(int argc, char **argv)
246{
247 ll_init_map(&rth);
248
249 if (argc > 0) {
250 if (matches(*argv, "set") == 0)
251 return mst_set(argc-1, argv+1);
252
253 if (matches(*argv, "show") == 0 ||
254 matches(*argv, "lst") == 0 ||
255 matches(*argv, "list") == 0)
256 return mst_show(argc-1, argv+1);
257 if (matches(*argv, "help") == 0)
258 usage();
259 } else
260 return mst_show(0, NULL);
261
262 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mst help\".\n", *argv);
263 exit(-1);
264}
265