]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink_macvlan.c
Merge branch 'iproute2-master' into iproute2-next
[mirror_iproute2.git] / ip / iplink_macvlan.c
CommitLineData
d63a9b2b 1/*
541f1b3e 2 * iplink_macvlan.c macvlan/macvtap device support
d63a9b2b
AB
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>
aa1b44ca 18#include <linux/if_ether.h>
d63a9b2b
AB
19
20#include "rt_names.h"
21#include "utils.h"
22#include "ip_common.h"
23
541f1b3e
PS
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)
d63a9b2b 31{
561e650e 32 fprintf(f,
aa1b44ca 33 "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\n"
e336868e 34 "\n"
aa1b44ca 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",
541f1b3e 39 lu->id
d63a9b2b
AB
40 );
41}
42
541f1b3e 43static void explain(struct link_util *lu)
561e650e 44{
541f1b3e 45 print_explain(lu, stderr);
561e650e 46}
47
f33b7276 48
f3f339e9 49static int mode_arg(const char *arg)
f33b7276 50{
7409334b 51 fprintf(stderr,
aa1b44ca 52 "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n",
53 arg);
54 return -1;
55}
56
57static int flag_arg(const char *arg)
58{
59 fprintf(stderr,
60 "Error: argument of \"flag\" must be \"nopromisc\" or \"null\", not \"%s\"\n",
56f5daac
SH
61 arg);
62 return -1;
d63a9b2b
AB
63}
64
65static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
66 struct nlmsghdr *n)
67{
3cf8ba59
PS
68 __u32 mode = 0;
69 __u16 flags = 0;
aa1b44ca 70 __u32 mac_mode = 0;
71 int has_flags = 0;
72 char mac[ETH_ALEN];
73 struct rtattr *nmac;
3cf8ba59 74
d63a9b2b
AB
75 while (argc > 0) {
76 if (matches(*argv, "mode") == 0) {
d63a9b2b
AB
77 NEXT_ARG();
78
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;
f0612d56
SS
85 else if (strcmp(*argv, "passthru") == 0)
86 mode = MACVLAN_MODE_PASSTHRU;
aa1b44ca 87 else if (strcmp(*argv, "source") == 0)
88 mode = MACVLAN_MODE_SOURCE;
d63a9b2b 89 else
541f1b3e 90 return mode_arg(*argv);
aa1b44ca 91 } else if (matches(*argv, "flag") == 0) {
92 NEXT_ARG();
93
94 if (strcmp(*argv, "nopromisc") == 0)
95 flags |= MACVLAN_FLAG_NOPROMISC;
96 else if (strcmp(*argv, "null") == 0)
97 flags |= 0;
98 else
99 return flag_arg(*argv);
100
101 has_flags = 1;
102
103 } else if (matches(*argv, "macaddr") == 0) {
104 NEXT_ARG();
105
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;
114 } else {
115 explain(lu);
116 return -1;
117 }
118
119 addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode);
120
121 if (mac_mode == MACVLAN_MACADDR_ADD ||
122 mac_mode == MACVLAN_MACADDR_DEL) {
123 NEXT_ARG();
124
125 if (ll_addr_a2n(mac, sizeof(mac),
126 *argv) != ETH_ALEN)
127 return -1;
128
129 addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, &mac,
130 ETH_ALEN);
131 }
132
133 if (mac_mode == MACVLAN_MACADDR_SET) {
134 nmac = addattr_nest(n, 1024,
135 IFLA_MACVLAN_MACADDR_DATA);
136 while (NEXT_ARG_OK()) {
137 NEXT_ARG_FWD();
138
139 if (ll_addr_a2n(mac, sizeof(mac),
140 *argv) != ETH_ALEN) {
141 PREV_ARG();
142 break;
143 }
144
145 addattr_l(n, 1024, IFLA_MACVLAN_MACADDR,
146 &mac, ETH_ALEN);
147 }
148 addattr_nest_end(n, nmac);
149 }
3cf8ba59
PS
150 } else if (matches(*argv, "nopromisc") == 0) {
151 flags |= MACVLAN_FLAG_NOPROMISC;
aa1b44ca 152 has_flags = 1;
d63a9b2b 153 } else if (matches(*argv, "help") == 0) {
541f1b3e 154 explain(lu);
d63a9b2b
AB
155 return -1;
156 } else {
541f1b3e
PS
157 pfx_err(lu, "unknown option \"%s\"?", *argv);
158 explain(lu);
d63a9b2b
AB
159 return -1;
160 }
161 argc--, argv++;
162 }
163
3cf8ba59
PS
164 if (mode)
165 addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
166
aa1b44ca 167 if (has_flags) {
3cf8ba59
PS
168 if (flags & MACVLAN_FLAG_NOPROMISC &&
169 mode != MACVLAN_MODE_PASSTHRU) {
170 pfx_err(lu, "nopromisc flag only valid in passthru mode");
171 explain(lu);
172 return -1;
173 }
174 addattr16(n, 1024, IFLA_MACVLAN_FLAGS, flags);
175 }
d63a9b2b
AB
176 return 0;
177}
178
179static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
180{
181 __u32 mode;
3cf8ba59 182 __u16 flags;
aa1b44ca 183 __u32 count;
184 unsigned char *addr;
185 int len;
186 struct rtattr *rta;
d63a9b2b
AB
187
188 if (!tb)
189 return;
190
191 if (!tb[IFLA_MACVLAN_MODE] ||
192 RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
193 return;
194
7dc0481a 195 mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
92b7454c
JF
196 print_string(PRINT_ANY,
197 "mode",
198 "mode %s ",
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"
204 : "unknown");
3cf8ba59
PS
205
206 if (!tb[IFLA_MACVLAN_FLAGS] ||
207 RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
aa1b44ca 208 flags = 0;
209 else
210 flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
3cf8ba59 211
3cf8ba59 212 if (flags & MACVLAN_FLAG_NOPROMISC)
92b7454c 213 print_bool(PRINT_ANY, "nopromisc", "nopromisc ", true);
aa1b44ca 214
215 /* in source mode, there are more options to print */
216
217 if (mode != MACVLAN_MODE_SOURCE)
218 return;
219
220 if (!tb[IFLA_MACVLAN_MACADDR_COUNT] ||
221 RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32))
222 return;
223
224 count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
92b7454c 225 print_int(PRINT_ANY, "macaddr_count", "remotes (%d) ", count);
aa1b44ca 226
227 if (!tb[IFLA_MACVLAN_MACADDR_DATA])
228 return;
229
230 rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]);
231 len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]);
232
92b7454c 233 open_json_array(PRINT_JSON, "macaddr_data");
aa1b44ca 234 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
235 if (rta->rta_type != IFLA_MACVLAN_MACADDR ||
236 RTA_PAYLOAD(rta) < 6)
237 continue;
238 addr = RTA_DATA(rta);
92b7454c
JF
239 if (is_json_context()) {
240 SPRINT_BUF(b1);
241
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);
246 } else {
247 fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
248 addr[1], addr[2], addr[3], addr[4], addr[5]);
249 }
aa1b44ca 250 }
92b7454c 251 close_json_array(PRINT_JSON, NULL);
d63a9b2b
AB
252}
253
561e650e 254static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
92b7454c 255 FILE *f)
561e650e 256{
541f1b3e 257 print_explain(lu, f);
561e650e 258}
259
d63a9b2b
AB
260struct link_util macvlan_link_util = {
261 .id = "macvlan",
262 .maxattr = IFLA_MACVLAN_MAX,
263 .parse_opt = macvlan_parse_opt,
264 .print_opt = macvlan_print_opt,
561e650e 265 .print_help = macvlan_print_help,
d63a9b2b 266};
541f1b3e
PS
267
268struct link_util macvtap_link_util = {
269 .id = "macvtap",
270 .maxattr = IFLA_MACVLAN_MAX,
271 .parse_opt = macvlan_parse_opt,
272 .print_opt = macvlan_print_opt,
273 .print_help = macvlan_print_help,
274};