2 * iplink_macvlan.c macvlan/macvtap device support
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.
9 * Authors: Patrick McHardy <kaber@trash.net>
10 * Arnd Bergmann <arnd@arndb.de>
16 #include <sys/socket.h>
17 #include <linux/if_link.h>
18 #include <linux/if_ether.h>
22 #include "ip_common.h"
24 #define pfx_err(lu, ...) { \
25 fprintf(stderr, "%s: ", lu->id); \
26 fprintf(stderr, __VA_ARGS__); \
27 fprintf(stderr, "\n"); \
30 static void print_explain(struct link_util
*lu
, FILE *f
)
33 "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\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",
43 static void explain(struct link_util
*lu
)
45 print_explain(lu
, stderr
);
49 static int mode_arg(const char *arg
)
52 "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n",
57 static int flag_arg(const char *arg
)
60 "Error: argument of \"flag\" must be \"nopromisc\" or \"null\", not \"%s\"\n",
65 static int macvlan_parse_opt(struct link_util
*lu
, int argc
, char **argv
,
76 if (matches(*argv
, "mode") == 0) {
79 if (strcmp(*argv
, "private") == 0)
80 mode
= MACVLAN_MODE_PRIVATE
;
81 else if (strcmp(*argv
, "vepa") == 0)
82 mode
= MACVLAN_MODE_VEPA
;
83 else if (strcmp(*argv
, "bridge") == 0)
84 mode
= MACVLAN_MODE_BRIDGE
;
85 else if (strcmp(*argv
, "passthru") == 0)
86 mode
= MACVLAN_MODE_PASSTHRU
;
87 else if (strcmp(*argv
, "source") == 0)
88 mode
= MACVLAN_MODE_SOURCE
;
90 return mode_arg(*argv
);
91 } else if (matches(*argv
, "flag") == 0) {
94 if (strcmp(*argv
, "nopromisc") == 0)
95 flags
|= MACVLAN_FLAG_NOPROMISC
;
96 else if (strcmp(*argv
, "null") == 0)
99 return flag_arg(*argv
);
103 } else if (matches(*argv
, "macaddr") == 0) {
106 if (strcmp(*argv
, "add") == 0) {
107 mac_mode
= MACVLAN_MACADDR_ADD
;
108 } else if (strcmp(*argv
, "del") == 0) {
109 mac_mode
= MACVLAN_MACADDR_DEL
;
110 } else if (strcmp(*argv
, "set") == 0) {
111 mac_mode
= MACVLAN_MACADDR_SET
;
112 } else if (strcmp(*argv
, "flush") == 0) {
113 mac_mode
= MACVLAN_MACADDR_FLUSH
;
119 addattr32(n
, 1024, IFLA_MACVLAN_MACADDR_MODE
, mac_mode
);
121 if (mac_mode
== MACVLAN_MACADDR_ADD
||
122 mac_mode
== MACVLAN_MACADDR_DEL
) {
125 if (ll_addr_a2n(mac
, sizeof(mac
),
129 addattr_l(n
, 1024, IFLA_MACVLAN_MACADDR
, &mac
,
133 if (mac_mode
== MACVLAN_MACADDR_SET
) {
134 nmac
= addattr_nest(n
, 1024,
135 IFLA_MACVLAN_MACADDR_DATA
);
136 while (NEXT_ARG_OK()) {
139 if (ll_addr_a2n(mac
, sizeof(mac
),
140 *argv
) != ETH_ALEN
) {
145 addattr_l(n
, 1024, IFLA_MACVLAN_MACADDR
,
148 addattr_nest_end(n
, nmac
);
150 } else if (matches(*argv
, "nopromisc") == 0) {
151 flags
|= MACVLAN_FLAG_NOPROMISC
;
153 } else if (matches(*argv
, "help") == 0) {
157 pfx_err(lu
, "unknown option \"%s\"?", *argv
);
165 addattr32(n
, 1024, IFLA_MACVLAN_MODE
, mode
);
168 if (flags
& MACVLAN_FLAG_NOPROMISC
&&
169 mode
!= MACVLAN_MODE_PASSTHRU
) {
170 pfx_err(lu
, "nopromisc flag only valid in passthru mode");
174 addattr16(n
, 1024, IFLA_MACVLAN_FLAGS
, flags
);
179 static void macvlan_print_opt(struct link_util
*lu
, FILE *f
, struct rtattr
*tb
[])
191 if (!tb
[IFLA_MACVLAN_MODE
] ||
192 RTA_PAYLOAD(tb
[IFLA_MACVLAN_MODE
]) < sizeof(__u32
))
195 mode
= rta_getattr_u32(tb
[IFLA_MACVLAN_MODE
]);
196 print_string(PRINT_ANY
,
199 mode
== MACVLAN_MODE_PRIVATE
? "private"
200 : mode
== MACVLAN_MODE_VEPA
? "vepa"
201 : mode
== MACVLAN_MODE_BRIDGE
? "bridge"
202 : mode
== MACVLAN_MODE_PASSTHRU
? "passthru"
203 : mode
== MACVLAN_MODE_SOURCE
? "source"
206 if (!tb
[IFLA_MACVLAN_FLAGS
] ||
207 RTA_PAYLOAD(tb
[IFLA_MACVLAN_FLAGS
]) < sizeof(__u16
))
210 flags
= rta_getattr_u16(tb
[IFLA_MACVLAN_FLAGS
]);
212 if (flags
& MACVLAN_FLAG_NOPROMISC
)
213 print_bool(PRINT_ANY
, "nopromisc", "nopromisc ", true);
215 /* in source mode, there are more options to print */
217 if (mode
!= MACVLAN_MODE_SOURCE
)
220 if (!tb
[IFLA_MACVLAN_MACADDR_COUNT
] ||
221 RTA_PAYLOAD(tb
[IFLA_MACVLAN_MACADDR_COUNT
]) < sizeof(__u32
))
224 count
= rta_getattr_u32(tb
[IFLA_MACVLAN_MACADDR_COUNT
]);
225 print_int(PRINT_ANY
, "macaddr_count", "remotes (%d) ", count
);
227 if (!tb
[IFLA_MACVLAN_MACADDR_DATA
])
230 rta
= RTA_DATA(tb
[IFLA_MACVLAN_MACADDR_DATA
]);
231 len
= RTA_PAYLOAD(tb
[IFLA_MACVLAN_MACADDR_DATA
]);
233 open_json_array(PRINT_JSON
, "macaddr_data");
234 for (; RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
235 if (rta
->rta_type
!= IFLA_MACVLAN_MACADDR
||
236 RTA_PAYLOAD(rta
) < 6)
238 addr
= RTA_DATA(rta
);
239 if (is_json_context()) {
242 snprintf(b1
, sizeof(b1
),
243 "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr
[0],
244 addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
245 print_string(PRINT_JSON
, NULL
, NULL
, b1
);
247 fprintf(f
, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr
[0],
248 addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
251 close_json_array(PRINT_JSON
, NULL
);
254 static void macvlan_print_help(struct link_util
*lu
, int argc
, char **argv
,
257 print_explain(lu
, f
);
260 struct link_util macvlan_link_util
= {
262 .maxattr
= IFLA_MACVLAN_MAX
,
263 .parse_opt
= macvlan_parse_opt
,
264 .print_opt
= macvlan_print_opt
,
265 .print_help
= macvlan_print_help
,
268 struct link_util macvtap_link_util
= {
270 .maxattr
= IFLA_MACVLAN_MAX
,
271 .parse_opt
= macvlan_parse_opt
,
272 .print_opt
= macvlan_print_opt
,
273 .print_help
= macvlan_print_help
,