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@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 36static struct nla_policy veth_policy[VETH_INFO_MAX+1] = { 37 [VETH_INFO_PEER] = { .minlen = sizeof(struct ifinfomsg) }, 38}; 39 40static 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 79errout: 80 return err; 81} 82 83static void veth_dump_line(struct rtnl_link *link, struct nl_dump_params *p) 84{ 85} 86 87static 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 99static 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 117static 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 143static 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 168static 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 180static 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 */ 212struct 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 */ 232struct 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 */ 243void 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 */ 255int 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 */ 274int 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 298static void __init veth_init(void) 299{ 300 rtnl_link_register_info(&veth_info_ops); 301} 302 303static void __exit veth_exit(void) 304{ 305 rtnl_link_unregister_info(&veth_info_ops); 306} 307 308/** @} */ 309