]>
Commit | Line | Data |
---|---|---|
0ad19a3f | 1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
9afe19d6 | 7 | * Daniel Lezcano <daniel.lezcano at free.fr> |
0ad19a3f | 8 | * |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
250b1eec | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
0ad19a3f | 22 | */ |
23 | #define _GNU_SOURCE | |
24 | #include <stdio.h> | |
25 | #undef _GNU_SOURCe | |
26 | #include <stdlib.h> | |
27 | #include <unistd.h> | |
28 | #include <fcntl.h> | |
29 | #include <errno.h> | |
30 | #include <string.h> | |
31 | #include <stdio.h> | |
32 | #include <ctype.h> | |
dd1d77f9 | 33 | #include <time.h> |
0ad19a3f | 34 | #include <sys/types.h> |
35 | #include <sys/stat.h> | |
36 | #include <sys/socket.h> | |
37 | #include <sys/param.h> | |
38 | #include <sys/ioctl.h> | |
39 | #include <arpa/inet.h> | |
40 | #include <net/if.h> | |
41 | #include <net/if_arp.h> | |
42 | #include <net/ethernet.h> | |
43 | #include <netinet/in.h> | |
44 | #include <linux/netlink.h> | |
45 | #include <linux/rtnetlink.h> | |
46 | #include <linux/sockios.h> | |
f549edcc GK |
47 | |
48 | #include "nl.h" | |
49 | #include "network.h" | |
72d0e1cb | 50 | #include "conf.h" |
0ad19a3f | 51 | |
a0265685 SG |
52 | #if HAVE_IFADDRS_H |
53 | #include <ifaddrs.h> | |
54 | #else | |
55 | #include <../include/ifaddrs.h> | |
56 | #endif | |
57 | ||
0ad19a3f | 58 | #ifndef IFLA_LINKMODE |
59 | # define IFLA_LINKMODE 17 | |
60 | #endif | |
61 | ||
62 | #ifndef IFLA_LINKINFO | |
63 | # define IFLA_LINKINFO 18 | |
64 | #endif | |
65 | ||
66 | #ifndef IFLA_NET_NS_PID | |
67 | # define IFLA_NET_NS_PID 19 | |
68 | #endif | |
69 | ||
70 | #ifndef IFLA_INFO_KIND | |
71 | # define IFLA_INFO_KIND 1 | |
72 | #endif | |
73 | ||
26c39028 JHS |
74 | #ifndef IFLA_VLAN_ID |
75 | # define IFLA_VLAN_ID 1 | |
76 | #endif | |
77 | ||
0ad19a3f | 78 | #ifndef IFLA_INFO_DATA |
79 | # define IFLA_INFO_DATA 2 | |
80 | #endif | |
81 | ||
82 | #ifndef VETH_INFO_PEER | |
83 | # define VETH_INFO_PEER 1 | |
84 | #endif | |
85 | ||
e892973e DL |
86 | #ifndef IFLA_MACVLAN_MODE |
87 | # define IFLA_MACVLAN_MODE 1 | |
88 | #endif | |
89 | ||
0ad19a3f | 90 | struct link_req { |
91 | struct nlmsg nlmsg; | |
92 | struct ifinfomsg ifinfomsg; | |
93 | }; | |
94 | ||
95 | struct ip_req { | |
96 | struct nlmsg nlmsg; | |
97 | struct ifaddrmsg ifa; | |
98 | }; | |
99 | ||
f8fee0e2 MK |
100 | struct rt_req { |
101 | struct nlmsg nlmsg; | |
102 | struct rtmsg rt; | |
103 | }; | |
104 | ||
d472214b | 105 | int lxc_netdev_move_by_index(int ifindex, pid_t pid) |
0ad19a3f | 106 | { |
107 | struct nl_handler nlh; | |
108 | struct nlmsg *nlmsg = NULL; | |
109 | struct link_req *link_req; | |
3cfc0f3a | 110 | int err; |
0ad19a3f | 111 | |
3cfc0f3a MN |
112 | err = netlink_open(&nlh, NETLINK_ROUTE); |
113 | if (err) | |
114 | return err; | |
0ad19a3f | 115 | |
3cfc0f3a | 116 | err = -ENOMEM; |
0ad19a3f | 117 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
118 | if (!nlmsg) | |
119 | goto out; | |
120 | ||
0ad19a3f | 121 | link_req = (struct link_req *)nlmsg; |
122 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
82d5ae15 | 123 | link_req->ifinfomsg.ifi_index = ifindex; |
0ad19a3f | 124 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
125 | nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; | |
126 | nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; | |
127 | ||
128 | if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) | |
129 | goto out; | |
130 | ||
3cfc0f3a | 131 | err = netlink_transaction(&nlh, nlmsg, nlmsg); |
0ad19a3f | 132 | out: |
133 | netlink_close(&nlh); | |
134 | nlmsg_free(nlmsg); | |
135 | return err; | |
136 | } | |
137 | ||
8befa924 SH |
138 | int lxc_netdev_move_by_name(char *ifname, pid_t pid) |
139 | { | |
140 | int index; | |
141 | ||
8befa924 SH |
142 | if (!ifname) |
143 | return -EINVAL; | |
144 | ||
32571606 SH |
145 | index = if_nametoindex(ifname); |
146 | ||
8befa924 SH |
147 | return lxc_netdev_move_by_index(index, pid); |
148 | } | |
149 | ||
b84f58b9 | 150 | int lxc_netdev_delete_by_index(int ifindex) |
0ad19a3f | 151 | { |
152 | struct nl_handler nlh; | |
153 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
154 | struct link_req *link_req; | |
b84f58b9 | 155 | int err; |
0ad19a3f | 156 | |
3cfc0f3a MN |
157 | err = netlink_open(&nlh, NETLINK_ROUTE); |
158 | if (err) | |
159 | return err; | |
0ad19a3f | 160 | |
3cfc0f3a | 161 | err = -ENOMEM; |
0ad19a3f | 162 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
163 | if (!nlmsg) | |
164 | goto out; | |
165 | ||
166 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
167 | if (!answer) | |
168 | goto out; | |
169 | ||
0ad19a3f | 170 | link_req = (struct link_req *)nlmsg; |
171 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
b84f58b9 | 172 | link_req->ifinfomsg.ifi_index = ifindex; |
0ad19a3f | 173 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); |
174 | nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; | |
175 | nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK; | |
176 | ||
3cfc0f3a | 177 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 178 | out: |
179 | netlink_close(&nlh); | |
180 | nlmsg_free(answer); | |
181 | nlmsg_free(nlmsg); | |
182 | return err; | |
183 | } | |
184 | ||
b84f58b9 DL |
185 | int lxc_netdev_delete_by_name(const char *name) |
186 | { | |
187 | int index; | |
188 | ||
189 | index = if_nametoindex(name); | |
190 | if (!index) | |
191 | return -EINVAL; | |
192 | ||
193 | return lxc_netdev_delete_by_index(index); | |
194 | } | |
195 | ||
196 | int lxc_netdev_rename_by_index(int ifindex, const char *newname) | |
b9a5bb58 DL |
197 | { |
198 | struct nl_handler nlh; | |
199 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
200 | struct link_req *link_req; | |
b84f58b9 | 201 | int len, err; |
b9a5bb58 | 202 | |
3cfc0f3a MN |
203 | err = netlink_open(&nlh, NETLINK_ROUTE); |
204 | if (err) | |
205 | return err; | |
b9a5bb58 | 206 | |
b84f58b9 | 207 | len = strlen(newname); |
dae3fdf6 | 208 | if (len == 1 || len >= IFNAMSIZ) |
b84f58b9 DL |
209 | goto out; |
210 | ||
3cfc0f3a | 211 | err = -ENOMEM; |
b9a5bb58 DL |
212 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
213 | if (!nlmsg) | |
214 | goto out; | |
215 | ||
216 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
217 | if (!answer) | |
218 | goto out; | |
219 | ||
220 | link_req = (struct link_req *)nlmsg; | |
221 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
222 | link_req->ifinfomsg.ifi_index = ifindex; | |
223 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | |
224 | nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; | |
b84f58b9 DL |
225 | nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; |
226 | ||
227 | if (nla_put_string(nlmsg, IFLA_IFNAME, newname)) | |
228 | goto out; | |
b9a5bb58 | 229 | |
3cfc0f3a | 230 | err = netlink_transaction(&nlh, nlmsg, answer); |
b9a5bb58 DL |
231 | out: |
232 | netlink_close(&nlh); | |
233 | nlmsg_free(answer); | |
234 | nlmsg_free(nlmsg); | |
235 | return err; | |
236 | } | |
237 | ||
b84f58b9 DL |
238 | int lxc_netdev_rename_by_name(const char *oldname, const char *newname) |
239 | { | |
240 | int len, index; | |
241 | ||
242 | len = strlen(oldname); | |
dae3fdf6 | 243 | if (len == 1 || len >= IFNAMSIZ) |
b84f58b9 DL |
244 | return -EINVAL; |
245 | ||
246 | index = if_nametoindex(oldname); | |
247 | if (!index) | |
248 | return -EINVAL; | |
249 | ||
250 | return lxc_netdev_rename_by_index(index, newname); | |
251 | } | |
252 | ||
8befa924 | 253 | int netdev_set_flag(const char *name, int flag) |
0ad19a3f | 254 | { |
255 | struct nl_handler nlh; | |
256 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
257 | struct link_req *link_req; | |
3cfc0f3a | 258 | int index, len, err; |
0ad19a3f | 259 | |
3cfc0f3a MN |
260 | err = netlink_open(&nlh, NETLINK_ROUTE); |
261 | if (err) | |
262 | return err; | |
0ad19a3f | 263 | |
3cfc0f3a | 264 | err = -EINVAL; |
0ad19a3f | 265 | len = strlen(name); |
dae3fdf6 | 266 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 267 | goto out; |
268 | ||
3cfc0f3a | 269 | err = -ENOMEM; |
0ad19a3f | 270 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
271 | if (!nlmsg) | |
272 | goto out; | |
273 | ||
274 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
275 | if (!answer) | |
276 | goto out; | |
277 | ||
3cfc0f3a | 278 | err = -EINVAL; |
0ad19a3f | 279 | index = if_nametoindex(name); |
280 | if (!index) | |
281 | goto out; | |
282 | ||
283 | link_req = (struct link_req *)nlmsg; | |
284 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
285 | link_req->ifinfomsg.ifi_index = index; | |
286 | link_req->ifinfomsg.ifi_change |= IFF_UP; | |
287 | link_req->ifinfomsg.ifi_flags |= flag; | |
288 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | |
289 | nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; | |
290 | nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; | |
291 | ||
292 | err = netlink_transaction(&nlh, nlmsg, answer); | |
0ad19a3f | 293 | out: |
294 | netlink_close(&nlh); | |
295 | nlmsg_free(nlmsg); | |
296 | nlmsg_free(answer); | |
297 | return err; | |
298 | } | |
299 | ||
0130df54 SH |
300 | int netdev_get_mtu(int ifindex) |
301 | { | |
302 | struct nl_handler nlh; | |
303 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
304 | struct ip_req *ip_req; | |
305 | struct nlmsghdr *msg; | |
306 | int err, res; | |
307 | int recv_len = 0, answer_len; | |
308 | int readmore = 0; | |
309 | ||
310 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
311 | if (err) | |
312 | return err; | |
313 | ||
314 | err = -ENOMEM; | |
315 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
316 | if (!nlmsg) | |
317 | goto out; | |
318 | ||
319 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
320 | if (!answer) | |
321 | goto out; | |
322 | ||
323 | /* Save the answer buffer length, since it will be overwritten | |
324 | * on the first receive (and we might need to receive more than | |
325 | * once. */ | |
326 | answer_len = answer->nlmsghdr.nlmsg_len; | |
327 | ||
328 | ip_req = (struct ip_req *)nlmsg; | |
329 | ip_req->nlmsg.nlmsghdr.nlmsg_len = | |
330 | NLMSG_LENGTH(sizeof(struct ifaddrmsg)); | |
331 | ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; | |
332 | ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETLINK; | |
333 | ip_req->ifa.ifa_family = AF_UNSPEC; | |
334 | ||
335 | /* Send the request for addresses, which returns all addresses | |
336 | * on all interfaces. */ | |
337 | err = netlink_send(&nlh, nlmsg); | |
338 | if (err < 0) | |
339 | goto out; | |
340 | ||
341 | do { | |
342 | /* Restore the answer buffer length, it might have been | |
343 | * overwritten by a previous receive. */ | |
344 | answer->nlmsghdr.nlmsg_len = answer_len; | |
345 | ||
346 | /* Get the (next) batch of reply messages */ | |
347 | err = netlink_rcv(&nlh, answer); | |
348 | if (err < 0) | |
349 | goto out; | |
350 | ||
351 | recv_len = err; | |
352 | err = 0; | |
353 | ||
354 | /* Satisfy the typing for the netlink macros */ | |
355 | msg = &answer->nlmsghdr; | |
356 | ||
357 | while (NLMSG_OK(msg, recv_len)) { | |
358 | ||
359 | /* Stop reading if we see an error message */ | |
360 | if (msg->nlmsg_type == NLMSG_ERROR) { | |
361 | struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg); | |
362 | err = errmsg->error; | |
363 | goto out; | |
364 | } | |
365 | ||
366 | /* Stop reading if we see a NLMSG_DONE message */ | |
367 | if (msg->nlmsg_type == NLMSG_DONE) { | |
368 | readmore = 0; | |
369 | break; | |
370 | } | |
371 | ||
372 | struct ifinfomsg *ifi = NLMSG_DATA(msg); | |
373 | if (ifi->ifi_index == ifindex) { | |
374 | struct rtattr *rta = IFLA_RTA(ifi); | |
375 | int attr_len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); | |
376 | res = 0; | |
377 | while(RTA_OK(rta, attr_len)) { | |
378 | /* Found a local address for the requested interface, | |
379 | * return it. */ | |
380 | if (rta->rta_type == IFLA_MTU) { | |
381 | memcpy(&res, RTA_DATA(rta), sizeof(int)); | |
382 | err = res; | |
383 | goto out; | |
384 | } | |
385 | rta = RTA_NEXT(rta, attr_len); | |
386 | } | |
387 | ||
388 | } | |
389 | ||
390 | /* Keep reading more data from the socket if the | |
391 | * last message had the NLF_F_MULTI flag set */ | |
392 | readmore = (msg->nlmsg_flags & NLM_F_MULTI); | |
393 | ||
394 | /* Look at the next message received in this buffer */ | |
395 | msg = NLMSG_NEXT(msg, recv_len); | |
396 | } | |
397 | } while (readmore); | |
398 | ||
399 | /* If we end up here, we didn't find any result, so signal an | |
400 | * error */ | |
401 | err = -1; | |
402 | ||
403 | out: | |
404 | netlink_close(&nlh); | |
405 | nlmsg_free(answer); | |
406 | nlmsg_free(nlmsg); | |
407 | return err; | |
408 | } | |
409 | ||
d472214b | 410 | int lxc_netdev_set_mtu(const char *name, int mtu) |
75d09f83 DL |
411 | { |
412 | struct nl_handler nlh; | |
413 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
414 | struct link_req *link_req; | |
3cfc0f3a | 415 | int index, len, err; |
75d09f83 | 416 | |
3cfc0f3a MN |
417 | err = netlink_open(&nlh, NETLINK_ROUTE); |
418 | if (err) | |
419 | return err; | |
75d09f83 | 420 | |
3cfc0f3a | 421 | err = -EINVAL; |
75d09f83 | 422 | len = strlen(name); |
dae3fdf6 | 423 | if (len == 1 || len >= IFNAMSIZ) |
75d09f83 DL |
424 | goto out; |
425 | ||
3cfc0f3a | 426 | err = -ENOMEM; |
75d09f83 DL |
427 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
428 | if (!nlmsg) | |
429 | goto out; | |
430 | ||
431 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
432 | if (!answer) | |
433 | goto out; | |
434 | ||
3cfc0f3a | 435 | err = -EINVAL; |
75d09f83 DL |
436 | index = if_nametoindex(name); |
437 | if (!index) | |
438 | goto out; | |
439 | ||
440 | link_req = (struct link_req *)nlmsg; | |
441 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
442 | link_req->ifinfomsg.ifi_index = index; | |
443 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | |
444 | nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; | |
445 | nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; | |
446 | ||
447 | if (nla_put_u32(nlmsg, IFLA_MTU, mtu)) | |
448 | goto out; | |
449 | ||
450 | err = netlink_transaction(&nlh, nlmsg, answer); | |
75d09f83 DL |
451 | out: |
452 | netlink_close(&nlh); | |
453 | nlmsg_free(nlmsg); | |
454 | nlmsg_free(answer); | |
455 | return err; | |
456 | } | |
457 | ||
d472214b | 458 | int lxc_netdev_up(const char *name) |
0ad19a3f | 459 | { |
d472214b | 460 | return netdev_set_flag(name, IFF_UP); |
0ad19a3f | 461 | } |
462 | ||
d472214b | 463 | int lxc_netdev_down(const char *name) |
0ad19a3f | 464 | { |
d472214b | 465 | return netdev_set_flag(name, 0); |
0ad19a3f | 466 | } |
467 | ||
497353b6 | 468 | int lxc_veth_create(const char *name1, const char *name2) |
0ad19a3f | 469 | { |
470 | struct nl_handler nlh; | |
471 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
472 | struct link_req *link_req; | |
473 | struct rtattr *nest1, *nest2, *nest3; | |
3cfc0f3a | 474 | int len, err; |
0ad19a3f | 475 | |
3cfc0f3a MN |
476 | err = netlink_open(&nlh, NETLINK_ROUTE); |
477 | if (err) | |
478 | return err; | |
0ad19a3f | 479 | |
3cfc0f3a | 480 | err = -EINVAL; |
0ad19a3f | 481 | len = strlen(name1); |
dae3fdf6 | 482 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 483 | goto out; |
484 | ||
485 | len = strlen(name2); | |
dae3fdf6 | 486 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 487 | goto out; |
488 | ||
3cfc0f3a | 489 | err = -ENOMEM; |
0ad19a3f | 490 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
491 | if (!nlmsg) | |
492 | goto out; | |
493 | ||
494 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
495 | if (!answer) | |
496 | goto out; | |
497 | ||
498 | link_req = (struct link_req *)nlmsg; | |
499 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
500 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | |
79e68309 | 501 | nlmsg->nlmsghdr.nlmsg_flags = |
0ad19a3f | 502 | NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; |
503 | nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; | |
504 | ||
3cfc0f3a | 505 | err = -EINVAL; |
79e68309 | 506 | nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO); |
0ad19a3f | 507 | if (!nest1) |
508 | goto out; | |
509 | ||
510 | if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth")) | |
511 | goto out; | |
512 | ||
513 | nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); | |
514 | if (!nest2) | |
515 | goto out; | |
516 | ||
517 | nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER); | |
518 | if (!nest3) | |
519 | goto out; | |
520 | ||
521 | nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg); | |
522 | ||
523 | if (nla_put_string(nlmsg, IFLA_IFNAME, name2)) | |
524 | goto out; | |
525 | ||
526 | nla_end_nested(nlmsg, nest3); | |
527 | ||
528 | nla_end_nested(nlmsg, nest2); | |
529 | ||
530 | nla_end_nested(nlmsg, nest1); | |
531 | ||
532 | if (nla_put_string(nlmsg, IFLA_IFNAME, name1)) | |
533 | goto out; | |
534 | ||
3cfc0f3a | 535 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 536 | out: |
537 | netlink_close(&nlh); | |
538 | nlmsg_free(answer); | |
539 | nlmsg_free(nlmsg); | |
540 | return err; | |
541 | } | |
542 | ||
26c39028 | 543 | /* XXX: merge with lxc_macvlan_create */ |
7c11d57a | 544 | int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid) |
26c39028 JHS |
545 | { |
546 | struct nl_handler nlh; | |
547 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
548 | struct link_req *link_req; | |
549 | struct rtattr *nest, *nest2; | |
3cfc0f3a | 550 | int lindex, len, err; |
26c39028 | 551 | |
3cfc0f3a MN |
552 | err = netlink_open(&nlh, NETLINK_ROUTE); |
553 | if (err) | |
554 | return err; | |
26c39028 | 555 | |
3cfc0f3a | 556 | err = -EINVAL; |
26c39028 | 557 | len = strlen(master); |
dae3fdf6 | 558 | if (len == 1 || len >= IFNAMSIZ) |
26c39028 JHS |
559 | goto err3; |
560 | ||
561 | len = strlen(name); | |
dae3fdf6 | 562 | if (len == 1 || len >= IFNAMSIZ) |
26c39028 JHS |
563 | goto err3; |
564 | ||
3cfc0f3a | 565 | err = -ENOMEM; |
26c39028 JHS |
566 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
567 | if (!nlmsg) | |
568 | goto err3; | |
569 | ||
570 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
571 | if (!answer) | |
572 | goto err2; | |
573 | ||
3cfc0f3a | 574 | err = -EINVAL; |
26c39028 JHS |
575 | lindex = if_nametoindex(master); |
576 | if (!lindex) | |
577 | goto err1; | |
578 | ||
579 | link_req = (struct link_req *)nlmsg; | |
580 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
581 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | |
582 | nlmsg->nlmsghdr.nlmsg_flags = | |
583 | NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; | |
584 | nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; | |
585 | ||
79e68309 | 586 | nest = nla_begin_nested(nlmsg, IFLA_LINKINFO); |
26c39028 JHS |
587 | if (!nest) |
588 | goto err1; | |
589 | ||
590 | if (nla_put_string(nlmsg, IFLA_INFO_KIND, "vlan")) | |
591 | goto err1; | |
592 | ||
593 | nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); | |
594 | if (!nest2) | |
595 | goto err1; | |
e892973e | 596 | |
26c39028 JHS |
597 | if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid)) |
598 | goto err1; | |
e892973e | 599 | |
26c39028 JHS |
600 | nla_end_nested(nlmsg, nest2); |
601 | ||
602 | nla_end_nested(nlmsg, nest); | |
603 | ||
604 | if (nla_put_u32(nlmsg, IFLA_LINK, lindex)) | |
605 | goto err1; | |
606 | ||
607 | if (nla_put_string(nlmsg, IFLA_IFNAME, name)) | |
608 | goto err1; | |
609 | ||
3cfc0f3a | 610 | err = netlink_transaction(&nlh, nlmsg, answer); |
26c39028 JHS |
611 | err1: |
612 | nlmsg_free(answer); | |
613 | err2: | |
614 | nlmsg_free(nlmsg); | |
615 | err3: | |
616 | netlink_close(&nlh); | |
617 | return err; | |
618 | } | |
619 | ||
e892973e | 620 | int lxc_macvlan_create(const char *master, const char *name, int mode) |
0ad19a3f | 621 | { |
622 | struct nl_handler nlh; | |
623 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
624 | struct link_req *link_req; | |
e892973e | 625 | struct rtattr *nest, *nest2; |
3cfc0f3a | 626 | int index, len, err; |
0ad19a3f | 627 | |
3cfc0f3a MN |
628 | err = netlink_open(&nlh, NETLINK_ROUTE); |
629 | if (err) | |
630 | return err; | |
0ad19a3f | 631 | |
3cfc0f3a | 632 | err = -EINVAL; |
0ad19a3f | 633 | len = strlen(master); |
dae3fdf6 | 634 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 635 | goto out; |
636 | ||
637 | len = strlen(name); | |
dae3fdf6 | 638 | if (len == 1 || len >= IFNAMSIZ) |
0ad19a3f | 639 | goto out; |
640 | ||
3cfc0f3a | 641 | err = -ENOMEM; |
0ad19a3f | 642 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
643 | if (!nlmsg) | |
644 | goto out; | |
645 | ||
646 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
647 | if (!answer) | |
648 | goto out; | |
649 | ||
3cfc0f3a | 650 | err = -EINVAL; |
0ad19a3f | 651 | index = if_nametoindex(master); |
652 | if (!index) | |
653 | goto out; | |
654 | ||
655 | link_req = (struct link_req *)nlmsg; | |
656 | link_req->ifinfomsg.ifi_family = AF_UNSPEC; | |
657 | nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | |
658 | nlmsg->nlmsghdr.nlmsg_flags = | |
659 | NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; | |
660 | nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; | |
661 | ||
79e68309 | 662 | nest = nla_begin_nested(nlmsg, IFLA_LINKINFO); |
0ad19a3f | 663 | if (!nest) |
664 | goto out; | |
665 | ||
666 | if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan")) | |
667 | goto out; | |
668 | ||
e892973e DL |
669 | if (mode) { |
670 | nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); | |
671 | if (!nest2) | |
672 | goto out; | |
673 | ||
674 | if (nla_put_u32(nlmsg, IFLA_MACVLAN_MODE, mode)) | |
675 | goto out; | |
676 | ||
677 | nla_end_nested(nlmsg, nest2); | |
678 | } | |
679 | ||
0ad19a3f | 680 | nla_end_nested(nlmsg, nest); |
681 | ||
682 | if (nla_put_u32(nlmsg, IFLA_LINK, index)) | |
683 | goto out; | |
684 | ||
685 | if (nla_put_string(nlmsg, IFLA_IFNAME, name)) | |
686 | goto out; | |
687 | ||
3cfc0f3a | 688 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 689 | out: |
690 | netlink_close(&nlh); | |
691 | nlmsg_free(answer); | |
692 | nlmsg_free(nlmsg); | |
693 | return err; | |
694 | } | |
695 | ||
696 | static int proc_sys_net_write(const char *path, const char *value) | |
697 | { | |
698 | int fd, err = 0; | |
699 | ||
700 | fd = open(path, O_WRONLY); | |
701 | if (fd < 0) | |
702 | return -errno; | |
703 | ||
704 | if (write(fd, value, strlen(value)) < 0) | |
705 | err = -errno; | |
706 | ||
707 | close(fd); | |
708 | return err; | |
709 | } | |
710 | ||
711 | static int ip_forward_set(const char *ifname, int family, int flag) | |
712 | { | |
22ebac19 | 713 | char path[MAXPATHLEN]; |
9ba8130c | 714 | int rc; |
0ad19a3f | 715 | |
716 | if (family != AF_INET && family != AF_INET6) | |
3cfc0f3a | 717 | return -EINVAL; |
0ad19a3f | 718 | |
9ba8130c | 719 | rc = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/forwarding", |
0ad19a3f | 720 | family == AF_INET?"ipv4":"ipv6" , ifname); |
9ba8130c SH |
721 | if (rc >= MAXPATHLEN) |
722 | return -E2BIG; | |
0ad19a3f | 723 | |
22ebac19 | 724 | return proc_sys_net_write(path, flag?"1":"0"); |
0ad19a3f | 725 | } |
726 | ||
497353b6 | 727 | int lxc_ip_forward_on(const char *ifname, int family) |
0ad19a3f | 728 | { |
729 | return ip_forward_set(ifname, family, 1); | |
730 | } | |
731 | ||
497353b6 | 732 | int lxc_ip_forward_off(const char *ifname, int family) |
0ad19a3f | 733 | { |
734 | return ip_forward_set(ifname, family, 0); | |
735 | } | |
736 | ||
737 | static int neigh_proxy_set(const char *ifname, int family, int flag) | |
738 | { | |
739 | char path[MAXPATHLEN]; | |
9ba8130c | 740 | int ret; |
0ad19a3f | 741 | |
742 | if (family != AF_INET && family != AF_INET6) | |
3cfc0f3a | 743 | return -EINVAL; |
0ad19a3f | 744 | |
9ba8130c | 745 | ret = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/%s", |
79e68309 | 746 | family == AF_INET?"ipv4":"ipv6" , ifname, |
0ad19a3f | 747 | family == AF_INET?"proxy_arp":"proxy_ndp"); |
9ba8130c SH |
748 | if (ret < 0 || ret >= MAXPATHLEN) |
749 | return -E2BIG; | |
0ad19a3f | 750 | |
751 | return proc_sys_net_write(path, flag?"1":"0"); | |
752 | } | |
753 | ||
497353b6 | 754 | int lxc_neigh_proxy_on(const char *name, int family) |
0ad19a3f | 755 | { |
756 | return neigh_proxy_set(name, family, 1); | |
757 | } | |
758 | ||
497353b6 | 759 | int lxc_neigh_proxy_off(const char *name, int family) |
0ad19a3f | 760 | { |
761 | return neigh_proxy_set(name, family, 0); | |
762 | } | |
763 | ||
764 | int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr) | |
765 | { | |
1f1b18e7 DL |
766 | unsigned char *data; |
767 | char c; | |
768 | int i = 0; | |
769 | unsigned val; | |
770 | ||
771 | sockaddr->sa_family = ARPHRD_ETHER; | |
772 | data = (unsigned char *)sockaddr->sa_data; | |
773 | ||
774 | while ((*macaddr != '\0') && (i < ETH_ALEN)) { | |
775 | val = 0; | |
776 | c = *macaddr++; | |
777 | if (isdigit(c)) | |
778 | val = c - '0'; | |
779 | else if (c >= 'a' && c <= 'f') | |
780 | val = c - 'a' + 10; | |
781 | else if (c >= 'A' && c <= 'F') | |
782 | val = c - 'A' + 10; | |
783 | else { | |
784 | return -EINVAL; | |
785 | } | |
786 | val <<= 4; | |
787 | c = *macaddr; | |
788 | if (isdigit(c)) | |
789 | val |= c - '0'; | |
790 | else if (c >= 'a' && c <= 'f') | |
791 | val |= c - 'a' + 10; | |
792 | else if (c >= 'A' && c <= 'F') | |
793 | val |= c - 'A' + 10; | |
794 | else if (c == ':' || c == 0) | |
795 | val >>= 4; | |
796 | else { | |
797 | return -EINVAL; | |
798 | } | |
799 | if (c != 0) | |
800 | macaddr++; | |
801 | *data++ = (unsigned char) (val & 0377); | |
802 | i++; | |
803 | ||
804 | if (*macaddr == ':') | |
805 | macaddr++; | |
0ad19a3f | 806 | } |
0ad19a3f | 807 | |
1f1b18e7 | 808 | return 0; |
0ad19a3f | 809 | } |
810 | ||
1f1b18e7 DL |
811 | static int ip_addr_add(int family, int ifindex, |
812 | void *addr, void *bcast, void *acast, int prefix) | |
0ad19a3f | 813 | { |
814 | struct nl_handler nlh; | |
0ad19a3f | 815 | struct nlmsg *nlmsg = NULL, *answer = NULL; |
816 | struct ip_req *ip_req; | |
4bf1968d | 817 | int addrlen; |
3cfc0f3a | 818 | int err; |
0ad19a3f | 819 | |
4bf1968d DL |
820 | addrlen = family == AF_INET ? sizeof(struct in_addr) : |
821 | sizeof(struct in6_addr); | |
822 | ||
3cfc0f3a MN |
823 | err = netlink_open(&nlh, NETLINK_ROUTE); |
824 | if (err) | |
825 | return err; | |
0ad19a3f | 826 | |
3cfc0f3a | 827 | err = -ENOMEM; |
0ad19a3f | 828 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); |
829 | if (!nlmsg) | |
830 | goto out; | |
831 | ||
832 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
833 | if (!answer) | |
834 | goto out; | |
835 | ||
0ad19a3f | 836 | ip_req = (struct ip_req *)nlmsg; |
1f1b18e7 DL |
837 | ip_req->nlmsg.nlmsghdr.nlmsg_len = |
838 | NLMSG_LENGTH(sizeof(struct ifaddrmsg)); | |
0ad19a3f | 839 | ip_req->nlmsg.nlmsghdr.nlmsg_flags = |
840 | NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; | |
841 | ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR; | |
842 | ip_req->ifa.ifa_prefixlen = prefix; | |
843 | ip_req->ifa.ifa_index = ifindex; | |
4bf1968d | 844 | ip_req->ifa.ifa_family = family; |
0ad19a3f | 845 | ip_req->ifa.ifa_scope = 0; |
846 | ||
3cfc0f3a | 847 | err = -EINVAL; |
4bf1968d | 848 | if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen)) |
0ad19a3f | 849 | goto out; |
850 | ||
4bf1968d | 851 | if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen)) |
0ad19a3f | 852 | goto out; |
853 | ||
d8948a52 | 854 | if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen)) |
1f1b18e7 DL |
855 | goto out; |
856 | ||
857 | /* TODO : multicast, anycast with ipv6 */ | |
7ddc8f24 | 858 | err = -EPROTONOSUPPORT; |
79881dc6 DL |
859 | if (family == AF_INET6 && |
860 | (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) || | |
861 | memcmp(acast, &in6addr_any, sizeof(in6addr_any)))) | |
1f1b18e7 | 862 | goto out; |
0ad19a3f | 863 | |
3cfc0f3a | 864 | err = netlink_transaction(&nlh, nlmsg, answer); |
0ad19a3f | 865 | out: |
866 | netlink_close(&nlh); | |
867 | nlmsg_free(answer); | |
868 | nlmsg_free(nlmsg); | |
869 | return err; | |
870 | } | |
871 | ||
1f1b18e7 DL |
872 | int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr, |
873 | struct in6_addr *mcast, | |
874 | struct in6_addr *acast, int prefix) | |
875 | { | |
876 | return ip_addr_add(AF_INET6, ifindex, addr, mcast, acast, prefix); | |
877 | } | |
878 | ||
879 | int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, | |
880 | struct in_addr *bcast, int prefix) | |
881 | { | |
882 | return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix); | |
883 | } | |
884 | ||
19a26f82 MK |
885 | /* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present) |
886 | * address from the given RTM_NEWADDR message. Allocates memory for the | |
887 | * address and stores that pointer in *res (so res should be an | |
888 | * in_addr** or in6_addr**). | |
889 | */ | |
890 | static int ifa_get_local_ip(int family, struct ip_req *ip_info, void** res) { | |
891 | struct rtattr *rta = IFA_RTA(&ip_info->ifa); | |
892 | int attr_len = IFA_PAYLOAD(&ip_info->nlmsg.nlmsghdr); | |
893 | int addrlen; | |
894 | ||
895 | if (ip_info->ifa.ifa_family != family) | |
896 | return 0; | |
897 | ||
898 | addrlen = family == AF_INET ? sizeof(struct in_addr) : | |
899 | sizeof(struct in6_addr); | |
900 | ||
901 | /* Loop over the rtattr's in this message */ | |
902 | while(RTA_OK(rta, attr_len)) { | |
903 | /* Found a local address for the requested interface, | |
904 | * return it. */ | |
905 | if (rta->rta_type == IFA_LOCAL || rta->rta_type == IFA_ADDRESS) { | |
906 | /* Sanity check. The family check above should | |
907 | * make sure the address length is correct, but | |
908 | * check here just in case */ | |
909 | if (RTA_PAYLOAD(rta) != addrlen) | |
910 | return -1; | |
911 | ||
912 | /* We might have found an IFA_ADDRESS before, | |
913 | * which we now overwrite with an IFA_LOCAL. */ | |
dd66e5ad | 914 | if (!*res) { |
19a26f82 | 915 | *res = malloc(addrlen); |
dd66e5ad DE |
916 | if (!*res) |
917 | return -1; | |
918 | } | |
19a26f82 MK |
919 | |
920 | memcpy(*res, RTA_DATA(rta), addrlen); | |
921 | ||
922 | if (rta->rta_type == IFA_LOCAL) | |
923 | break; | |
924 | } | |
925 | rta = RTA_NEXT(rta, attr_len); | |
926 | } | |
927 | return 0; | |
928 | } | |
929 | ||
930 | static int ip_addr_get(int family, int ifindex, void **res) | |
931 | { | |
932 | struct nl_handler nlh; | |
933 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
934 | struct ip_req *ip_req, *ip_info; | |
935 | struct nlmsghdr *msg; | |
936 | int err; | |
937 | int recv_len = 0, answer_len; | |
938 | int readmore = 0; | |
939 | ||
940 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
941 | if (err) | |
942 | return err; | |
943 | ||
944 | err = -ENOMEM; | |
945 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
946 | if (!nlmsg) | |
947 | goto out; | |
948 | ||
949 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
950 | if (!answer) | |
951 | goto out; | |
952 | ||
953 | /* Save the answer buffer length, since it will be overwritten | |
954 | * on the first receive (and we might need to receive more than | |
955 | * once. */ | |
956 | answer_len = answer->nlmsghdr.nlmsg_len; | |
957 | ||
958 | ip_req = (struct ip_req *)nlmsg; | |
959 | ip_req->nlmsg.nlmsghdr.nlmsg_len = | |
960 | NLMSG_LENGTH(sizeof(struct ifaddrmsg)); | |
961 | ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT; | |
962 | ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETADDR; | |
963 | ip_req->ifa.ifa_family = family; | |
964 | ||
965 | /* Send the request for addresses, which returns all addresses | |
966 | * on all interfaces. */ | |
967 | err = netlink_send(&nlh, nlmsg); | |
968 | if (err < 0) | |
969 | goto out; | |
19a26f82 MK |
970 | |
971 | do { | |
972 | /* Restore the answer buffer length, it might have been | |
973 | * overwritten by a previous receive. */ | |
974 | answer->nlmsghdr.nlmsg_len = answer_len; | |
975 | ||
976 | /* Get the (next) batch of reply messages */ | |
977 | err = netlink_rcv(&nlh, answer); | |
978 | if (err < 0) | |
979 | goto out; | |
980 | ||
981 | recv_len = err; | |
982 | err = 0; | |
983 | ||
984 | /* Satisfy the typing for the netlink macros */ | |
985 | msg = &answer->nlmsghdr; | |
986 | ||
987 | while (NLMSG_OK(msg, recv_len)) { | |
988 | /* Stop reading if we see an error message */ | |
989 | if (msg->nlmsg_type == NLMSG_ERROR) { | |
990 | struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg); | |
991 | err = errmsg->error; | |
992 | goto out; | |
993 | } | |
994 | ||
995 | /* Stop reading if we see a NLMSG_DONE message */ | |
996 | if (msg->nlmsg_type == NLMSG_DONE) { | |
997 | readmore = 0; | |
998 | break; | |
999 | } | |
1000 | ||
1001 | if (msg->nlmsg_type != RTM_NEWADDR) { | |
1002 | err = -1; | |
1003 | goto out; | |
1004 | } | |
1005 | ||
1006 | ip_info = (struct ip_req *)msg; | |
1007 | if (ip_info->ifa.ifa_index == ifindex) { | |
51e7a874 SG |
1008 | if (ifa_get_local_ip(family, ip_info, res) < 0) { |
1009 | err = -1; | |
1010 | goto out; | |
1011 | } | |
1012 | ||
19a26f82 MK |
1013 | /* Found a result, stop searching */ |
1014 | if (*res) | |
1015 | goto out; | |
1016 | } | |
1017 | ||
1018 | /* Keep reading more data from the socket if the | |
1019 | * last message had the NLF_F_MULTI flag set */ | |
1020 | readmore = (msg->nlmsg_flags & NLM_F_MULTI); | |
1021 | ||
1022 | /* Look at the next message received in this buffer */ | |
1023 | msg = NLMSG_NEXT(msg, recv_len); | |
1024 | } | |
1025 | } while (readmore); | |
1026 | ||
1027 | /* If we end up here, we didn't find any result, so signal an | |
1028 | * error */ | |
1029 | err = -1; | |
1030 | ||
1031 | out: | |
1032 | netlink_close(&nlh); | |
1033 | nlmsg_free(answer); | |
1034 | nlmsg_free(nlmsg); | |
1035 | return err; | |
1036 | } | |
1037 | ||
1038 | int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res) | |
1039 | { | |
1040 | return ip_addr_get(AF_INET6, ifindex, (void**)res); | |
1041 | } | |
1042 | ||
1043 | int lxc_ipv4_addr_get(int ifindex, struct in_addr** res) | |
1044 | { | |
1045 | return ip_addr_get(AF_INET, ifindex, (void**)res); | |
1046 | } | |
1047 | ||
f8fee0e2 MK |
1048 | static int ip_gateway_add(int family, int ifindex, void *gw) |
1049 | { | |
1050 | struct nl_handler nlh; | |
1051 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
1052 | struct rt_req *rt_req; | |
1053 | int addrlen; | |
1054 | int err; | |
1055 | ||
1056 | addrlen = family == AF_INET ? sizeof(struct in_addr) : | |
1057 | sizeof(struct in6_addr); | |
1058 | ||
1059 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
1060 | if (err) | |
1061 | return err; | |
1062 | ||
1063 | err = -ENOMEM; | |
1064 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
1065 | if (!nlmsg) | |
1066 | goto out; | |
1067 | ||
1068 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
1069 | if (!answer) | |
1070 | goto out; | |
1071 | ||
1072 | rt_req = (struct rt_req *)nlmsg; | |
1073 | rt_req->nlmsg.nlmsghdr.nlmsg_len = | |
1074 | NLMSG_LENGTH(sizeof(struct rtmsg)); | |
1075 | rt_req->nlmsg.nlmsghdr.nlmsg_flags = | |
1076 | NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; | |
1077 | rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE; | |
1078 | rt_req->rt.rtm_family = family; | |
1079 | rt_req->rt.rtm_table = RT_TABLE_MAIN; | |
1080 | rt_req->rt.rtm_scope = RT_SCOPE_UNIVERSE; | |
1081 | rt_req->rt.rtm_protocol = RTPROT_BOOT; | |
1082 | rt_req->rt.rtm_type = RTN_UNICAST; | |
1083 | /* "default" destination */ | |
1084 | rt_req->rt.rtm_dst_len = 0; | |
1085 | ||
1086 | err = -EINVAL; | |
1087 | if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen)) | |
1088 | goto out; | |
1089 | ||
1090 | /* Adding the interface index enables the use of link-local | |
1091 | * addresses for the gateway */ | |
1092 | if (nla_put_u32(nlmsg, RTA_OIF, ifindex)) | |
1093 | goto out; | |
1094 | ||
1095 | err = netlink_transaction(&nlh, nlmsg, answer); | |
1096 | out: | |
1097 | netlink_close(&nlh); | |
1098 | nlmsg_free(answer); | |
1099 | nlmsg_free(nlmsg); | |
1100 | return err; | |
1101 | } | |
1102 | ||
1103 | int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw) | |
1104 | { | |
1105 | return ip_gateway_add(AF_INET, ifindex, gw); | |
1106 | } | |
1107 | ||
1108 | int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw) | |
1109 | { | |
1110 | return ip_gateway_add(AF_INET6, ifindex, gw); | |
1111 | } | |
1112 | ||
77dcf03a GL |
1113 | static int ip_route_dest_add(int family, int ifindex, void *dest) |
1114 | { | |
1115 | struct nl_handler nlh; | |
1116 | struct nlmsg *nlmsg = NULL, *answer = NULL; | |
1117 | struct rt_req *rt_req; | |
1118 | int addrlen; | |
1119 | int err; | |
1120 | ||
1121 | addrlen = family == AF_INET ? sizeof(struct in_addr) : | |
1122 | sizeof(struct in6_addr); | |
1123 | ||
1124 | err = netlink_open(&nlh, NETLINK_ROUTE); | |
1125 | if (err) | |
1126 | return err; | |
1127 | ||
1128 | err = -ENOMEM; | |
1129 | nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
1130 | if (!nlmsg) | |
1131 | goto out; | |
1132 | ||
1133 | answer = nlmsg_alloc(NLMSG_GOOD_SIZE); | |
1134 | if (!answer) | |
1135 | goto out; | |
1136 | ||
1137 | rt_req = (struct rt_req *)nlmsg; | |
1138 | rt_req->nlmsg.nlmsghdr.nlmsg_len = | |
1139 | NLMSG_LENGTH(sizeof(struct rtmsg)); | |
1140 | rt_req->nlmsg.nlmsghdr.nlmsg_flags = | |
1141 | NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; | |
1142 | rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE; | |
1143 | rt_req->rt.rtm_family = family; | |
1144 | rt_req->rt.rtm_table = RT_TABLE_MAIN; | |
1145 | rt_req->rt.rtm_scope = RT_SCOPE_LINK; | |
1146 | rt_req->rt.rtm_protocol = RTPROT_BOOT; | |
1147 | rt_req->rt.rtm_type = RTN_UNICAST; | |
1148 | rt_req->rt.rtm_dst_len = addrlen*8; | |
1149 | ||
1150 | err = -EINVAL; | |
1151 | if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen)) | |
1152 | goto out; | |
1153 | if (nla_put_u32(nlmsg, RTA_OIF, ifindex)) | |
1154 | goto out; | |
1155 | err = netlink_transaction(&nlh, nlmsg, answer); | |
1156 | out: | |
1157 | netlink_close(&nlh); | |
1158 | nlmsg_free(answer); | |
1159 | nlmsg_free(nlmsg); | |
1160 | return err; | |
1161 | } | |
1162 | ||
1163 | int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest) | |
1164 | { | |
1165 | return ip_route_dest_add(AF_INET, ifindex, dest); | |
1166 | } | |
1167 | ||
1168 | int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest) | |
1169 | { | |
1170 | return ip_route_dest_add(AF_INET6, ifindex, dest); | |
1171 | } | |
1172 | ||
7d163508 MN |
1173 | /* |
1174 | * There is a lxc_bridge_attach, but no need of a bridge detach | |
d472214b | 1175 | * as automatically done by kernel when a netdev is deleted. |
7d163508 MN |
1176 | */ |
1177 | int lxc_bridge_attach(const char *bridge, const char *ifname) | |
0ad19a3f | 1178 | { |
1179 | int fd, index, err; | |
1180 | struct ifreq ifr; | |
1181 | ||
dae3fdf6 | 1182 | if (strlen(ifname) >= IFNAMSIZ) |
3cfc0f3a | 1183 | return -EINVAL; |
0ad19a3f | 1184 | |
1185 | index = if_nametoindex(ifname); | |
1186 | if (!index) | |
3cfc0f3a | 1187 | return -EINVAL; |
0ad19a3f | 1188 | |
1189 | fd = socket(AF_INET, SOCK_STREAM, 0); | |
1190 | if (fd < 0) | |
3cfc0f3a | 1191 | return -errno; |
0ad19a3f | 1192 | |
5da6aa8c DE |
1193 | strncpy(ifr.ifr_name, bridge, IFNAMSIZ-1); |
1194 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; | |
0ad19a3f | 1195 | ifr.ifr_ifindex = index; |
7d163508 | 1196 | err = ioctl(fd, SIOCBRADDIF, &ifr); |
0ad19a3f | 1197 | close(fd); |
3cfc0f3a MN |
1198 | if (err) |
1199 | err = -errno; | |
0ad19a3f | 1200 | |
1201 | return err; | |
1202 | } | |
72d0e1cb | 1203 | |
74a3920a | 1204 | static const char* const lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = { |
b343592b | 1205 | [LXC_NET_EMPTY] = "empty", |
72d0e1cb SG |
1206 | [LXC_NET_VETH] = "veth", |
1207 | [LXC_NET_MACVLAN] = "macvlan", | |
72d0e1cb | 1208 | [LXC_NET_PHYS] = "phys", |
b343592b BP |
1209 | [LXC_NET_VLAN] = "vlan", |
1210 | [LXC_NET_NONE] = "none", | |
72d0e1cb SG |
1211 | }; |
1212 | ||
1213 | const char *lxc_net_type_to_str(int type) | |
1214 | { | |
1215 | if (type < 0 || type > LXC_NET_MAXCONFTYPE) | |
1216 | return NULL; | |
1217 | return lxc_network_types[type]; | |
1218 | } | |
8befa924 | 1219 | |
74a3920a | 1220 | static const char padchar[] = |
a0265685 SG |
1221 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
1222 | ||
1223 | char *lxc_mkifname(char *template) | |
1224 | { | |
1225 | char *name = NULL; | |
1226 | int i = 0; | |
1227 | FILE *urandom; | |
1228 | unsigned int seed; | |
1229 | struct ifaddrs *ifaddr, *ifa; | |
1230 | int ifexists = 0; | |
1231 | ||
1232 | /* Get all the network interfaces */ | |
1233 | getifaddrs(&ifaddr); | |
1234 | ||
1235 | /* Initialize the random number generator */ | |
a0265685 | 1236 | urandom = fopen ("/dev/urandom", "r"); |
a0265685 SG |
1237 | if (urandom != NULL) { |
1238 | if (fread (&seed, sizeof(seed), 1, urandom) <= 0) | |
1239 | seed = time(0); | |
a0265685 | 1240 | fclose(urandom); |
a0265685 SG |
1241 | } |
1242 | else | |
1243 | seed = time(0); | |
1244 | ||
1245 | #ifndef HAVE_RAND_R | |
1246 | srand(seed); | |
1247 | #endif | |
1248 | ||
1249 | /* Generate random names until we find one that doesn't exist */ | |
1250 | while(1) { | |
1251 | ifexists = 0; | |
1252 | name = strdup(template); | |
1253 | ||
1254 | if (name == NULL) | |
1255 | return NULL; | |
1256 | ||
1257 | for (i = 0; i < strlen(name); i++) { | |
1258 | if (name[i] == 'X') { | |
1259 | #ifdef HAVE_RAND_R | |
1260 | name[i] = padchar[rand_r(&seed) % (strlen(padchar) - 1)]; | |
1261 | #else | |
1262 | name[i] = padchar[rand() % (strlen(padchar) - 1)]; | |
1263 | #endif | |
1264 | } | |
1265 | } | |
1266 | ||
1267 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | |
1268 | if (strcmp(ifa->ifa_name, name) == 0) { | |
1269 | ifexists = 1; | |
1270 | break; | |
1271 | } | |
1272 | } | |
1273 | ||
1274 | if (ifexists == 0) | |
1275 | break; | |
1276 | ||
1277 | free(name); | |
1278 | } | |
1279 | ||
1280 | freeifaddrs(ifaddr); | |
1281 | return name; | |
1282 | } | |
1283 | ||
8befa924 SH |
1284 | int setup_private_host_hw_addr(char *veth1) |
1285 | { | |
1286 | struct ifreq ifr; | |
1287 | int err; | |
1288 | int sockfd; | |
1289 | ||
8befa924 | 1290 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); |
8befa924 SH |
1291 | if (sockfd < 0) |
1292 | return -errno; | |
1293 | ||
1294 | snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1); | |
1295 | err = ioctl(sockfd, SIOCGIFHWADDR, &ifr); | |
1296 | if (err < 0) { | |
8befa924 | 1297 | close(sockfd); |
8befa924 SH |
1298 | return -errno; |
1299 | } | |
1300 | ||
1301 | ifr.ifr_hwaddr.sa_data[0] = 0xfe; | |
1302 | err = ioctl(sockfd, SIOCSIFHWADDR, &ifr); | |
8befa924 | 1303 | close(sockfd); |
8befa924 SH |
1304 | if (err < 0) |
1305 | return -errno; | |
1306 | ||
1307 | return 0; | |
1308 | } |