Home | History | Annotate | Download | only in link
      1 /*
      2  * lib/route/link/veth.c	Virtual Ethernet
      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 Cong Wang <xiyou.wangcong (at) gmail.com>
     10  */
     11 
     12 /**
     13  * @ingroup link
     14  * @defgroup veth VETH
     15  * Virtual Ethernet
     16  *
     17  * @details
     18  * \b Link Type Name: "veth"
     19  *
     20  * @route_doc{link_veth, VETH 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/veth.h>
     33 
     34 #include <linux/if_link.h>
     35 
     36 static struct nla_policy veth_policy[VETH_INFO_MAX+1] = {
     37 	[VETH_INFO_PEER]	= { .minlen = sizeof(struct ifinfomsg) },
     38 };
     39 
     40 static int veth_parse(struct rtnl_link *link, struct nlattr *data,
     41 		      struct nlattr *xstats)
     42 {
     43 	struct nlattr *tb[VETH_INFO_MAX+1];
     44 	struct nlattr *peer_tb[IFLA_MAX + 1];
     45 	struct rtnl_link *peer = link->l_info;
     46 	int err;
     47 
     48 	NL_DBG(3, "Parsing veth link info");
     49 
     50 	if ((err = nla_parse_nested(tb, VETH_INFO_MAX, data, veth_policy)) < 0)
     51 		goto errout;
     52 
     53 	if (tb[VETH_INFO_PEER]) {
     54 		struct nlattr *nla_peer;
     55 		struct ifinfomsg *ifi;
     56 
     57 		nla_peer = tb[VETH_INFO_PEER];
     58 		ifi = nla_data(nla_peer);
     59 
     60 		peer->l_family = ifi->ifi_family;
     61 		peer->l_arptype = ifi->ifi_type;
     62 		peer->l_index = ifi->ifi_index;
     63 		peer->l_flags = ifi->ifi_flags;
     64 		peer->l_change = ifi->ifi_change;
     65 		err = nla_parse(peer_tb, IFLA_MAX,
     66 				nla_data(nla_peer) + sizeof(struct ifinfomsg),
     67 				nla_len(nla_peer) - sizeof(struct ifinfomsg),
     68 				rtln_link_policy);
     69 		if (err < 0)
     70 			goto errout;
     71 
     72 		err = rtnl_link_info_parse(peer, peer_tb);
     73 		if (err < 0)
     74 			goto errout;
     75 	}
     76 
     77 	err = 0;
     78 
     79 errout:
     80 	return err;
     81 }
     82 
     83 static void veth_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
     84 {
     85 }
     86 
     87 static void veth_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
     88 {
     89 	struct rtnl_link *peer = link->l_info;
     90 	char *name;
     91 	name = rtnl_link_get_name(peer);
     92 	nl_dump(p, "      peer ");
     93 	if (name)
     94 		nl_dump_line(p, "%s\n", name);
     95 	else
     96 		nl_dump_line(p, "%u\n", peer->l_index);
     97 }
     98 
     99 static int veth_clone(struct rtnl_link *dst, struct rtnl_link *src)
    100 {
    101 	struct rtnl_link *dst_peer = NULL, *src_peer = src->l_info;
    102 
    103 	/* we are calling nl_object_clone() recursively, this should
    104 	 * happen only once */
    105 	if (src_peer) {
    106 		src_peer->l_info = NULL;
    107 		dst_peer = (struct rtnl_link *)nl_object_clone(OBJ_CAST(src_peer));
    108 		if (!dst_peer)
    109 			return -NLE_NOMEM;
    110 		src_peer->l_info = src;
    111 		dst_peer->l_info = dst;
    112 	}
    113 	dst->l_info = dst_peer;
    114 	return 0;
    115 }
    116 
    117 static int veth_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
    118 {
    119 	struct rtnl_link *peer = link->l_info;
    120 	struct ifinfomsg ifi;
    121 	struct nlattr *data, *info_peer;
    122 
    123 	memset(&ifi, 0, sizeof ifi);
    124 	ifi.ifi_family = peer->l_family;
    125 	ifi.ifi_type = peer->l_arptype;
    126 	ifi.ifi_index = peer->l_index;
    127 	ifi.ifi_flags = peer->l_flags;
    128 	ifi.ifi_change = peer->l_change;
    129 
    130 	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
    131 		return -NLE_MSGSIZE;
    132 	if (!(info_peer = nla_nest_start(msg, VETH_INFO_PEER)))
    133 		return -NLE_MSGSIZE;
    134 	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
    135 		return -NLE_MSGSIZE;
    136 	rtnl_link_fill_info(msg, peer);
    137 	nla_nest_end(msg, info_peer);
    138 	nla_nest_end(msg, data);
    139 
    140 	return 0;
    141 }
    142 
    143 static int veth_alloc(struct rtnl_link *link)
    144 {
    145 	struct rtnl_link *peer;
    146 	int err;
    147 
    148 	/* return early if we are in recursion */
    149 	if (link->l_info)
    150 		return 0;
    151 
    152 	if (!(peer = rtnl_link_alloc()))
    153 		return -NLE_NOMEM;
    154 
    155 	/* We don't need to hold a reference here, as link and
    156 	 * its peer should always be freed together.
    157 	 */
    158 	peer->l_info = link;
    159 	if ((err = rtnl_link_set_type(peer, "veth")) < 0) {
    160 		rtnl_link_put(peer);
    161 		return err;
    162 	}
    163 
    164 	link->l_info = peer;
    165 	return 0;
    166 }
    167 
    168 static void veth_free(struct rtnl_link *link)
    169 {
    170 	struct rtnl_link *peer = link->l_info;
    171 	if (peer) {
    172 		link->l_info = NULL;
    173 		/* avoid calling this recursively */
    174 		peer->l_info = NULL;
    175 		rtnl_link_put(peer);
    176 	}
    177 	/* the caller should finally free link */
    178 }
    179 
    180 static struct rtnl_link_info_ops veth_info_ops = {
    181 	.io_name		= "veth",
    182 	.io_parse		= veth_parse,
    183 	.io_dump = {
    184 	    [NL_DUMP_LINE]	= veth_dump_line,
    185 	    [NL_DUMP_DETAILS]	= veth_dump_details,
    186 	},
    187 	.io_alloc		= veth_alloc,
    188 	.io_clone		= veth_clone,
    189 	.io_put_attrs		= veth_put_attrs,
    190 	.io_free		= veth_free,
    191 };
    192 
    193 /** @cond SKIP */
    194 
    195 #define IS_VETH_LINK_ASSERT(link) \
    196 	if ((link)->l_info_ops != &veth_info_ops) { \
    197 		APPBUG("Link is not a veth link. set type \"veth\" first."); \
    198 		return NULL; \
    199 	}
    200 /** @endcond */
    201 
    202 /**
    203  * @name VETH Object
    204  * @{
    205  */
    206 
    207 /**
    208  * Allocate link object of type veth
    209  *
    210  * @return Allocated link object or NULL.
    211  */
    212 struct rtnl_link *rtnl_link_veth_alloc(void)
    213 {
    214 	struct rtnl_link *link;
    215 	int err;
    216 
    217 	if (!(link = rtnl_link_alloc()))
    218 		return NULL;
    219 	if ((err = rtnl_link_set_type(link, "veth")) < 0) {
    220 		rtnl_link_put(link);
    221 		return NULL;
    222 	}
    223 
    224 	return link;
    225 }
    226 
    227 /**
    228  * Get the peer link of a veth link
    229  *
    230  * @return the peer link object.
    231  */
    232 struct rtnl_link *rtnl_link_veth_get_peer(struct rtnl_link *link)
    233 {
    234 	IS_VETH_LINK_ASSERT(link);
    235 	nl_object_get(OBJ_CAST(link->l_info));
    236 	return link->l_info;
    237 }
    238 
    239 /**
    240  * Release a veth link and its peer
    241  *
    242  */
    243 void rtnl_link_veth_release(struct rtnl_link *link)
    244 {
    245 	veth_free(link);
    246 	rtnl_link_put(link);
    247 }
    248 
    249 /**
    250  * Check if link is a veth link
    251  * @arg link		Link object
    252  *
    253  * @return True if link is a veth link, otherwise false is returned.
    254  */
    255 int rtnl_link_is_veth(struct rtnl_link *link)
    256 {
    257 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "veth");
    258 }
    259 
    260 /**
    261  * Create a new kernel veth device
    262  * @arg sock		netlink socket
    263  * @arg name		name of the veth device or NULL
    264  * @arg peer_name	name of its peer or NULL
    265  * @arg pid		pid of the process in the new netns
    266  *
    267  * Creates a new veth device pair in the kernel and move the peer
    268  * to the network namespace where the process is. If no name is
    269  * provided, the kernel will automatically pick a name of the
    270  * form "veth%d" (e.g. veth0, veth1, etc.)
    271  *
    272  * @return 0 on success or a negative error code
    273  */
    274 int rtnl_link_veth_add(struct nl_sock *sock, const char *name,
    275                        const char *peer_name, pid_t pid)
    276 {
    277 	struct rtnl_link *link, *peer;
    278 	int err = -NLE_NOMEM;
    279 
    280 	if (!(link = rtnl_link_veth_alloc()))
    281 		return -NLE_NOMEM;
    282 	peer = link->l_info;
    283 
    284 	if (name && peer_name) {
    285 		rtnl_link_set_name(link, name);
    286 		rtnl_link_set_name(peer, peer_name);
    287 	}
    288 
    289 	rtnl_link_set_ns_pid(peer, pid);
    290 	err = rtnl_link_add(sock, link, NLM_F_CREATE | NLM_F_EXCL);
    291 
    292 	rtnl_link_put(link);
    293 	return err;
    294 }
    295 
    296 /** @} */
    297 
    298 static void __init veth_init(void)
    299 {
    300 	rtnl_link_register_info(&veth_info_ops);
    301 }
    302 
    303 static void __exit veth_exit(void)
    304 {
    305 	rtnl_link_unregister_info(&veth_info_ops);
    306 }
    307 
    308 /** @} */
    309