[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