Home | History | Annotate | Download | only in link
      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 (at) 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  */
    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  */
    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  */
    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  */
    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 
    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 /** @} */
    368