1
2
3
4
5
6
7
8
9
10
11
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/socket.h>
17#include <linux/if_link.h>
18#include <linux/if_ether.h>
19
20#include "rt_names.h"
21#include "utils.h"
22#include "ip_common.h"
23
24#define pfx_err(lu, ...) { \
25 fprintf(stderr, "%s: ", lu->id); \
26 fprintf(stderr, __VA_ARGS__); \
27 fprintf(stderr, "\n"); \
28}
29
30static void print_explain(struct link_util *lu, FILE *f)
31{
32 fprintf(f,
33 "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS [bcqueuelen BC_QUEUE_LEN]\n"
34 "\n"
35 "MODE: private | vepa | bridge | passthru | source\n"
36 "MODE_FLAG: null | nopromisc | nodst\n"
37 "MODE_OPTS: for mode \"source\":\n"
38 "\tmacaddr { { add | del } <macaddr> | set [ <macaddr> [ <macaddr> ... ] ] | flush }\n"
39 "BC_QUEUE_LEN: Length of the rx queue for broadcast/multicast: [0-4294967295]\n",
40 lu->id
41 );
42}
43
44static void explain(struct link_util *lu)
45{
46 print_explain(lu, stderr);
47}
48
49
50static int mode_arg(const char *arg)
51{
52 fprintf(stderr,
53 "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n",
54 arg);
55 return -1;
56}
57
58static int flag_arg(const char *arg)
59{
60 fprintf(stderr,
61 "Error: argument of \"flag\" must be \"nopromisc\", \"nodst\" or \"null\", not \"%s\"\n",
62 arg);
63 return -1;
64}
65
66static int bc_queue_len_arg(const char *arg)
67{
68 fprintf(stderr,
69 "Error: argument of \"bcqueuelen\" must be a positive integer [0-4294967295], not \"%s\"\n",
70 arg);
71 return -1;
72}
73
74static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
75 struct nlmsghdr *n)
76{
77 __u32 mode = 0;
78 __u16 flags = 0;
79 __u32 mac_mode = 0;
80 int has_flags = 0;
81 char mac[ETH_ALEN];
82 struct rtattr *nmac;
83
84 while (argc > 0) {
85 if (matches(*argv, "mode") == 0) {
86 NEXT_ARG();
87
88 if (strcmp(*argv, "private") == 0)
89 mode = MACVLAN_MODE_PRIVATE;
90 else if (strcmp(*argv, "vepa") == 0)
91 mode = MACVLAN_MODE_VEPA;
92 else if (strcmp(*argv, "bridge") == 0)
93 mode = MACVLAN_MODE_BRIDGE;
94 else if (strcmp(*argv, "passthru") == 0)
95 mode = MACVLAN_MODE_PASSTHRU;
96 else if (strcmp(*argv, "source") == 0)
97 mode = MACVLAN_MODE_SOURCE;
98 else
99 return mode_arg(*argv);
100 } else if (matches(*argv, "flag") == 0) {
101 NEXT_ARG();
102
103 if (strcmp(*argv, "nopromisc") == 0)
104 flags |= MACVLAN_FLAG_NOPROMISC;
105 else if (strcmp(*argv, "nodst") == 0)
106 flags |= MACVLAN_FLAG_NODST;
107 else if (strcmp(*argv, "null") == 0)
108 flags |= 0;
109 else
110 return flag_arg(*argv);
111
112 has_flags = 1;
113
114 } else if (matches(*argv, "macaddr") == 0) {
115 NEXT_ARG();
116
117 if (strcmp(*argv, "add") == 0) {
118 mac_mode = MACVLAN_MACADDR_ADD;
119 } else if (strcmp(*argv, "del") == 0) {
120 mac_mode = MACVLAN_MACADDR_DEL;
121 } else if (strcmp(*argv, "set") == 0) {
122 mac_mode = MACVLAN_MACADDR_SET;
123 } else if (strcmp(*argv, "flush") == 0) {
124 mac_mode = MACVLAN_MACADDR_FLUSH;
125 } else {
126 explain(lu);
127 return -1;
128 }
129
130 addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode);
131
132 if (mac_mode == MACVLAN_MACADDR_ADD ||
133 mac_mode == MACVLAN_MACADDR_DEL) {
134 NEXT_ARG();
135
136 if (ll_addr_a2n(mac, sizeof(mac),
137 *argv) != ETH_ALEN)
138 return -1;
139
140 addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, &mac,
141 ETH_ALEN);
142 }
143
144 if (mac_mode == MACVLAN_MACADDR_SET) {
145 nmac = addattr_nest(n, 1024,
146 IFLA_MACVLAN_MACADDR_DATA);
147 while (NEXT_ARG_OK()) {
148 NEXT_ARG_FWD();
149
150 if (ll_addr_a2n(mac, sizeof(mac),
151 *argv) != ETH_ALEN) {
152 PREV_ARG();
153 break;
154 }
155
156 addattr_l(n, 1024, IFLA_MACVLAN_MACADDR,
157 &mac, ETH_ALEN);
158 }
159 addattr_nest_end(n, nmac);
160 }
161 } else if (matches(*argv, "nopromisc") == 0) {
162 flags |= MACVLAN_FLAG_NOPROMISC;
163 has_flags = 1;
164 } else if (matches(*argv, "nodst") == 0) {
165 flags |= MACVLAN_FLAG_NODST;
166 has_flags = 1;
167 } else if (matches(*argv, "bcqueuelen") == 0) {
168 __u32 bc_queue_len;
169 NEXT_ARG();
170
171 if (get_u32(&bc_queue_len, *argv, 0)) {
172 return bc_queue_len_arg(*argv);
173 }
174 addattr32(n, 1024, IFLA_MACVLAN_BC_QUEUE_LEN, bc_queue_len);
175 } else if (matches(*argv, "help") == 0) {
176 explain(lu);
177 return -1;
178 } else {
179 pfx_err(lu, "unknown option \"%s\"?", *argv);
180 explain(lu);
181 return -1;
182 }
183 argc--, argv++;
184 }
185
186 if (mode)
187 addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
188
189 if (has_flags) {
190 if (flags & MACVLAN_FLAG_NOPROMISC &&
191 mode != MACVLAN_MODE_PASSTHRU) {
192 pfx_err(lu, "nopromisc flag only valid in passthru mode");
193 explain(lu);
194 return -1;
195 }
196 addattr16(n, 1024, IFLA_MACVLAN_FLAGS, flags);
197 }
198 return 0;
199}
200
201static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
202{
203 __u32 mode;
204 __u16 flags;
205 __u32 count;
206 unsigned char *addr;
207 int len;
208 struct rtattr *rta;
209
210 if (!tb)
211 return;
212
213 if (!tb[IFLA_MACVLAN_MODE] ||
214 RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
215 return;
216
217 mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
218 print_string(PRINT_ANY,
219 "mode",
220 "mode %s ",
221 mode == MACVLAN_MODE_PRIVATE ? "private"
222 : mode == MACVLAN_MODE_VEPA ? "vepa"
223 : mode == MACVLAN_MODE_BRIDGE ? "bridge"
224 : mode == MACVLAN_MODE_PASSTHRU ? "passthru"
225 : mode == MACVLAN_MODE_SOURCE ? "source"
226 : "unknown");
227
228 if (!tb[IFLA_MACVLAN_FLAGS] ||
229 RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
230 flags = 0;
231 else
232 flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
233
234 if (flags & MACVLAN_FLAG_NOPROMISC)
235 print_bool(PRINT_ANY, "nopromisc", "nopromisc ", true);
236
237 if (flags & MACVLAN_FLAG_NODST)
238 print_bool(PRINT_ANY, "nodst", "nodst ", true);
239
240 if (tb[IFLA_MACVLAN_BC_QUEUE_LEN] &&
241 RTA_PAYLOAD(tb[IFLA_MACVLAN_BC_QUEUE_LEN]) >= sizeof(__u32)) {
242 __u32 bc_queue_len = rta_getattr_u32(tb[IFLA_MACVLAN_BC_QUEUE_LEN]);
243 print_luint(PRINT_ANY, "bcqueuelen", "bcqueuelen %lu ", bc_queue_len);
244 }
245
246 if (tb[IFLA_MACVLAN_BC_QUEUE_LEN_USED] &&
247 RTA_PAYLOAD(tb[IFLA_MACVLAN_BC_QUEUE_LEN_USED]) >= sizeof(__u32)) {
248 __u32 bc_queue_len = rta_getattr_u32(tb[IFLA_MACVLAN_BC_QUEUE_LEN_USED]);
249 print_luint(PRINT_ANY, "usedbcqueuelen", "usedbcqueuelen %lu ", bc_queue_len);
250 }
251
252
253
254 if (mode != MACVLAN_MODE_SOURCE)
255 return;
256
257 if (!tb[IFLA_MACVLAN_MACADDR_COUNT] ||
258 RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32))
259 return;
260
261 count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
262 print_int(PRINT_ANY, "macaddr_count", "remotes (%d) ", count);
263
264 if (!tb[IFLA_MACVLAN_MACADDR_DATA])
265 return;
266
267 rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]);
268 len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]);
269
270 open_json_array(PRINT_JSON, "macaddr_data");
271 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
272 if (rta->rta_type != IFLA_MACVLAN_MACADDR ||
273 RTA_PAYLOAD(rta) < 6)
274 continue;
275 addr = RTA_DATA(rta);
276 if (is_json_context()) {
277 SPRINT_BUF(b1);
278
279 snprintf(b1, sizeof(b1),
280 "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0],
281 addr[1], addr[2], addr[3], addr[4], addr[5]);
282 print_string(PRINT_JSON, NULL, NULL, b1);
283 } else {
284 fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
285 addr[1], addr[2], addr[3], addr[4], addr[5]);
286 }
287 }
288 close_json_array(PRINT_JSON, NULL);
289}
290
291static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
292 FILE *f)
293{
294 print_explain(lu, f);
295}
296
297struct link_util macvlan_link_util = {
298 .id = "macvlan",
299 .maxattr = IFLA_MACVLAN_MAX,
300 .parse_opt = macvlan_parse_opt,
301 .print_opt = macvlan_print_opt,
302 .print_help = macvlan_print_help,
303};
304
305struct link_util macvtap_link_util = {
306 .id = "macvtap",
307 .maxattr = IFLA_MACVLAN_MAX,
308 .parse_opt = macvlan_parse_opt,
309 .print_opt = macvlan_print_opt,
310 .print_help = macvlan_print_help,
311};
312