libnl  3.2.24-rc1
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 
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 , *src_peer = src->l_info;
102  int err;
103 
104  dst_peer = dst->l_info = rtnl_link_alloc();
105  if (!dst_peer || !src_peer)
106  return -NLE_NOMEM;
107  if ((err = rtnl_link_set_type(dst, "veth")) < 0) {
108  rtnl_link_put(dst_peer);
109  return err;
110  }
111 
112  memcpy(dst_peer, src_peer, sizeof(struct rtnl_link));
113 
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 struct rtnl_link_info_ops veth_info_ops = {
144  .io_name = "veth",
145  .io_parse = veth_parse,
146  .io_dump = {
147  [NL_DUMP_LINE] = veth_dump_line,
148  [NL_DUMP_DETAILS] = veth_dump_details,
149  },
150  .io_clone = veth_clone,
151  .io_put_attrs = veth_put_attrs,
152 };
153 
154 /** @cond SKIP */
155 
156 #define IS_VETH_LINK_ASSERT(link) \
157  if ((link)->l_info_ops != &veth_info_ops) { \
158  APPBUG("Link is not a veth link. set type \"veth\" first."); \
159  return NULL; \
160  }
161 /** @endcond */
162 
163 /**
164  * @name VETH Object
165  * @{
166  */
167 
168 /**
169  * Allocate link object of type veth
170  *
171  * @return Allocated link object or NULL.
172  */
174 {
175  struct rtnl_link *link, *peer;
176  int err;
177 
178  if (!(link = rtnl_link_alloc()))
179  return NULL;
180  if (!(peer = rtnl_link_alloc())) {
181  rtnl_link_put(link);
182  return NULL;
183  }
184 
185  if ((err = rtnl_link_set_type(link, "veth")) < 0) {
186  rtnl_link_put(peer);
187  rtnl_link_put(link);
188  return NULL;
189  }
190  if ((err = rtnl_link_set_type(peer, "veth")) < 0) {
191  rtnl_link_put(peer);
192  rtnl_link_put(link);
193  return NULL;
194  }
195 
196  link->l_info = peer;
197  peer->l_info = link;
198  return link;
199 }
200 
201 /**
202  * Get the peer link of a veth link
203  *
204  * @return the peer link object.
205  */
207 {
208  IS_VETH_LINK_ASSERT(link);
209  return link->l_info;
210 }
211 
212 /**
213  * Release a veth link and its peer
214  *
215  */
217 {
218  struct rtnl_link *peer = rtnl_link_veth_get_peer(link);
219  rtnl_link_put(peer);
220  rtnl_link_put(link);
221 }
222 
223 /**
224  * Check if link is a veth link
225  * @arg link Link object
226  *
227  * @return True if link is a veth link, otherwise false is returned.
228  */
229 int rtnl_link_is_veth(struct rtnl_link *link)
230 {
231  return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "veth");
232 }
233 
234 /**
235  * Create a new kernel veth device
236  * @arg sock netlink socket
237  * @arg name name of the veth device or NULL
238  * @arg peer_name name of its peer or NULL
239  * @arg pid pid of the process in the new netns
240  *
241  * Creates a new veth device pair in the kernel and move the peer
242  * to the network namespace where the process is. If no name is
243  * provided, the kernel will automatically pick a name of the
244  * form "veth%d" (e.g. veth0, veth1, etc.)
245  *
246  * @return 0 on success or a negative error code
247  */
248 int rtnl_link_veth_add(struct nl_sock *sock, const char *name,
249  const char *peer_name, pid_t pid)
250 {
251  struct rtnl_link *link, *peer;
252  int err = -NLE_NOMEM;
253 
254  if (!(link = rtnl_link_veth_alloc()))
255  return -NLE_NOMEM;
256  peer = rtnl_link_veth_get_peer(link);
257 
258  if (name && peer_name) {
259  rtnl_link_set_name(link, name);
260  rtnl_link_set_name(peer, peer_name);
261  }
262 
263  rtnl_link_set_ns_pid(peer, pid);
264  err = rtnl_link_add(sock, link, NLM_F_CREATE);
265 
266  rtnl_link_put(peer);
267  rtnl_link_put(link);
268 
269  return err;
270 }
271 
272 /** @} */
273 
274 static void __init veth_init(void)
275 {
276  rtnl_link_register_info(&veth_info_ops);
277 }
278 
279 static void __exit veth_exit(void)
280 {
281  rtnl_link_unregister_info(&veth_info_ops);
282 }
283 
284 /** @} */