libnl  3.2.24-rc1
macvlan.c
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 
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 
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 
98 static void macvlan_free(struct rtnl_link *link)
99 {
100  free(link->l_info);
101  link->l_info = NULL;
102 }
103 
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 
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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 
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 
350 int rtnl_link_macvlan_str2mode(const char *name)
351 {
352  return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
353 }
354 
355 /** @} */
356 
357 static void __init macvlan_init(void)
358 {
359  rtnl_link_register_info(&macvlan_info_ops);
360 }
361 
362 static void __exit macvlan_exit(void)
363 {
364  rtnl_link_unregister_info(&macvlan_info_ops);
365 }
366 
367 /** @} */