• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/link/macvlan.c	MACVLAN Link Info
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2013 Michael Braun <michael-dev@fami-braun.de>
10  */
11 
12 /**
13  * @ingroup link
14  * @defgroup macvlan MACVLAN
15  * MAC-based Virtual LAN link module
16  *
17  * @details
18  * \b Link Type Name: "macvlan"
19  *
20  * @route_doc{link_macvlan, MACVLAN Documentation}
21  *
22  * @{
23  */
24 
25 #include <netlink-private/netlink.h>
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/route/rtnl.h>
31 #include <netlink-private/route/link/api.h>
32 #include <netlink/route/link/macvlan.h>
33 
34 #include <linux/if_link.h>
35 
36 /** @cond SKIP */
37 #define MACVLAN_HAS_MODE	(1<<0)
38 #define MACVLAN_HAS_FLAGS	(1<<1)
39 
40 struct macvlan_info
41 {
42 	uint32_t		mvi_mode;
43 	uint16_t		mvi_flags; // there currently is only one flag and kernel has no flags_mask yet
44 	uint32_t		mvi_mask;
45 };
46 
47 /** @endcond */
48 
49 static struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX+1] = {
50 	[IFLA_MACVLAN_MODE]	= { .type = NLA_U32 },
51 	[IFLA_MACVLAN_FLAGS]	= { .type = NLA_U16 },
52 };
53 
macvlan_alloc(struct rtnl_link * link)54 static int macvlan_alloc(struct rtnl_link *link)
55 {
56 	struct macvlan_info *mvi;
57 
58 	if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
59 		return -NLE_NOMEM;
60 
61 	link->l_info = mvi;
62 
63 	return 0;
64 }
65 
macvlan_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)66 static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
67                          struct nlattr *xstats)
68 {
69 	struct nlattr *tb[IFLA_MACVLAN_MAX+1];
70 	struct macvlan_info *mvi;
71 	int err;
72 
73 	NL_DBG(3, "Parsing MACVLAN link info");
74 
75 	if ((err = nla_parse_nested(tb, IFLA_MACVLAN_MAX, data, macvlan_policy)) < 0)
76 		goto errout;
77 
78 	if ((err = macvlan_alloc(link)) < 0)
79 		goto errout;
80 
81 	mvi = link->l_info;
82 
83 	if (tb[IFLA_MACVLAN_MODE]) {
84 		mvi->mvi_mode = nla_get_u32(tb[IFLA_MACVLAN_MODE]);
85 		mvi->mvi_mask |= MACVLAN_HAS_MODE;
86 	}
87 
88 	if (tb[IFLA_MACVLAN_FLAGS]) {
89 		mvi->mvi_mode = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
90 		mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
91 	}
92 
93 	err = 0;
94 errout:
95 	return err;
96 }
97 
macvlan_free(struct rtnl_link * link)98 static void macvlan_free(struct rtnl_link *link)
99 {
100 	free(link->l_info);
101 	link->l_info = NULL;
102 }
103 
macvlan_dump(struct rtnl_link * link,struct nl_dump_params * p)104 static void macvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
105 {
106 	char buf[64];
107 	struct macvlan_info *mvi = link->l_info;
108 
109 	if (mvi->mvi_mask & MACVLAN_HAS_MODE) {
110 		rtnl_link_macvlan_mode2str(mvi->mvi_mode, buf, sizeof(buf));
111 		nl_dump(p, "macvlan-mode %s", buf);
112 	}
113 
114 	if (mvi->mvi_mask & MACVLAN_HAS_FLAGS) {
115 		rtnl_link_macvlan_flags2str(mvi->mvi_flags, buf, sizeof(buf));
116 		nl_dump(p, "macvlan-flags %s", buf);
117 	}
118 }
119 
macvlan_clone(struct rtnl_link * dst,struct rtnl_link * src)120 static int macvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
121 {
122 	struct macvlan_info *vdst, *vsrc = src->l_info;
123 	int err;
124 
125 	dst->l_info = NULL;
126 	if ((err = rtnl_link_set_type(dst, "macvlan")) < 0)
127 		return err;
128 	vdst = dst->l_info;
129 
130 	if (!vdst || !vsrc)
131 		return -NLE_NOMEM;
132 
133 	memcpy(vdst, vsrc, sizeof(struct macvlan_info));
134 
135 	return 0;
136 }
137 
macvlan_put_attrs(struct nl_msg * msg,struct rtnl_link * link)138 static int macvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
139 {
140 	struct macvlan_info *mvi = link->l_info;
141 	struct nlattr *data;
142 
143 	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
144 		return -NLE_MSGSIZE;
145 
146 	if (mvi->mvi_mask & MACVLAN_HAS_MODE)
147 		NLA_PUT_U32(msg, IFLA_MACVLAN_MODE, mvi->mvi_mode);
148 
149 	if (mvi->mvi_mask & MACVLAN_HAS_FLAGS)
150 		NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, mvi->mvi_flags);
151 
152 	nla_nest_end(msg, data);
153 
154 nla_put_failure:
155 
156 	return 0;
157 }
158 
159 static struct rtnl_link_info_ops macvlan_info_ops = {
160 	.io_name		= "macvlan",
161 	.io_alloc		= macvlan_alloc,
162 	.io_parse		= macvlan_parse,
163 	.io_dump = {
164 	    [NL_DUMP_LINE]	= macvlan_dump,
165 	    [NL_DUMP_DETAILS]	= macvlan_dump,
166 	},
167 	.io_clone		= macvlan_clone,
168 	.io_put_attrs		= macvlan_put_attrs,
169 	.io_free		= macvlan_free,
170 };
171 
172 /** @cond SKIP */
173 #define IS_MACVLAN_LINK_ASSERT(link) \
174 	if ((link)->l_info_ops != &macvlan_info_ops) { \
175 		APPBUG("Link is not a macvlan link. set type \"macvlan\" first."); \
176 		return -NLE_OPNOTSUPP; \
177 	}
178 /** @endcond */
179 
180 /**
181  * @name MACVLAN Object
182  * @{
183  */
184 
185 /**
186  * Allocate link object of type MACVLAN
187  *
188  * @return Allocated link object or NULL.
189  */
rtnl_link_macvlan_alloc(void)190 struct rtnl_link *rtnl_link_macvlan_alloc(void)
191 {
192 	struct rtnl_link *link;
193 	int err;
194 
195 	if (!(link = rtnl_link_alloc()))
196 		return NULL;
197 
198 	if ((err = rtnl_link_set_type(link, "macvlan")) < 0) {
199 		rtnl_link_put(link);
200 		return NULL;
201 	}
202 
203 	return link;
204 }
205 
206 /**
207  * Check if link is a MACVLAN link
208  * @arg link		Link object
209  *
210  * @return True if link is a MACVLAN link, otherwise false is returned.
211  */
rtnl_link_is_macvlan(struct rtnl_link * link)212 int rtnl_link_is_macvlan(struct rtnl_link *link)
213 {
214 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvlan");
215 }
216 
217 /**
218  * Set MACVLAN MODE
219  * @arg link		Link object
220  * @arg mode		MACVLAN mode
221  *
222  * @return 0 on success or a negative error code
223  */
rtnl_link_macvlan_set_mode(struct rtnl_link * link,uint32_t mode)224 int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
225 {
226 	struct macvlan_info *mvi = link->l_info;
227 
228 	IS_MACVLAN_LINK_ASSERT(link);
229 
230 	mvi->mvi_mode = mode;
231 	mvi->mvi_mask |= MACVLAN_HAS_MODE;
232 
233 	return 0;
234 }
235 
236 /**
237  * Get MACVLAN Mode
238  * @arg link		Link object
239  *
240  * @return MACVLAN mode, 0 if not set or a negative error code.
241  */
rtnl_link_macvlan_get_mode(struct rtnl_link * link)242 uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
243 {
244 	struct macvlan_info *mvi = link->l_info;
245 
246 	IS_MACVLAN_LINK_ASSERT(link);
247 
248 	if (mvi->mvi_mask & MACVLAN_HAS_MODE)
249 		return mvi->mvi_mode;
250 	else
251 		return 0;
252 }
253 
254 /**
255  * Set MACVLAN flags
256  * @arg link		Link object
257  * @arg flags		MACVLAN flags
258  *
259  * @return 0 on success or a negative error code.
260  */
rtnl_link_macvlan_set_flags(struct rtnl_link * link,uint16_t flags)261 int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
262 {
263 	struct macvlan_info *mvi = link->l_info;
264 
265 	IS_MACVLAN_LINK_ASSERT(link);
266 
267 	mvi->mvi_flags |= flags;
268 	mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
269 
270 	return 0;
271 }
272 
273 /**
274  * Unset MACVLAN flags
275  * @arg link		Link object
276  * @arg flags		MACVLAN flags
277  *
278  * Note: kernel currently only has a single flag and lacks flags_mask to
279  * indicate which flags shall be changed (it always all).
280  *
281  * @return 0 on success or a negative error code.
282  */
rtnl_link_macvlan_unset_flags(struct rtnl_link * link,uint16_t flags)283 int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
284 {
285 	struct macvlan_info *mvi = link->l_info;
286 
287 	IS_MACVLAN_LINK_ASSERT(link);
288 
289 	mvi->mvi_flags &= ~flags;
290 	mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
291 
292 	return 0;
293 }
294 
295 /**
296  * Get MACVLAN flags
297  * @arg link		Link object
298  *
299  * @return MACVLAN flags, 0 if none set, or a negative error code.
300  */
rtnl_link_macvlan_get_flags(struct rtnl_link * link)301 uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *link)
302 {
303 	struct macvlan_info *mvi = link->l_info;
304 
305 	IS_MACVLAN_LINK_ASSERT(link);
306 
307 	return mvi->mvi_flags;
308 }
309 
310 /** @} */
311 
312 static const struct trans_tbl macvlan_flags[] = {
313 	__ADD(MACVLAN_FLAG_NOPROMISC, nopromisc)
314 };
315 
316 static const struct trans_tbl macvlan_modes[] = {
317 	__ADD(MACVLAN_MODE_PRIVATE, private)
318 	__ADD(MACVLAN_MODE_VEPA, vepa)
319 	__ADD(MACVLAN_MODE_BRIDGE, bridge)
320 	__ADD(MACVLAN_MODE_PASSTHRU, passthru)
321 };
322 
323 /**
324  * @name Flag Translation
325  * @{
326  */
327 
rtnl_link_macvlan_flags2str(int flags,char * buf,size_t len)328 char *rtnl_link_macvlan_flags2str(int flags, char *buf, size_t len)
329 {
330 	return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
331 }
332 
rtnl_link_macvlan_str2flags(const char * name)333 int rtnl_link_macvlan_str2flags(const char *name)
334 {
335 	return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
336 }
337 
338 /** @} */
339 
340 /**
341  * @name Mode Translation
342  * @{
343  */
344 
rtnl_link_macvlan_mode2str(int mode,char * buf,size_t len)345 char *rtnl_link_macvlan_mode2str(int mode, char *buf, size_t len)
346 {
347 	return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
348 }
349 
rtnl_link_macvlan_str2mode(const char * name)350 int rtnl_link_macvlan_str2mode(const char *name)
351 {
352 	return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
353 }
354 
355 /** @} */
356 
macvlan_init(void)357 static void __init macvlan_init(void)
358 {
359 	rtnl_link_register_info(&macvlan_info_ops);
360 }
361 
macvlan_exit(void)362 static void __exit macvlan_exit(void)
363 {
364 	rtnl_link_unregister_info(&macvlan_info_ops);
365 }
366 
367 /** @} */
368