]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink_macvlan.c
devlink: Introduce PCI SF port flavour and attribute
[mirror_iproute2.git] / ip / iplink_macvlan.c
1 /*
2 * iplink_macvlan.c macvlan/macvtap 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: Patrick McHardy <kaber@trash.net>
10 * Arnd Bergmann <arnd@arndb.de>
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
30 static 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\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
44 static void explain(struct link_util *lu)
45 {
46 print_explain(lu, stderr);
47 }
48
49
50 static 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
58 static int flag_arg(const char *arg)
59 {
60 fprintf(stderr,
61 "Error: argument of \"flag\" must be \"nopromisc\" or \"null\", not \"%s\"\n",
62 arg);
63 return -1;
64 }
65
66 static 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
74 static 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, "null") == 0)
106 flags |= 0;
107 else
108 return flag_arg(*argv);
109
110 has_flags = 1;
111
112 } else if (matches(*argv, "macaddr") == 0) {
113 NEXT_ARG();
114
115 if (strcmp(*argv, "add") == 0) {
116 mac_mode = MACVLAN_MACADDR_ADD;
117 } else if (strcmp(*argv, "del") == 0) {
118 mac_mode = MACVLAN_MACADDR_DEL;
119 } else if (strcmp(*argv, "set") == 0) {
120 mac_mode = MACVLAN_MACADDR_SET;
121 } else if (strcmp(*argv, "flush") == 0) {
122 mac_mode = MACVLAN_MACADDR_FLUSH;
123 } else {
124 explain(lu);
125 return -1;
126 }
127
128 addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode);
129
130 if (mac_mode == MACVLAN_MACADDR_ADD ||
131 mac_mode == MACVLAN_MACADDR_DEL) {
132 NEXT_ARG();
133
134 if (ll_addr_a2n(mac, sizeof(mac),
135 *argv) != ETH_ALEN)
136 return -1;
137
138 addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, &mac,
139 ETH_ALEN);
140 }
141
142 if (mac_mode == MACVLAN_MACADDR_SET) {
143 nmac = addattr_nest(n, 1024,
144 IFLA_MACVLAN_MACADDR_DATA);
145 while (NEXT_ARG_OK()) {
146 NEXT_ARG_FWD();
147
148 if (ll_addr_a2n(mac, sizeof(mac),
149 *argv) != ETH_ALEN) {
150 PREV_ARG();
151 break;
152 }
153
154 addattr_l(n, 1024, IFLA_MACVLAN_MACADDR,
155 &mac, ETH_ALEN);
156 }
157 addattr_nest_end(n, nmac);
158 }
159 } else if (matches(*argv, "nopromisc") == 0) {
160 flags |= MACVLAN_FLAG_NOPROMISC;
161 has_flags = 1;
162 } else if (matches(*argv, "bcqueuelen") == 0) {
163 __u32 bc_queue_len;
164 NEXT_ARG();
165
166 if (get_u32(&bc_queue_len, *argv, 0)) {
167 return bc_queue_len_arg(*argv);
168 }
169 addattr32(n, 1024, IFLA_MACVLAN_BC_QUEUE_LEN, bc_queue_len);
170 } else if (matches(*argv, "help") == 0) {
171 explain(lu);
172 return -1;
173 } else {
174 pfx_err(lu, "unknown option \"%s\"?", *argv);
175 explain(lu);
176 return -1;
177 }
178 argc--, argv++;
179 }
180
181 if (mode)
182 addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
183
184 if (has_flags) {
185 if (flags & MACVLAN_FLAG_NOPROMISC &&
186 mode != MACVLAN_MODE_PASSTHRU) {
187 pfx_err(lu, "nopromisc flag only valid in passthru mode");
188 explain(lu);
189 return -1;
190 }
191 addattr16(n, 1024, IFLA_MACVLAN_FLAGS, flags);
192 }
193 return 0;
194 }
195
196 static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
197 {
198 __u32 mode;
199 __u16 flags;
200 __u32 count;
201 unsigned char *addr;
202 int len;
203 struct rtattr *rta;
204
205 if (!tb)
206 return;
207
208 if (!tb[IFLA_MACVLAN_MODE] ||
209 RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
210 return;
211
212 mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
213 print_string(PRINT_ANY,
214 "mode",
215 "mode %s ",
216 mode == MACVLAN_MODE_PRIVATE ? "private"
217 : mode == MACVLAN_MODE_VEPA ? "vepa"
218 : mode == MACVLAN_MODE_BRIDGE ? "bridge"
219 : mode == MACVLAN_MODE_PASSTHRU ? "passthru"
220 : mode == MACVLAN_MODE_SOURCE ? "source"
221 : "unknown");
222
223 if (!tb[IFLA_MACVLAN_FLAGS] ||
224 RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
225 flags = 0;
226 else
227 flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
228
229 if (flags & MACVLAN_FLAG_NOPROMISC)
230 print_bool(PRINT_ANY, "nopromisc", "nopromisc ", true);
231
232 if (tb[IFLA_MACVLAN_BC_QUEUE_LEN] &&
233 RTA_PAYLOAD(tb[IFLA_MACVLAN_BC_QUEUE_LEN]) >= sizeof(__u32)) {
234 __u32 bc_queue_len = rta_getattr_u32(tb[IFLA_MACVLAN_BC_QUEUE_LEN]);
235 print_luint(PRINT_ANY, "bcqueuelen", "bcqueuelen %lu ", bc_queue_len);
236 }
237
238 if (tb[IFLA_MACVLAN_BC_QUEUE_LEN_USED] &&
239 RTA_PAYLOAD(tb[IFLA_MACVLAN_BC_QUEUE_LEN_USED]) >= sizeof(__u32)) {
240 __u32 bc_queue_len = rta_getattr_u32(tb[IFLA_MACVLAN_BC_QUEUE_LEN_USED]);
241 print_luint(PRINT_ANY, "usedbcqueuelen", "usedbcqueuelen %lu ", bc_queue_len);
242 }
243
244 /* in source mode, there are more options to print */
245
246 if (mode != MACVLAN_MODE_SOURCE)
247 return;
248
249 if (!tb[IFLA_MACVLAN_MACADDR_COUNT] ||
250 RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32))
251 return;
252
253 count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
254 print_int(PRINT_ANY, "macaddr_count", "remotes (%d) ", count);
255
256 if (!tb[IFLA_MACVLAN_MACADDR_DATA])
257 return;
258
259 rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]);
260 len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]);
261
262 open_json_array(PRINT_JSON, "macaddr_data");
263 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
264 if (rta->rta_type != IFLA_MACVLAN_MACADDR ||
265 RTA_PAYLOAD(rta) < 6)
266 continue;
267 addr = RTA_DATA(rta);
268 if (is_json_context()) {
269 SPRINT_BUF(b1);
270
271 snprintf(b1, sizeof(b1),
272 "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0],
273 addr[1], addr[2], addr[3], addr[4], addr[5]);
274 print_string(PRINT_JSON, NULL, NULL, b1);
275 } else {
276 fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
277 addr[1], addr[2], addr[3], addr[4], addr[5]);
278 }
279 }
280 close_json_array(PRINT_JSON, NULL);
281 }
282
283 static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
284 FILE *f)
285 {
286 print_explain(lu, f);
287 }
288
289 struct link_util macvlan_link_util = {
290 .id = "macvlan",
291 .maxattr = IFLA_MACVLAN_MAX,
292 .parse_opt = macvlan_parse_opt,
293 .print_opt = macvlan_print_opt,
294 .print_help = macvlan_print_help,
295 };
296
297 struct link_util macvtap_link_util = {
298 .id = "macvtap",
299 .maxattr = IFLA_MACVLAN_MAX,
300 .parse_opt = macvlan_parse_opt,
301 .print_opt = macvlan_print_opt,
302 .print_help = macvlan_print_help,
303 };