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