libnl: /data/src/libnl3/lib/route/link/veth.c Source File

libnl 3.7.0

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