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
veth_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)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, (struct nlattr *)
67 ((char *) 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
veth_dump_line(struct rtnl_link * link,struct nl_dump_params * p)84 static void veth_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
85 {
86 }
87
veth_dump_details(struct rtnl_link * link,struct nl_dump_params * p)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
veth_clone(struct rtnl_link * dst,struct rtnl_link * src)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
veth_put_attrs(struct nl_msg * msg,struct rtnl_link * link)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
veth_alloc(struct rtnl_link * link)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
veth_free(struct rtnl_link * link)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 */
rtnl_link_veth_alloc(void)213 struct rtnl_link *rtnl_link_veth_alloc(void)
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 */
rtnl_link_veth_get_peer(struct rtnl_link * link)233 struct rtnl_link *rtnl_link_veth_get_peer(struct rtnl_link *link)
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 */
rtnl_link_veth_release(struct rtnl_link * link)244 void rtnl_link_veth_release(struct rtnl_link *link)
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 */
rtnl_link_is_veth(struct rtnl_link * link)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 */
rtnl_link_veth_add(struct nl_sock * sock,const char * name,const char * peer_name,pid_t pid)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)
286 rtnl_link_set_name(link, name);
287 if (peer_name)
288 rtnl_link_set_name(peer, peer_name);
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
veth_init(void)299 static void __init veth_init(void)
300 {
301 rtnl_link_register_info(&veth_info_ops);
302 }
303
veth_exit(void)304 static void __exit veth_exit(void)
305 {
306 rtnl_link_unregister_info(&veth_info_ops);
307 }
308
309 /** @} */
310