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
19#include "rt_names.h"
20#include "utils.h"
21#include "ip_common.h"
22
23#define pfx_err(lu, ...) {               \
24	fprintf(stderr, "%s: ", lu->id); \
25	fprintf(stderr, __VA_ARGS__);    \
26	fprintf(stderr, "\n");           \
27}
28
29static void print_explain(struct link_util *lu, FILE *f)
30{
31	fprintf(f,
32		"Usage: ... %s mode { private | vepa | bridge | passthru [nopromisc] }\n",
33		lu->id
34	);
35}
36
37static void explain(struct link_util *lu)
38{
39	print_explain(lu, stderr);
40}
41
42static int mode_arg(const char *arg)
43{
44        fprintf(stderr, "Error: argument of \"mode\" must be \"private\", "
45		"\"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", arg);
46        return -1;
47}
48
49static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
50			  struct nlmsghdr *n)
51{
52	__u32 mode = 0;
53	__u16 flags = 0;
54
55	while (argc > 0) {
56		if (matches(*argv, "mode") == 0) {
57			NEXT_ARG();
58
59			if (strcmp(*argv, "private") == 0)
60				mode = MACVLAN_MODE_PRIVATE;
61			else if (strcmp(*argv, "vepa") == 0)
62				mode = MACVLAN_MODE_VEPA;
63			else if (strcmp(*argv, "bridge") == 0)
64				mode = MACVLAN_MODE_BRIDGE;
65			else if (strcmp(*argv, "passthru") == 0)
66				mode = MACVLAN_MODE_PASSTHRU;
67			else
68				return mode_arg(*argv);
69		} else if (matches(*argv, "nopromisc") == 0) {
70			flags |= MACVLAN_FLAG_NOPROMISC;
71		} else if (matches(*argv, "help") == 0) {
72			explain(lu);
73			return -1;
74		} else {
75			pfx_err(lu, "unknown option \"%s\"?", *argv);
76			explain(lu);
77			return -1;
78		}
79		argc--, argv++;
80	}
81
82	if (mode)
83		addattr32(n, 1024, IFLA_MACVLAN_MODE, mode);
84
85	if (flags) {
86		if (flags & MACVLAN_FLAG_NOPROMISC &&
87		    mode != MACVLAN_MODE_PASSTHRU) {
88			pfx_err(lu, "nopromisc flag only valid in passthru mode");
89			explain(lu);
90			return -1;
91		}
92		addattr16(n, 1024, IFLA_MACVLAN_FLAGS, flags);
93	}
94	return 0;
95}
96
97static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
98{
99	__u32 mode;
100	__u16 flags;
101
102	if (!tb)
103		return;
104
105	if (!tb[IFLA_MACVLAN_MODE] ||
106	    RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
107		return;
108
109	mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
110	fprintf(f, " mode %s ",
111		  mode == MACVLAN_MODE_PRIVATE ? "private"
112		: mode == MACVLAN_MODE_VEPA    ? "vepa"
113		: mode == MACVLAN_MODE_BRIDGE  ? "bridge"
114		: mode == MACVLAN_MODE_PASSTHRU  ? "passthru"
115		:				 "unknown");
116
117	if (!tb[IFLA_MACVLAN_FLAGS] ||
118	    RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
119		return;
120
121	flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
122	if (flags & MACVLAN_FLAG_NOPROMISC)
123		fprintf(f, "nopromisc ");
124}
125
126static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
127	FILE *f)
128{
129	print_explain(lu, f);
130}
131
132struct link_util macvlan_link_util = {
133	.id		= "macvlan",
134	.maxattr	= IFLA_MACVLAN_MAX,
135	.parse_opt	= macvlan_parse_opt,
136	.print_opt	= macvlan_print_opt,
137	.print_help	= macvlan_print_help,
138};
139
140struct link_util macvtap_link_util = {
141	.id		= "macvtap",
142	.maxattr	= IFLA_MACVLAN_MAX,
143	.parse_opt	= macvlan_parse_opt,
144	.print_opt	= macvlan_print_opt,
145	.print_help	= macvlan_print_help,
146};
147