blob: 2adfc098d571a885131c4134a0e5c46986957898 [file] [log] [blame]
Arnd Bergmannd63a9b22009-12-26 11:22:57 -08001/*
Phil Sutter541f1b32015-09-25 14:09:49 +02002 * iplink_macvlan.c macvlan/macvtap device support
Arnd Bergmannd63a9b22009-12-26 11:22:57 -08003 *
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>
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +020018#include <linux/if_ether.h>
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080019
20#include "rt_names.h"
21#include "utils.h"
22#include "ip_common.h"
23
Phil Sutter541f1b32015-09-25 14:09:49 +020024#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)
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080031{
vadimk561e6502014-09-30 08:17:31 +030032 fprintf(f,
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +020033 "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\n"
34 "MODE: private | vepa | bridge | passthru | source\n"
35 "MODE_FLAG: null | nopromisc | unicast | unicast_all\n"
36 "MODE_OPTS: for mode \"source\":\n"
37 "\tmacaddr { add <macaddr> | del <macaddr> | flush }\n",
Phil Sutter541f1b32015-09-25 14:09:49 +020038 lu->id
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080039 );
40}
41
Phil Sutter541f1b32015-09-25 14:09:49 +020042static void explain(struct link_util *lu)
vadimk561e6502014-09-30 08:17:31 +030043{
Phil Sutter541f1b32015-09-25 14:09:49 +020044 print_explain(lu, stderr);
vadimk561e6502014-09-30 08:17:31 +030045}
46
Phil Sutter541f1b32015-09-25 14:09:49 +020047static int mode_arg(const char *arg)
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080048{
Stephen Hemminger74093342016-10-12 15:23:27 -070049 fprintf(stderr,
50 "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n",
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +020051 arg);
52 return -1;
53}
54
55static int flag_arg(const char *arg)
56{
Stephen Hemminger74093342016-10-12 15:23:27 -070057 fprintf(stderr,
58 "Error: argument of \"flag\" must be \"nopromisc\", \"unicast\", \"unicast_all\" or \"null\", not \"%s\"\n",
Stephen Hemminger56f5daa2016-03-21 11:52:19 -070059 arg);
60 return -1;
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080061}
62
63static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
64 struct nlmsghdr *n)
65{
Phil Sutter3cf8ba52015-09-25 14:09:50 +020066 __u32 mode = 0;
67 __u16 flags = 0;
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +020068 __u32 mac_mode = 0;
69 int len = 0;
70 char abuf[32];
Phil Sutter3cf8ba52015-09-25 14:09:50 +020071
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080072 while (argc > 0) {
73 if (matches(*argv, "mode") == 0) {
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080074 NEXT_ARG();
75
76 if (strcmp(*argv, "private") == 0)
77 mode = MACVLAN_MODE_PRIVATE;
78 else if (strcmp(*argv, "vepa") == 0)
79 mode = MACVLAN_MODE_VEPA;
80 else if (strcmp(*argv, "bridge") == 0)
81 mode = MACVLAN_MODE_BRIDGE;
Sridhar Samudralaf0612d52011-03-16 17:01:58 -070082 else if (strcmp(*argv, "passthru") == 0)
83 mode = MACVLAN_MODE_PASSTHRU;
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +020084 else if (strcmp(*argv, "source") == 0)
85 mode = MACVLAN_MODE_SOURCE;
Arnd Bergmannd63a9b22009-12-26 11:22:57 -080086 else
Phil Sutter541f1b32015-09-25 14:09:49 +020087 return mode_arg(*argv);
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +020088 } else if (matches(*argv, "flag") == 0) {
89 NEXT_ARG();
90
91 if (strcmp(*argv, "nopromisc") == 0)
92 flags |= MACVLAN_FLAG_NOPROMISC;
93 else if (strcmp(*argv, "unicast") == 0)
94 flags |= MACVLAN_FLAG_UNICAST;
95 else if (strcmp(*argv, "unicast_all") == 0)
96 flags |= MACVLAN_FLAG_UNICAST_ALL;
97 else if (strcmp(*argv, "null") == 0)
98 flags |= 0;
99 else
100 return flag_arg(*argv);
101
102 } else if (matches(*argv, "macaddr") == 0) {
103 NEXT_ARG();
104
105 if (strcmp(*argv, "add") == 0) {
106 mac_mode = MACVLAN_MACADDR_ADD;
107 } else if (strcmp(*argv, "del") == 0) {
108 mac_mode = MACVLAN_MACADDR_DEL;
109 } else if (strcmp(*argv, "flush") == 0) {
110 mac_mode = MACVLAN_MACADDR_FLUSH;
111 } else {
112 explain(lu);
113 return -1;
114 }
115
116 if (mac_mode != MACVLAN_MACADDR_FLUSH) {
117 NEXT_ARG();
118
119 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
120 if (len < 0)
121 return -1;
122 }
Phil Sutter3cf8ba52015-09-25 14:09:50 +0200123 } else if (matches(*argv, "nopromisc") == 0) {
124 flags |= MACVLAN_FLAG_NOPROMISC;
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800125 } else if (matches(*argv, "help") == 0) {
Phil Sutter541f1b32015-09-25 14:09:49 +0200126 explain(lu);
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800127 return -1;
128 } else {
Phil Sutter541f1b32015-09-25 14:09:49 +0200129 pfx_err(lu, "unknown option \"%s\"?", *argv);
130 explain(lu);
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800131 return -1;
132 }
133 argc--, argv++;
134 }
135
Phil Sutter3cf8ba52015-09-25 14:09:50 +0200136 if (mode)
137 addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
138
139 if (flags) {
140 if (flags & MACVLAN_FLAG_NOPROMISC &&
141 mode != MACVLAN_MODE_PASSTHRU) {
142 pfx_err(lu, "nopromisc flag only valid in passthru mode");
143 explain(lu);
144 return -1;
145 }
146 addattr16(n, 1024, IFLA_MACVLAN_FLAGS, flags);
147 }
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +0200148
149 if (mac_mode) {
150 addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode);
151 if (mac_mode != MACVLAN_MACADDR_FLUSH && len > 0)
152 addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, abuf, len);
153 }
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800154 return 0;
155}
156
157static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
158{
159 __u32 mode;
Phil Sutter3cf8ba52015-09-25 14:09:50 +0200160 __u16 flags;
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +0200161 __u32 count;
162 unsigned char *addr;
163 int len;
164 struct rtattr *rta;
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800165
166 if (!tb)
167 return;
168
169 if (!tb[IFLA_MACVLAN_MODE] ||
170 RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
171 return;
172
Lutz Jaenicke7dc04812013-08-29 09:50:28 +0200173 mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800174 fprintf(f, " mode %s ",
175 mode == MACVLAN_MODE_PRIVATE ? "private"
176 : mode == MACVLAN_MODE_VEPA ? "vepa"
177 : mode == MACVLAN_MODE_BRIDGE ? "bridge"
Sridhar Samudralaf0612d52011-03-16 17:01:58 -0700178 : mode == MACVLAN_MODE_PASSTHRU ? "passthru"
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +0200179 : mode == MACVLAN_MODE_SOURCE ? "source"
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800180 : "unknown");
Phil Sutter3cf8ba52015-09-25 14:09:50 +0200181
182 if (!tb[IFLA_MACVLAN_FLAGS] ||
183 RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +0200184 flags = 0;
185 else
186 flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
Phil Sutter3cf8ba52015-09-25 14:09:50 +0200187
Phil Sutter3cf8ba52015-09-25 14:09:50 +0200188 if (flags & MACVLAN_FLAG_NOPROMISC)
189 fprintf(f, "nopromisc ");
michael-dev@fami-braun.def33b7272016-09-25 21:08:55 +0200190 if (flags & MACVLAN_FLAG_UNICAST)
191 fprintf(f, "flag unicast ");
192 if (flags & MACVLAN_FLAG_UNICAST_ALL)
193 fprintf(f, "flag unicast_all ");
194
195 /* in source mode, there are more options to print */
196
197 if (mode != MACVLAN_MODE_SOURCE)
198 return;
199
200 if (!tb[IFLA_MACVLAN_MACADDR_COUNT] ||
201 RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32))
202 return;
203
204 count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
205 fprintf(f, " remotes (%d)", count);
206
207 if (!tb[IFLA_MACVLAN_MACADDR_DATA])
208 return;
209
210 rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]);
211 len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]);
212
213 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
214 if (rta->rta_type != IFLA_MACVLAN_MACADDR ||
215 RTA_PAYLOAD(rta) < 6)
216 continue;
217 addr = RTA_DATA(rta);
218 fprintf(f, " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0],
219 addr[1], addr[2], addr[3], addr[4], addr[5]);
220 }
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800221}
222
vadimk561e6502014-09-30 08:17:31 +0300223static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
224 FILE *f)
225{
Phil Sutter541f1b32015-09-25 14:09:49 +0200226 print_explain(lu, f);
vadimk561e6502014-09-30 08:17:31 +0300227}
228
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800229struct link_util macvlan_link_util = {
230 .id = "macvlan",
231 .maxattr = IFLA_MACVLAN_MAX,
232 .parse_opt = macvlan_parse_opt,
233 .print_opt = macvlan_print_opt,
vadimk561e6502014-09-30 08:17:31 +0300234 .print_help = macvlan_print_help,
Arnd Bergmannd63a9b22009-12-26 11:22:57 -0800235};
Phil Sutter541f1b32015-09-25 14:09:49 +0200236
237struct link_util macvtap_link_util = {
238 .id = "macvtap",
239 .maxattr = IFLA_MACVLAN_MAX,
240 .parse_opt = macvlan_parse_opt,
241 .print_opt = macvlan_print_opt,
242 .print_help = macvlan_print_help,
243};