[PATCH 1/2] Add ipvlan support

Thomas Haller thaller at redhat.com
Fri Jun 19 09:14:50 PDT 2015


On Tue, 2015-06-09 at 21:53 -0700, Cong Wang wrote:
> Signed-off-by: Cong Wang <xiyou.wangcong at gmail.com>
> ---
>  include/Makefile.am                   |   1 +
>  include/linux-private/linux/if_link.h |  15 ++
>  include/netlink/route/link/ipvlan.h   |  37 +++++
>  lib/Makefile.am                       |   2 +-
>  lib/route/link/ipvlan.c               | 279 
> ++++++++++++++++++++++++++++++++++
>  libnl-route-3.sym                     |  10 ++
>  6 files changed, 343 insertions(+), 1 deletion(-)
>  create mode 100644 include/netlink/route/link/ipvlan.h
>  create mode 100644 lib/route/link/ipvlan.c
> 
> diff --git a/include/Makefile.am b/include/Makefile.am
> index bf86ed1..ffaa9a5 100644
> --- a/include/Makefile.am
> +++ b/include/Makefile.am
> @@ -60,6 +60,7 @@ nobase_libnlinclude_HEADERS = \
>  	netlink/route/link/ipip.h \
>  	netlink/route/link/ipvti.h \
>  	netlink/route/link/sit.h \
> +	netlink/route/link/ipvlan.h \
>  	netlink/route/qdisc/cbq.h \
>  	netlink/route/qdisc/dsmark.h \
>  	netlink/route/qdisc/fifo.h \
> diff --git a/include/linux-private/linux/if_link.h b/include/linux
> -private/linux/if_link.h
> index ff95760..69e30d0 100644
> --- a/include/linux-private/linux/if_link.h
> +++ b/include/linux-private/linux/if_link.h
> @@ -305,6 +305,21 @@ enum macvlan_mode {
>  
>  #define MACVLAN_FLAG_NOPROMISC	1
>  
> +/* IPVLAN section */
> +enum {
> +	IFLA_IPVLAN_UNSPEC,
> +	IFLA_IPVLAN_MODE,
> +	__IFLA_IPVLAN_MAX
> +};
> +
> +#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
> +
> +enum ipvlan_mode {
> +	IPVLAN_MODE_L2 = 0,
> +	IPVLAN_MODE_L3,
> +	IPVLAN_MODE_MAX
> +};
> +
>  /* VXLAN section */
>  enum {
>  	IFLA_VXLAN_UNSPEC,
> diff --git a/include/netlink/route/link/ipvlan.h 
> b/include/netlink/route/link/ipvlan.h
> new file mode 100644
> index 0000000..21cce85
> --- /dev/null
> +++ b/include/netlink/route/link/ipvlan.h
> @@ -0,0 +1,37 @@
> +/*
> + * netlink/route/link/ipvlan.h		IPVLAN interface
> + *
> + *	This library is free software; you can redistribute it 
> and/or
> + *	modify it under the terms of the GNU Lesser General Public
> + *	License as published by the Free Software Foundation version 
> 2.1
> + *	of the License.
> + *
> + * Copyright (c) 2015 Cong Wang <cwang at twopensource.com>
> + */
> +
> +#ifndef NETLINK_LINK_IPVLAN_H_
> +#define NETLINK_LINK_IPVLAN_H_
> +
> +#include <netlink/netlink.h>
> +#include <netlink/route/link.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +extern struct rtnl_link *rtnl_link_ipvlan_alloc(void);
> +
> +extern int		rtnl_link_is_ipvlan(struct rtnl_link *);
> +
> +extern char *		rtnl_link_ipvlan_mode2str(int, char *, 
> size_t);
> +extern int		rtnl_link_ipvlan_str2mode(const char *);
> +
> +extern int		rtnl_link_ipvlan_set_mode(struct rtnl_link 
> *,
> +			                           uint16_t);
> +extern uint16_t		rtnl_link_ipvlan_get_mode(struct 
> rtnl_link *);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 92f812c..1474c8d 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -110,7 +110,7 @@ libnl_route_3_la_SOURCES = \
>  	route/link/bonding.c route/link/can.c route/link/macvlan.c \
>  	route/link/vxlan.c route/link/veth.c route/link/ipip.c \
>  	route/link/ipgre.c route/link/sit.c route/link/ipvti.c \
> -	route/link/ip6tnl.c route/link/ifb.c \
> +	route/link/ip6tnl.c route/link/ifb.c route/link/ipvlan.c \
>  	\
>  	route/qdisc/blackhole.c route/qdisc/cbq.c 
> route/qdisc/dsmark.c \
>  	route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \
> diff --git a/lib/route/link/ipvlan.c b/lib/route/link/ipvlan.c
> new file mode 100644
> index 0000000..2ad56f8
> --- /dev/null
> +++ b/lib/route/link/ipvlan.c
> @@ -0,0 +1,279 @@
> +/*
> + * lib/route/link/ipvlan.c	IPVLAN Link Info
> + *
> + *	This library is free software; you can redistribute it 
> and/or
> + *	modify it under the terms of the GNU Lesser General Public
> + *	License as published by the Free Software Foundation version 
> 2.1
> + *	of the License.
> + *
> + * Copyright (c) 2015 Cong Wang <cwang at twopensource.com>
> + */
> +
> +/**
> + * @ingroup link
> + * @defgroup ipvlan IPVLAN
> + * IP-based Virtual LAN link module
> + *
> + * @details
> + * \b Link Type Name: "ipvlan"
> + *
> + * @route_doc{link_ipvlan, IPVLAN Documentation}
> + *
> + * @{
> + */
> +
> +#include <netlink-private/netlink.h>
> +#include <netlink/netlink.h>
> +#include <netlink/attr.h>
> +#include <netlink/utils.h>
> +#include <netlink/object.h>
> +#include <netlink/route/rtnl.h>
> +#include <netlink-private/route/link/api.h>
> +#include <netlink/route/link/ipvlan.h>
> +
> +#include <linux/if_link.h>
> +
> +/** @cond SKIP */
> +#define IPVLAN_HAS_MODE	(1<<0)
> +
> +struct ipvlan_info
> +{
> +	uint16_t		ipi_mode;
> +	uint32_t		ipi_mask;
> +};
> +
> +/** @endcond */
> +
> +static struct nla_policy ipvlan_policy[IFLA_IPVLAN_MAX+1] = {
> +	[IFLA_IPVLAN_MODE]	= { .type = NLA_U16 },
> +};
> +
> +static int ipvlan_alloc(struct rtnl_link *link)
> +{
> +	struct ipvlan_info *ipi;
> +
> +	if (link->l_info)
> +		memset(link->l_info, 0, sizeof(*ipi));
> +	else {
> +		if ((ipi = calloc(1, sizeof(*ipi))) == NULL)
> +			return -NLE_NOMEM;
> +
> +		link->l_info = ipi;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipvlan_parse(struct rtnl_link *link, struct nlattr *data,
> +                         struct nlattr *xstats)
> +{
> +	struct nlattr *tb[IFLA_IPVLAN_MAX+1];
> +	struct ipvlan_info *ipi;
> +	int err;
> +
> +	NL_DBG(3, "Parsing IPVLAN link info");
> +
> +	if ((err = nla_parse_nested(tb, IFLA_IPVLAN_MAX, data, 
> ipvlan_policy)) < 0)
> +		goto errout;
> +
> +	if ((err = ipvlan_alloc(link)) < 0)
> +		goto errout;
> +
> +	ipi = link->l_info;
> +
> +	if (tb[IFLA_IPVLAN_MODE]) {
> +		ipi->ipi_mode = nla_get_u16(tb[IFLA_IPVLAN_MODE]);
> +		ipi->ipi_mask |= IPVLAN_HAS_MODE;
> +	}
> +
> +	err = 0;
> +errout:
> +	return err;
> +}
> +
> +static void ipvlan_free(struct rtnl_link *link)
> +{
> +	free(link->l_info);
> +	link->l_info = NULL;
> +}
> +
> +static void ipvlan_dump(struct rtnl_link *link, struct 
> nl_dump_params *p)
> +{
> +	char buf[64];
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	if (ipi->ipi_mask & IPVLAN_HAS_MODE) {
> +		rtnl_link_ipvlan_mode2str(ipi->ipi_mode, buf, 
> sizeof(buf));
> +		nl_dump(p, "ipvlan-mode %s", buf);
> +	}
> +}
> +
> +static int ipvlan_clone(struct rtnl_link *dst, struct rtnl_link 
> *src)
> +{
> +	struct ipvlan_info *vdst, *vsrc = src->l_info;
> +	int err;
> +
> +	dst->l_info = NULL;
> +	if ((err = rtnl_link_set_type(dst, "ipvlan")) < 0)
> +		return err;
> +	vdst = dst->l_info;
> +
> +	if (!vdst || !vsrc)
> +		return -NLE_NOMEM;
> +
> +	memcpy(vdst, vsrc, sizeof(struct ipvlan_info));
> +
> +	return 0;
> +}
> +
> +static int ipvlan_put_attrs(struct nl_msg *msg, struct rtnl_link 
> *link)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +	struct nlattr *data;
> +
> +	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
> +		return -NLE_MSGSIZE;
> +
> +	if (ipi->ipi_mask & IPVLAN_HAS_MODE)
> +		NLA_PUT_U16(msg, IFLA_IPVLAN_MODE, ipi->ipi_mode);
> +
> +	nla_nest_end(msg, data);
> +
> +nla_put_failure:
> +
> +	return 0;
> +}
> +
> +static struct rtnl_link_info_ops ipvlan_info_ops = {
> +	.io_name		= "ipvlan",
> +	.io_alloc		= ipvlan_alloc,
> +	.io_parse		= ipvlan_parse,
> +	.io_dump = {
> +	    [NL_DUMP_LINE]	= ipvlan_dump,
> +	    [NL_DUMP_DETAILS]	= ipvlan_dump,
> +	},
> +	.io_clone		= ipvlan_clone,
> +	.io_put_attrs		= ipvlan_put_attrs,
> +	.io_free		= ipvlan_free,
> +};
> +
> +/** @cond SKIP */
> +#define IS_IPVLAN_LINK_ASSERT(link) \
> +	if ((link)->l_info_ops != &ipvlan_info_ops) { \
> +		APPBUG("Link is not a ipvlan link. set type 
> \"ipvlan\" first."); \
> +		return -NLE_OPNOTSUPP; \
> +	}
> +/** @endcond */
> +
> +/**
> + * @name IPVLAN Object
> + * @{
> + */
> +
> +/**
> + * Allocate link object of type IPVLAN
> + *
> + * @return Allocated link object or NULL.
> + */
> +struct rtnl_link *rtnl_link_ipvlan_alloc(void)
> +{
> +	struct rtnl_link *link;
> +	int err;
> +
> +	if (!(link = rtnl_link_alloc()))
> +		return NULL;
> +
> +	if ((err = rtnl_link_set_type(link, "ipvlan")) < 0) {
> +		rtnl_link_put(link);
> +		return NULL;
> +	}
> +
> +	return link;
> +}
> +
> +/**
> + * Check if link is a IPVLAN link
> + * @arg link		Link object
> + *
> + * @return True if link is a IPVLAN link, otherwise false is 
> returned.
> + */
> +int rtnl_link_is_ipvlan(struct rtnl_link *link)
> +{
> +	return link->l_info_ops && !strcmp(link->l_info_ops
> ->io_name, "ipvlan");
> +}
> +
> +/**
> + * Set IPVLAN MODE
> + * @arg link		Link object
> + * @arg mode		IPVLAN mode
> + *
> + * @return 0 on success or a negative error code
> + */
> +int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t mode)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	IS_IPVLAN_LINK_ASSERT(link);
> +
> +	if (mode != IPVLAN_MODE_L2 && mode != IPVLAN_MODE_L3)
> +		return -NLE_INVAL;
> +
> +	ipi->ipi_mode = mode;
> +	ipi->ipi_mask |= IPVLAN_HAS_MODE;
> +
> +	return 0;
> +}
> +
> +/**
> + * Get IPVLAN Mode
> + * @arg link		Link object
> + *
> + * @return IPVLAN mode, 0 if not set or a negative error code.
> + */
> +uint16_t rtnl_link_ipvlan_get_mode(struct rtnl_link *link)
> +{
> +	struct ipvlan_info *ipi = link->l_info;
> +
> +	IS_IPVLAN_LINK_ASSERT(link);
> +
> +	if (ipi->ipi_mask & IPVLAN_HAS_MODE)
> +		return ipi->ipi_mode;
> +	else
> +		return 0;
> +}
> +
> +/** @} */
> +
> +static const struct trans_tbl ipvlan_modes[] = {
> +	__ADD(IPVLAN_MODE_L2, l2),
> +	__ADD(IPVLAN_MODE_L3, l3),
> +};
> +
> +/**
> + * @name Mode Translation
> + * @{
> + */
> +
> +char *rtnl_link_ipvlan_mode2str(int mode, char *buf, size_t len)
> +{
> +	return __type2str(mode, buf, len, ipvlan_modes, 
> ARRAY_SIZE(ipvlan_modes));
> +}
> +
> +int rtnl_link_ipvlan_str2mode(const char *name)
> +{
> +	return __str2type(name, ipvlan_modes, 
> ARRAY_SIZE(ipvlan_modes));
> +}
> +
> +/** @} */
> +
> +static void __init ipvlan_init(void)
> +{
> +	rtnl_link_register_info(&ipvlan_info_ops);
> +}
> +
> +static void __exit ipvlan_exit(void)
> +{
> +	rtnl_link_unregister_info(&ipvlan_info_ops);
> +}
> +
> +/** @} */
> diff --git a/libnl-route-3.sym b/libnl-route-3.sym
> index ad2ed36..f55a162 100644
> --- a/libnl-route-3.sym
> +++ b/libnl-route-3.sym
> @@ -872,3 +872,13 @@ global:
>  	rtnl_tc_str2stat;
>  	rtnl_u32_get_classid;
>  } libnl_3;
> +
> +libnl_3_2_27 {
> +global:
> +	rtnl_link_ipvlan_alloc;
> +	rtnl_link_is_ipvlan;
> +	rtnl_link_ipvlan_mode2str;
> +	rtnl_link_ipvlan_str2mode;
> +	rtnl_link_ipvlan_set_mode;
> +	rtnl_link_ipvlan_get_mode;
> +} libnl_3_2_26;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/libnl/attachments/20150619/1b1c4320/attachment.sig>


More information about the libnl mailing list