]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/network.c
audit: added capacity and reserve() to nlmsg
[mirror_lxc.git] / src / lxc / network.c
CommitLineData
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"
0d204771 51#include "utils.h"
0ad19a3f 52
a0265685
SG
53#if HAVE_IFADDRS_H
54#include <ifaddrs.h>
55#else
56#include <../include/ifaddrs.h>
57#endif
58
0ad19a3f 59#ifndef IFLA_LINKMODE
60# define IFLA_LINKMODE 17
61#endif
62
63#ifndef IFLA_LINKINFO
64# define IFLA_LINKINFO 18
65#endif
66
67#ifndef IFLA_NET_NS_PID
68# define IFLA_NET_NS_PID 19
69#endif
70
71#ifndef IFLA_INFO_KIND
72# define IFLA_INFO_KIND 1
73#endif
74
26c39028
JHS
75#ifndef IFLA_VLAN_ID
76# define IFLA_VLAN_ID 1
77#endif
78
0ad19a3f 79#ifndef IFLA_INFO_DATA
80# define IFLA_INFO_DATA 2
81#endif
82
83#ifndef VETH_INFO_PEER
84# define VETH_INFO_PEER 1
85#endif
86
e892973e
DL
87#ifndef IFLA_MACVLAN_MODE
88# define IFLA_MACVLAN_MODE 1
89#endif
90
f8fee0e2 91
8d357196 92int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname)
0ad19a3f 93{
94 struct nl_handler nlh;
95 struct nlmsg *nlmsg = NULL;
06f976ca 96 struct ifinfomsg *ifi;
3cfc0f3a 97 int err;
0ad19a3f 98
3cfc0f3a
MN
99 err = netlink_open(&nlh, NETLINK_ROUTE);
100 if (err)
101 return err;
0ad19a3f 102
3cfc0f3a 103 err = -ENOMEM;
0ad19a3f 104 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
105 if (!nlmsg)
106 goto out;
107
06f976ca
SZ
108 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
109 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
110
111 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
112 ifi->ifi_family = AF_UNSPEC;
113 ifi->ifi_index = ifindex;
0ad19a3f 114
115 if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
116 goto out;
117
8d357196
DY
118 if (ifname != NULL) {
119 if (nla_put_string(nlmsg, IFLA_IFNAME, ifname))
120 goto out;
121 }
122
3cfc0f3a 123 err = netlink_transaction(&nlh, nlmsg, nlmsg);
0ad19a3f 124out:
125 netlink_close(&nlh);
126 nlmsg_free(nlmsg);
127 return err;
128}
129
e5848d39
SH
130/*
131 * If we are asked to move a wireless interface, then
132 * we must actually move its phyN device. Detect
133 * that condition and return the physname here. The
134 * physname will be passed to lxc_netdev_move_wlan()
135 * which will free it when done
136 */
137#define PHYSNAME "/sys/class/net/%s/phy80211/name"
138static char * is_wlan(const char *ifname)
139{
140 char *path, *physname = NULL;
141 size_t len = strlen(ifname) + strlen(PHYSNAME) - 1;
142 struct stat sb;
143 long physlen;
144 FILE *f;
145 int ret, i;
146
147 path = alloca(len+1);
148 ret = snprintf(path, len, PHYSNAME, ifname);
149 if (ret < 0 || ret >= len)
150 goto bad;
151 ret = stat(path, &sb);
152 if (ret)
153 goto bad;
154 if (!(f = fopen(path, "r")))
155 goto bad;
156 // feh - sb.st_size is always 4096
157 fseek(f, 0, SEEK_END);
158 physlen = ftell(f);
159 fseek(f, 0, SEEK_SET);
160 physname = malloc(physlen+1);
161 if (!physname)
162 goto bad;
163 memset(physname, 0, physlen+1);
164 ret = fread(physname, 1, physlen, f);
165 fclose(f);
166 if (ret < 0)
167 goto bad;
168
169 for (i = 0; i < physlen; i++) {
170 if (physname[i] == '\n')
171 physname[i] = '\0';
172 if (physname[i] == '\0')
173 break;
174 }
175
176 return physname;
177
178bad:
179 if (physname)
180 free(physname);
181 return NULL;
182}
183
184static int
185lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old, const char *new)
186{
187 pid_t fpid = fork();
188
189 if (fpid < 0)
190 return -1;
191 if (fpid != 0)
192 return wait_for_pid(fpid);
193 if (!switch_to_ns(pid, "net"))
194 return -1;
195 exit(lxc_netdev_rename_by_name(old, new));
196}
197
198static int
199lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, const char* newname)
200{
201 int err = -1;
202 pid_t fpid;
203 char *cmd;
204
205 /* Move phyN into the container. TODO - do this using netlink.
206 * However, IIUC this involves a bit more complicated work to
207 * talk to the 80211 module, so for now just call out to iw
208 */
209 cmd = on_path("iw", NULL);
210 if (!cmd)
211 goto out1;
212 free(cmd);
213
214 fpid = fork();
215 if (fpid < 0)
216 goto out1;
217 if (fpid == 0) {
218 char pidstr[30];
219 sprintf(pidstr, "%d", pid);
220 if (execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, NULL))
221 exit(1);
222 exit(0); // notreached
223 }
224 if (wait_for_pid(fpid))
225 goto out1;
226
227 err = 0;
228 if (newname)
229 err = lxc_netdev_rename_by_name_in_netns(pid, ifname, newname);
230
231out1:
232 free(physname);
233 return err;
234}
235
8d357196 236int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname)
8befa924
SH
237{
238 int index;
e5848d39 239 char *physname;
8befa924 240
8befa924
SH
241 if (!ifname)
242 return -EINVAL;
243
32571606 244 index = if_nametoindex(ifname);
49428bf3
DY
245 if (!index)
246 return -EINVAL;
32571606 247
e5848d39
SH
248 if ((physname = is_wlan(ifname)))
249 return lxc_netdev_move_wlan(physname, ifname, pid, newname);
250
8d357196 251 return lxc_netdev_move_by_index(index, pid, newname);
8befa924
SH
252}
253
b84f58b9 254int lxc_netdev_delete_by_index(int ifindex)
0ad19a3f 255{
256 struct nl_handler nlh;
257 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 258 struct ifinfomsg *ifi;
b84f58b9 259 int err;
0ad19a3f 260
3cfc0f3a
MN
261 err = netlink_open(&nlh, NETLINK_ROUTE);
262 if (err)
263 return err;
0ad19a3f 264
3cfc0f3a 265 err = -ENOMEM;
0ad19a3f 266 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
267 if (!nlmsg)
268 goto out;
269
06f976ca 270 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 271 if (!answer)
272 goto out;
273
06f976ca
SZ
274 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
275 nlmsg->nlmsghdr->nlmsg_type = RTM_DELLINK;
276
277 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
278 ifi->ifi_family = AF_UNSPEC;
279 ifi->ifi_index = ifindex;
0ad19a3f 280
3cfc0f3a 281 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 282out:
283 netlink_close(&nlh);
284 nlmsg_free(answer);
285 nlmsg_free(nlmsg);
286 return err;
287}
288
b84f58b9
DL
289int lxc_netdev_delete_by_name(const char *name)
290{
291 int index;
292
293 index = if_nametoindex(name);
294 if (!index)
295 return -EINVAL;
296
297 return lxc_netdev_delete_by_index(index);
298}
299
300int lxc_netdev_rename_by_index(int ifindex, const char *newname)
b9a5bb58
DL
301{
302 struct nl_handler nlh;
303 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 304 struct ifinfomsg *ifi;
b84f58b9 305 int len, err;
b9a5bb58 306
3cfc0f3a
MN
307 err = netlink_open(&nlh, NETLINK_ROUTE);
308 if (err)
309 return err;
b9a5bb58 310
b84f58b9 311 len = strlen(newname);
dae3fdf6 312 if (len == 1 || len >= IFNAMSIZ)
b84f58b9
DL
313 goto out;
314
3cfc0f3a 315 err = -ENOMEM;
b9a5bb58
DL
316 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
317 if (!nlmsg)
318 goto out;
319
06f976ca 320 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
b9a5bb58
DL
321 if (!answer)
322 goto out;
323
06f976ca
SZ
324 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
325 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
326
327 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
328 ifi->ifi_family = AF_UNSPEC;
329 ifi->ifi_index = ifindex;
b84f58b9
DL
330
331 if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
332 goto out;
b9a5bb58 333
3cfc0f3a 334 err = netlink_transaction(&nlh, nlmsg, answer);
b9a5bb58
DL
335out:
336 netlink_close(&nlh);
337 nlmsg_free(answer);
338 nlmsg_free(nlmsg);
339 return err;
340}
341
b84f58b9
DL
342int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
343{
344 int len, index;
345
346 len = strlen(oldname);
dae3fdf6 347 if (len == 1 || len >= IFNAMSIZ)
b84f58b9
DL
348 return -EINVAL;
349
350 index = if_nametoindex(oldname);
351 if (!index)
352 return -EINVAL;
353
354 return lxc_netdev_rename_by_index(index, newname);
355}
356
8befa924 357int netdev_set_flag(const char *name, int flag)
0ad19a3f 358{
359 struct nl_handler nlh;
360 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 361 struct ifinfomsg *ifi;
3cfc0f3a 362 int index, len, err;
0ad19a3f 363
3cfc0f3a
MN
364 err = netlink_open(&nlh, NETLINK_ROUTE);
365 if (err)
366 return err;
0ad19a3f 367
3cfc0f3a 368 err = -EINVAL;
0ad19a3f 369 len = strlen(name);
dae3fdf6 370 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 371 goto out;
372
3cfc0f3a 373 err = -ENOMEM;
0ad19a3f 374 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
375 if (!nlmsg)
376 goto out;
377
06f976ca 378 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 379 if (!answer)
380 goto out;
381
3cfc0f3a 382 err = -EINVAL;
0ad19a3f 383 index = if_nametoindex(name);
384 if (!index)
385 goto out;
386
06f976ca
SZ
387 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
388 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
389
390 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
391 ifi->ifi_family = AF_UNSPEC;
392 ifi->ifi_index = index;
393 ifi->ifi_change |= IFF_UP;
394 ifi->ifi_flags |= flag;
0ad19a3f 395
396 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 397out:
398 netlink_close(&nlh);
399 nlmsg_free(nlmsg);
400 nlmsg_free(answer);
401 return err;
402}
403
efa1cf45
DY
404int netdev_get_flag(const char* name, int *flag)
405{
406 struct nl_handler nlh;
407 struct nlmsg *nlmsg = NULL, *answer = NULL;
a4318300 408 struct ifinfomsg *ifi;
06f976ca 409 int index, len, err;
efa1cf45
DY
410
411 if (!name)
412 return -EINVAL;
413
414 err = netlink_open(&nlh, NETLINK_ROUTE);
415 if (err)
416 return err;
417
418 err = -EINVAL;
419 len = strlen(name);
420 if (len == 1 || len >= IFNAMSIZ)
421 goto out;
422
423 err = -ENOMEM;
424 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
425 if (!nlmsg)
426 goto out;
427
06f976ca 428 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
efa1cf45
DY
429 if (!answer)
430 goto out;
431
432 err = -EINVAL;
433 index = if_nametoindex(name);
434 if (!index)
435 goto out;
436
06f976ca
SZ
437 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST;
438 nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
439
440 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
441 ifi->ifi_family = AF_UNSPEC;
442 ifi->ifi_index = index;
efa1cf45
DY
443
444 err = netlink_transaction(&nlh, nlmsg, answer);
445 if (err)
446 goto out;
447
06f976ca 448 ifi = NLMSG_DATA(answer->nlmsghdr);
efa1cf45
DY
449
450 *flag = ifi->ifi_flags;
451out:
452 netlink_close(&nlh);
453 nlmsg_free(nlmsg);
454 nlmsg_free(answer);
455 return err;
456}
457
458/*
459 * \brief Check a interface is up or not.
460 *
461 * \param name: name for the interface.
462 *
463 * \return int.
464 * 0 means interface is down.
465 * 1 means interface is up.
466 * Others means error happened, and ret-value is the error number.
467 */
468int lxc_netdev_isup(const char* name)
469{
470 int flag;
471 int err;
472
473 err = netdev_get_flag(name, &flag);
474 if (err)
475 goto out;
476 if (flag & IFF_UP)
477 return 1;
478 return 0;
479out:
480 return err;
481}
482
0130df54
SH
483int netdev_get_mtu(int ifindex)
484{
485 struct nl_handler nlh;
486 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 487 struct ifinfomsg *ifi;
0130df54
SH
488 struct nlmsghdr *msg;
489 int err, res;
490 int recv_len = 0, answer_len;
491 int readmore = 0;
492
493 err = netlink_open(&nlh, NETLINK_ROUTE);
494 if (err)
495 return err;
496
497 err = -ENOMEM;
498 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
499 if (!nlmsg)
500 goto out;
501
06f976ca 502 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0130df54
SH
503 if (!answer)
504 goto out;
505
506 /* Save the answer buffer length, since it will be overwritten
507 * on the first receive (and we might need to receive more than
508 * once. */
06f976ca
SZ
509 answer_len = answer->nlmsghdr->nlmsg_len;
510
511 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
512 nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
0130df54 513
06f976ca
SZ
514 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
515 ifi->ifi_family = AF_UNSPEC;
0130df54
SH
516
517 /* Send the request for addresses, which returns all addresses
518 * on all interfaces. */
519 err = netlink_send(&nlh, nlmsg);
520 if (err < 0)
521 goto out;
522
523 do {
524 /* Restore the answer buffer length, it might have been
525 * overwritten by a previous receive. */
06f976ca 526 answer->nlmsghdr->nlmsg_len = answer_len;
0130df54
SH
527
528 /* Get the (next) batch of reply messages */
529 err = netlink_rcv(&nlh, answer);
530 if (err < 0)
531 goto out;
532
533 recv_len = err;
534 err = 0;
535
536 /* Satisfy the typing for the netlink macros */
06f976ca 537 msg = answer->nlmsghdr;
0130df54
SH
538
539 while (NLMSG_OK(msg, recv_len)) {
540
541 /* Stop reading if we see an error message */
542 if (msg->nlmsg_type == NLMSG_ERROR) {
543 struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg);
544 err = errmsg->error;
545 goto out;
546 }
547
548 /* Stop reading if we see a NLMSG_DONE message */
549 if (msg->nlmsg_type == NLMSG_DONE) {
550 readmore = 0;
551 break;
552 }
553
06f976ca 554 ifi = NLMSG_DATA(msg);
0130df54
SH
555 if (ifi->ifi_index == ifindex) {
556 struct rtattr *rta = IFLA_RTA(ifi);
557 int attr_len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
558 res = 0;
559 while(RTA_OK(rta, attr_len)) {
560 /* Found a local address for the requested interface,
561 * return it. */
562 if (rta->rta_type == IFLA_MTU) {
563 memcpy(&res, RTA_DATA(rta), sizeof(int));
564 err = res;
565 goto out;
566 }
567 rta = RTA_NEXT(rta, attr_len);
568 }
569
570 }
571
572 /* Keep reading more data from the socket if the
573 * last message had the NLF_F_MULTI flag set */
574 readmore = (msg->nlmsg_flags & NLM_F_MULTI);
575
576 /* Look at the next message received in this buffer */
577 msg = NLMSG_NEXT(msg, recv_len);
578 }
579 } while (readmore);
580
581 /* If we end up here, we didn't find any result, so signal an
582 * error */
583 err = -1;
584
585out:
586 netlink_close(&nlh);
587 nlmsg_free(answer);
588 nlmsg_free(nlmsg);
589 return err;
590}
591
d472214b 592int lxc_netdev_set_mtu(const char *name, int mtu)
75d09f83
DL
593{
594 struct nl_handler nlh;
595 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 596 struct ifinfomsg *ifi;
3cfc0f3a 597 int index, len, err;
75d09f83 598
3cfc0f3a
MN
599 err = netlink_open(&nlh, NETLINK_ROUTE);
600 if (err)
601 return err;
75d09f83 602
3cfc0f3a 603 err = -EINVAL;
75d09f83 604 len = strlen(name);
dae3fdf6 605 if (len == 1 || len >= IFNAMSIZ)
75d09f83
DL
606 goto out;
607
3cfc0f3a 608 err = -ENOMEM;
75d09f83
DL
609 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
610 if (!nlmsg)
611 goto out;
612
06f976ca 613 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
75d09f83
DL
614 if (!answer)
615 goto out;
616
3cfc0f3a 617 err = -EINVAL;
75d09f83
DL
618 index = if_nametoindex(name);
619 if (!index)
620 goto out;
621
06f976ca
SZ
622 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
623 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
624
625 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
626 ifi->ifi_family = AF_UNSPEC;
627 ifi->ifi_index = index;
75d09f83
DL
628
629 if (nla_put_u32(nlmsg, IFLA_MTU, mtu))
630 goto out;
631
632 err = netlink_transaction(&nlh, nlmsg, answer);
75d09f83
DL
633out:
634 netlink_close(&nlh);
635 nlmsg_free(nlmsg);
636 nlmsg_free(answer);
637 return err;
638}
639
d472214b 640int lxc_netdev_up(const char *name)
0ad19a3f 641{
d472214b 642 return netdev_set_flag(name, IFF_UP);
0ad19a3f 643}
644
d472214b 645int lxc_netdev_down(const char *name)
0ad19a3f 646{
d472214b 647 return netdev_set_flag(name, 0);
0ad19a3f 648}
649
497353b6 650int lxc_veth_create(const char *name1, const char *name2)
0ad19a3f 651{
652 struct nl_handler nlh;
653 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 654 struct ifinfomsg *ifi;
0ad19a3f 655 struct rtattr *nest1, *nest2, *nest3;
3cfc0f3a 656 int len, err;
0ad19a3f 657
3cfc0f3a
MN
658 err = netlink_open(&nlh, NETLINK_ROUTE);
659 if (err)
660 return err;
0ad19a3f 661
3cfc0f3a 662 err = -EINVAL;
0ad19a3f 663 len = strlen(name1);
dae3fdf6 664 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 665 goto out;
666
667 len = strlen(name2);
dae3fdf6 668 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 669 goto out;
670
3cfc0f3a 671 err = -ENOMEM;
0ad19a3f 672 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
673 if (!nlmsg)
674 goto out;
675
06f976ca 676 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 677 if (!answer)
678 goto out;
679
06f976ca 680 nlmsg->nlmsghdr->nlmsg_flags =
0ad19a3f 681 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
06f976ca
SZ
682 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
683
684 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
685 ifi->ifi_family = AF_UNSPEC;
0ad19a3f 686
3cfc0f3a 687 err = -EINVAL;
79e68309 688 nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
0ad19a3f 689 if (!nest1)
690 goto out;
691
692 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
693 goto out;
694
695 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
696 if (!nest2)
697 goto out;
698
699 nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
700 if (!nest3)
701 goto out;
702
06f976ca
SZ
703 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
704 if (!ifi)
705 goto out;
0ad19a3f 706
707 if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
708 goto out;
709
710 nla_end_nested(nlmsg, nest3);
711
712 nla_end_nested(nlmsg, nest2);
713
714 nla_end_nested(nlmsg, nest1);
715
716 if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
717 goto out;
718
3cfc0f3a 719 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 720out:
721 netlink_close(&nlh);
722 nlmsg_free(answer);
723 nlmsg_free(nlmsg);
724 return err;
725}
726
26c39028 727/* XXX: merge with lxc_macvlan_create */
7c11d57a 728int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid)
26c39028
JHS
729{
730 struct nl_handler nlh;
731 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 732 struct ifinfomsg *ifi;
26c39028 733 struct rtattr *nest, *nest2;
3cfc0f3a 734 int lindex, len, err;
26c39028 735
3cfc0f3a
MN
736 err = netlink_open(&nlh, NETLINK_ROUTE);
737 if (err)
738 return err;
26c39028 739
3cfc0f3a 740 err = -EINVAL;
26c39028 741 len = strlen(master);
dae3fdf6 742 if (len == 1 || len >= IFNAMSIZ)
26c39028
JHS
743 goto err3;
744
745 len = strlen(name);
dae3fdf6 746 if (len == 1 || len >= IFNAMSIZ)
26c39028
JHS
747 goto err3;
748
3cfc0f3a 749 err = -ENOMEM;
26c39028
JHS
750 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
751 if (!nlmsg)
752 goto err3;
753
06f976ca 754 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
26c39028
JHS
755 if (!answer)
756 goto err2;
757
3cfc0f3a 758 err = -EINVAL;
26c39028
JHS
759 lindex = if_nametoindex(master);
760 if (!lindex)
761 goto err1;
762
06f976ca 763 nlmsg->nlmsghdr->nlmsg_flags =
26c39028 764 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
06f976ca
SZ
765 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
766
767 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
768 ifi->ifi_family = AF_UNSPEC;
26c39028 769
79e68309 770 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
26c39028
JHS
771 if (!nest)
772 goto err1;
773
774 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "vlan"))
775 goto err1;
776
777 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
778 if (!nest2)
779 goto err1;
e892973e 780
26c39028
JHS
781 if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid))
782 goto err1;
e892973e 783
26c39028
JHS
784 nla_end_nested(nlmsg, nest2);
785
786 nla_end_nested(nlmsg, nest);
787
788 if (nla_put_u32(nlmsg, IFLA_LINK, lindex))
789 goto err1;
790
791 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
792 goto err1;
793
3cfc0f3a 794 err = netlink_transaction(&nlh, nlmsg, answer);
26c39028
JHS
795err1:
796 nlmsg_free(answer);
797err2:
798 nlmsg_free(nlmsg);
799err3:
800 netlink_close(&nlh);
801 return err;
802}
803
e892973e 804int lxc_macvlan_create(const char *master, const char *name, int mode)
0ad19a3f 805{
806 struct nl_handler nlh;
807 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 808 struct ifinfomsg *ifi;
e892973e 809 struct rtattr *nest, *nest2;
3cfc0f3a 810 int index, len, err;
0ad19a3f 811
3cfc0f3a
MN
812 err = netlink_open(&nlh, NETLINK_ROUTE);
813 if (err)
814 return err;
0ad19a3f 815
3cfc0f3a 816 err = -EINVAL;
0ad19a3f 817 len = strlen(master);
dae3fdf6 818 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 819 goto out;
820
821 len = strlen(name);
dae3fdf6 822 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 823 goto out;
824
3cfc0f3a 825 err = -ENOMEM;
0ad19a3f 826 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
827 if (!nlmsg)
828 goto out;
829
06f976ca 830 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 831 if (!answer)
832 goto out;
833
3cfc0f3a 834 err = -EINVAL;
0ad19a3f 835 index = if_nametoindex(master);
836 if (!index)
837 goto out;
838
06f976ca 839 nlmsg->nlmsghdr->nlmsg_flags =
0ad19a3f 840 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
06f976ca
SZ
841 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
842
843 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
844 ifi->ifi_family = AF_UNSPEC;
0ad19a3f 845
79e68309 846 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
0ad19a3f 847 if (!nest)
848 goto out;
849
850 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan"))
851 goto out;
852
e892973e
DL
853 if (mode) {
854 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
855 if (!nest2)
856 goto out;
857
858 if (nla_put_u32(nlmsg, IFLA_MACVLAN_MODE, mode))
859 goto out;
860
861 nla_end_nested(nlmsg, nest2);
862 }
863
0ad19a3f 864 nla_end_nested(nlmsg, nest);
865
866 if (nla_put_u32(nlmsg, IFLA_LINK, index))
867 goto out;
868
869 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
870 goto out;
871
3cfc0f3a 872 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 873out:
874 netlink_close(&nlh);
875 nlmsg_free(answer);
876 nlmsg_free(nlmsg);
877 return err;
878}
879
880static int proc_sys_net_write(const char *path, const char *value)
881{
882 int fd, err = 0;
883
884 fd = open(path, O_WRONLY);
885 if (fd < 0)
886 return -errno;
887
888 if (write(fd, value, strlen(value)) < 0)
889 err = -errno;
890
891 close(fd);
892 return err;
893}
894
895static int ip_forward_set(const char *ifname, int family, int flag)
896{
22ebac19 897 char path[MAXPATHLEN];
9ba8130c 898 int rc;
0ad19a3f 899
900 if (family != AF_INET && family != AF_INET6)
3cfc0f3a 901 return -EINVAL;
0ad19a3f 902
9ba8130c 903 rc = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/forwarding",
0ad19a3f 904 family == AF_INET?"ipv4":"ipv6" , ifname);
9ba8130c
SH
905 if (rc >= MAXPATHLEN)
906 return -E2BIG;
0ad19a3f 907
22ebac19 908 return proc_sys_net_write(path, flag?"1":"0");
0ad19a3f 909}
910
497353b6 911int lxc_ip_forward_on(const char *ifname, int family)
0ad19a3f 912{
913 return ip_forward_set(ifname, family, 1);
914}
915
497353b6 916int lxc_ip_forward_off(const char *ifname, int family)
0ad19a3f 917{
918 return ip_forward_set(ifname, family, 0);
919}
920
921static int neigh_proxy_set(const char *ifname, int family, int flag)
922{
923 char path[MAXPATHLEN];
9ba8130c 924 int ret;
0ad19a3f 925
926 if (family != AF_INET && family != AF_INET6)
3cfc0f3a 927 return -EINVAL;
0ad19a3f 928
9ba8130c 929 ret = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/%s",
79e68309 930 family == AF_INET?"ipv4":"ipv6" , ifname,
0ad19a3f 931 family == AF_INET?"proxy_arp":"proxy_ndp");
9ba8130c
SH
932 if (ret < 0 || ret >= MAXPATHLEN)
933 return -E2BIG;
0ad19a3f 934
935 return proc_sys_net_write(path, flag?"1":"0");
936}
937
497353b6 938int lxc_neigh_proxy_on(const char *name, int family)
0ad19a3f 939{
940 return neigh_proxy_set(name, family, 1);
941}
942
497353b6 943int lxc_neigh_proxy_off(const char *name, int family)
0ad19a3f 944{
945 return neigh_proxy_set(name, family, 0);
946}
947
948int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr)
949{
1f1b18e7
DL
950 unsigned char *data;
951 char c;
952 int i = 0;
953 unsigned val;
954
955 sockaddr->sa_family = ARPHRD_ETHER;
956 data = (unsigned char *)sockaddr->sa_data;
957
958 while ((*macaddr != '\0') && (i < ETH_ALEN)) {
959 val = 0;
960 c = *macaddr++;
961 if (isdigit(c))
962 val = c - '0';
963 else if (c >= 'a' && c <= 'f')
964 val = c - 'a' + 10;
965 else if (c >= 'A' && c <= 'F')
966 val = c - 'A' + 10;
967 else {
968 return -EINVAL;
969 }
970 val <<= 4;
971 c = *macaddr;
972 if (isdigit(c))
973 val |= c - '0';
974 else if (c >= 'a' && c <= 'f')
975 val |= c - 'a' + 10;
976 else if (c >= 'A' && c <= 'F')
977 val |= c - 'A' + 10;
978 else if (c == ':' || c == 0)
979 val >>= 4;
980 else {
981 return -EINVAL;
982 }
983 if (c != 0)
984 macaddr++;
985 *data++ = (unsigned char) (val & 0377);
986 i++;
987
988 if (*macaddr == ':')
989 macaddr++;
0ad19a3f 990 }
0ad19a3f 991
1f1b18e7 992 return 0;
0ad19a3f 993}
994
1f1b18e7
DL
995static int ip_addr_add(int family, int ifindex,
996 void *addr, void *bcast, void *acast, int prefix)
0ad19a3f 997{
998 struct nl_handler nlh;
0ad19a3f 999 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 1000 struct ifaddrmsg *ifa;
4bf1968d 1001 int addrlen;
3cfc0f3a 1002 int err;
0ad19a3f 1003
4bf1968d
DL
1004 addrlen = family == AF_INET ? sizeof(struct in_addr) :
1005 sizeof(struct in6_addr);
1006
3cfc0f3a
MN
1007 err = netlink_open(&nlh, NETLINK_ROUTE);
1008 if (err)
1009 return err;
0ad19a3f 1010
3cfc0f3a 1011 err = -ENOMEM;
0ad19a3f 1012 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1013 if (!nlmsg)
1014 goto out;
1015
06f976ca 1016 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 1017 if (!answer)
1018 goto out;
1019
06f976ca 1020 nlmsg->nlmsghdr->nlmsg_flags =
0ad19a3f 1021 NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
06f976ca
SZ
1022 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWADDR;
1023
1024 ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
1025 ifa->ifa_prefixlen = prefix;
1026 ifa->ifa_index = ifindex;
1027 ifa->ifa_family = family;
1028 ifa->ifa_scope = 0;
0ad19a3f 1029
3cfc0f3a 1030 err = -EINVAL;
4bf1968d 1031 if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen))
0ad19a3f 1032 goto out;
1033
4bf1968d 1034 if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen))
0ad19a3f 1035 goto out;
1036
d8948a52 1037 if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen))
1f1b18e7
DL
1038 goto out;
1039
1040 /* TODO : multicast, anycast with ipv6 */
7ddc8f24 1041 err = -EPROTONOSUPPORT;
79881dc6
DL
1042 if (family == AF_INET6 &&
1043 (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) ||
1044 memcmp(acast, &in6addr_any, sizeof(in6addr_any))))
1f1b18e7 1045 goto out;
0ad19a3f 1046
3cfc0f3a 1047 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 1048out:
1049 netlink_close(&nlh);
1050 nlmsg_free(answer);
1051 nlmsg_free(nlmsg);
1052 return err;
1053}
1054
1f1b18e7
DL
1055int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr,
1056 struct in6_addr *mcast,
1057 struct in6_addr *acast, int prefix)
1058{
1059 return ip_addr_add(AF_INET6, ifindex, addr, mcast, acast, prefix);
1060}
1061
1062int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
1063 struct in_addr *bcast, int prefix)
1064{
1065 return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix);
1066}
1067
19a26f82
MK
1068/* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present)
1069 * address from the given RTM_NEWADDR message. Allocates memory for the
1070 * address and stores that pointer in *res (so res should be an
1071 * in_addr** or in6_addr**).
1072 */
06f976ca
SZ
1073static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void** res) {
1074 struct ifaddrmsg *ifa = NLMSG_DATA(msg);
1075 struct rtattr *rta = IFA_RTA(ifa);
1076 int attr_len = NLMSG_PAYLOAD(msg, sizeof(struct ifaddrmsg));
19a26f82
MK
1077 int addrlen;
1078
06f976ca 1079 if (ifa->ifa_family != family)
19a26f82
MK
1080 return 0;
1081
1082 addrlen = family == AF_INET ? sizeof(struct in_addr) :
1083 sizeof(struct in6_addr);
1084
1085 /* Loop over the rtattr's in this message */
1086 while(RTA_OK(rta, attr_len)) {
1087 /* Found a local address for the requested interface,
1088 * return it. */
1089 if (rta->rta_type == IFA_LOCAL || rta->rta_type == IFA_ADDRESS) {
1090 /* Sanity check. The family check above should
1091 * make sure the address length is correct, but
1092 * check here just in case */
1093 if (RTA_PAYLOAD(rta) != addrlen)
1094 return -1;
1095
1096 /* We might have found an IFA_ADDRESS before,
1097 * which we now overwrite with an IFA_LOCAL. */
dd66e5ad 1098 if (!*res) {
19a26f82 1099 *res = malloc(addrlen);
dd66e5ad
DE
1100 if (!*res)
1101 return -1;
1102 }
19a26f82
MK
1103
1104 memcpy(*res, RTA_DATA(rta), addrlen);
1105
1106 if (rta->rta_type == IFA_LOCAL)
1107 break;
1108 }
1109 rta = RTA_NEXT(rta, attr_len);
1110 }
1111 return 0;
1112}
1113
1114static int ip_addr_get(int family, int ifindex, void **res)
1115{
1116 struct nl_handler nlh;
1117 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 1118 struct ifaddrmsg *ifa;
19a26f82
MK
1119 struct nlmsghdr *msg;
1120 int err;
1121 int recv_len = 0, answer_len;
1122 int readmore = 0;
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
06f976ca 1133 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
19a26f82
MK
1134 if (!answer)
1135 goto out;
1136
1137 /* Save the answer buffer length, since it will be overwritten
1138 * on the first receive (and we might need to receive more than
1139 * once. */
06f976ca
SZ
1140 answer_len = answer->nlmsghdr->nlmsg_len;
1141
1142 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT;
1143 nlmsg->nlmsghdr->nlmsg_type = RTM_GETADDR;
19a26f82 1144
06f976ca
SZ
1145 ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
1146 ifa->ifa_family = family;
19a26f82
MK
1147
1148 /* Send the request for addresses, which returns all addresses
1149 * on all interfaces. */
1150 err = netlink_send(&nlh, nlmsg);
1151 if (err < 0)
1152 goto out;
19a26f82
MK
1153
1154 do {
1155 /* Restore the answer buffer length, it might have been
1156 * overwritten by a previous receive. */
06f976ca 1157 answer->nlmsghdr->nlmsg_len = answer_len;
19a26f82
MK
1158
1159 /* Get the (next) batch of reply messages */
1160 err = netlink_rcv(&nlh, answer);
1161 if (err < 0)
1162 goto out;
1163
1164 recv_len = err;
1165 err = 0;
1166
1167 /* Satisfy the typing for the netlink macros */
06f976ca 1168 msg = answer->nlmsghdr;
19a26f82
MK
1169
1170 while (NLMSG_OK(msg, recv_len)) {
1171 /* Stop reading if we see an error message */
1172 if (msg->nlmsg_type == NLMSG_ERROR) {
1173 struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg);
1174 err = errmsg->error;
1175 goto out;
1176 }
1177
1178 /* Stop reading if we see a NLMSG_DONE message */
1179 if (msg->nlmsg_type == NLMSG_DONE) {
1180 readmore = 0;
1181 break;
1182 }
1183
1184 if (msg->nlmsg_type != RTM_NEWADDR) {
1185 err = -1;
1186 goto out;
1187 }
1188
06f976ca
SZ
1189 ifa = (struct ifaddrmsg *)NLMSG_DATA(msg);
1190 if (ifa->ifa_index == ifindex) {
1191 if (ifa_get_local_ip(family, msg, res) < 0) {
51e7a874
SG
1192 err = -1;
1193 goto out;
1194 }
1195
19a26f82
MK
1196 /* Found a result, stop searching */
1197 if (*res)
1198 goto out;
1199 }
1200
1201 /* Keep reading more data from the socket if the
1202 * last message had the NLF_F_MULTI flag set */
1203 readmore = (msg->nlmsg_flags & NLM_F_MULTI);
1204
1205 /* Look at the next message received in this buffer */
1206 msg = NLMSG_NEXT(msg, recv_len);
1207 }
1208 } while (readmore);
1209
1210 /* If we end up here, we didn't find any result, so signal an
1211 * error */
1212 err = -1;
1213
1214out:
1215 netlink_close(&nlh);
1216 nlmsg_free(answer);
1217 nlmsg_free(nlmsg);
1218 return err;
1219}
1220
1221int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res)
1222{
1223 return ip_addr_get(AF_INET6, ifindex, (void**)res);
1224}
1225
1226int lxc_ipv4_addr_get(int ifindex, struct in_addr** res)
1227{
1228 return ip_addr_get(AF_INET, ifindex, (void**)res);
1229}
1230
f8fee0e2
MK
1231static int ip_gateway_add(int family, int ifindex, void *gw)
1232{
1233 struct nl_handler nlh;
1234 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 1235 struct rtmsg *rt;
f8fee0e2
MK
1236 int addrlen;
1237 int err;
1238
1239 addrlen = family == AF_INET ? sizeof(struct in_addr) :
1240 sizeof(struct in6_addr);
1241
1242 err = netlink_open(&nlh, NETLINK_ROUTE);
1243 if (err)
1244 return err;
1245
1246 err = -ENOMEM;
1247 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1248 if (!nlmsg)
1249 goto out;
1250
06f976ca 1251 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
f8fee0e2
MK
1252 if (!answer)
1253 goto out;
1254
06f976ca 1255 nlmsg->nlmsghdr->nlmsg_flags =
f8fee0e2 1256 NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
06f976ca
SZ
1257 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE;
1258
1259 rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
1260 rt->rtm_family = family;
1261 rt->rtm_table = RT_TABLE_MAIN;
1262 rt->rtm_scope = RT_SCOPE_UNIVERSE;
1263 rt->rtm_protocol = RTPROT_BOOT;
1264 rt->rtm_type = RTN_UNICAST;
f8fee0e2 1265 /* "default" destination */
06f976ca 1266 rt->rtm_dst_len = 0;
f8fee0e2
MK
1267
1268 err = -EINVAL;
1269 if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
1270 goto out;
1271
1272 /* Adding the interface index enables the use of link-local
1273 * addresses for the gateway */
1274 if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
1275 goto out;
1276
1277 err = netlink_transaction(&nlh, nlmsg, answer);
1278out:
1279 netlink_close(&nlh);
1280 nlmsg_free(answer);
1281 nlmsg_free(nlmsg);
1282 return err;
1283}
1284
1285int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw)
1286{
1287 return ip_gateway_add(AF_INET, ifindex, gw);
1288}
1289
1290int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw)
1291{
1292 return ip_gateway_add(AF_INET6, ifindex, gw);
1293}
1294
77dcf03a
GL
1295static int ip_route_dest_add(int family, int ifindex, void *dest)
1296{
1297 struct nl_handler nlh;
1298 struct nlmsg *nlmsg = NULL, *answer = NULL;
06f976ca 1299 struct rtmsg *rt;
77dcf03a
GL
1300 int addrlen;
1301 int err;
1302
1303 addrlen = family == AF_INET ? sizeof(struct in_addr) :
1304 sizeof(struct in6_addr);
1305
1306 err = netlink_open(&nlh, NETLINK_ROUTE);
1307 if (err)
1308 return err;
1309
1310 err = -ENOMEM;
1311 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1312 if (!nlmsg)
1313 goto out;
1314
06f976ca 1315 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
77dcf03a
GL
1316 if (!answer)
1317 goto out;
1318
06f976ca 1319 nlmsg->nlmsghdr->nlmsg_flags =
77dcf03a 1320 NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
06f976ca
SZ
1321 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE;
1322
1323 rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
1324 rt->rtm_family = family;
1325 rt->rtm_table = RT_TABLE_MAIN;
1326 rt->rtm_scope = RT_SCOPE_LINK;
1327 rt->rtm_protocol = RTPROT_BOOT;
1328 rt->rtm_type = RTN_UNICAST;
1329 rt->rtm_dst_len = addrlen*8;
77dcf03a
GL
1330
1331 err = -EINVAL;
1332 if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen))
1333 goto out;
1334 if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
1335 goto out;
1336 err = netlink_transaction(&nlh, nlmsg, answer);
1337out:
1338 netlink_close(&nlh);
1339 nlmsg_free(answer);
1340 nlmsg_free(nlmsg);
1341 return err;
1342}
1343
1344int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest)
1345{
1346 return ip_route_dest_add(AF_INET, ifindex, dest);
1347}
1348
1349int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest)
1350{
1351 return ip_route_dest_add(AF_INET6, ifindex, dest);
1352}
1353
0d204771
SH
1354static bool is_ovs_bridge(const char *bridge)
1355{
1356 char brdirname[22 + IFNAMSIZ + 1] = {0};
1357 struct stat sb;
1358
1359 snprintf(brdirname, 22 +IFNAMSIZ + 1, "/sys/class/net/%s/bridge", bridge);
1360 if (stat(brdirname, &sb) == -1 && errno == ENOENT)
1361 return true;
1362 return false;
1363}
1364
1365static int attach_to_ovs_bridge(const char *bridge, const char *nic)
1366{
1367 pid_t pid;
6ad22d06
SH
1368 char *cmd;
1369
1370 cmd = on_path("ovs-vsctl", NULL);
1371 if (!cmd)
1372 return -1;
1373 free(cmd);
0d204771
SH
1374
1375 pid = fork();
1376 if (pid < 0)
1377 return -1;
1378 if (pid > 0)
1379 return wait_for_pid(pid);
1380
6ad22d06 1381 if (execlp("ovs-vsctl", "ovs-vsctl", "add-port", bridge, nic, NULL))
0d204771
SH
1382 exit(1);
1383 // not reached
1384 exit(1);
1385}
0d204771 1386
7d163508
MN
1387/*
1388 * There is a lxc_bridge_attach, but no need of a bridge detach
d472214b 1389 * as automatically done by kernel when a netdev is deleted.
7d163508
MN
1390 */
1391int lxc_bridge_attach(const char *bridge, const char *ifname)
0ad19a3f 1392{
1393 int fd, index, err;
1394 struct ifreq ifr;
1395
dae3fdf6 1396 if (strlen(ifname) >= IFNAMSIZ)
3cfc0f3a 1397 return -EINVAL;
0ad19a3f 1398
1399 index = if_nametoindex(ifname);
1400 if (!index)
3cfc0f3a 1401 return -EINVAL;
0ad19a3f 1402
0d204771
SH
1403 if (is_ovs_bridge(bridge))
1404 return attach_to_ovs_bridge(bridge, ifname);
1405
0ad19a3f 1406 fd = socket(AF_INET, SOCK_STREAM, 0);
1407 if (fd < 0)
3cfc0f3a 1408 return -errno;
0ad19a3f 1409
5da6aa8c
DE
1410 strncpy(ifr.ifr_name, bridge, IFNAMSIZ-1);
1411 ifr.ifr_name[IFNAMSIZ-1] = '\0';
0ad19a3f 1412 ifr.ifr_ifindex = index;
7d163508 1413 err = ioctl(fd, SIOCBRADDIF, &ifr);
0ad19a3f 1414 close(fd);
3cfc0f3a
MN
1415 if (err)
1416 err = -errno;
0ad19a3f 1417
1418 return err;
1419}
72d0e1cb 1420
74a3920a 1421static const char* const lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
b343592b 1422 [LXC_NET_EMPTY] = "empty",
72d0e1cb
SG
1423 [LXC_NET_VETH] = "veth",
1424 [LXC_NET_MACVLAN] = "macvlan",
72d0e1cb 1425 [LXC_NET_PHYS] = "phys",
b343592b
BP
1426 [LXC_NET_VLAN] = "vlan",
1427 [LXC_NET_NONE] = "none",
72d0e1cb
SG
1428};
1429
1430const char *lxc_net_type_to_str(int type)
1431{
1432 if (type < 0 || type > LXC_NET_MAXCONFTYPE)
1433 return NULL;
1434 return lxc_network_types[type];
1435}
8befa924 1436
74a3920a 1437static const char padchar[] =
a0265685
SG
1438"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1439
1440char *lxc_mkifname(char *template)
1441{
1442 char *name = NULL;
1443 int i = 0;
1444 FILE *urandom;
1445 unsigned int seed;
1446 struct ifaddrs *ifaddr, *ifa;
1447 int ifexists = 0;
1448
1449 /* Get all the network interfaces */
1450 getifaddrs(&ifaddr);
1451
1452 /* Initialize the random number generator */
a0265685 1453 urandom = fopen ("/dev/urandom", "r");
a0265685
SG
1454 if (urandom != NULL) {
1455 if (fread (&seed, sizeof(seed), 1, urandom) <= 0)
1456 seed = time(0);
a0265685 1457 fclose(urandom);
a0265685
SG
1458 }
1459 else
1460 seed = time(0);
1461
1462#ifndef HAVE_RAND_R
1463 srand(seed);
1464#endif
1465
1466 /* Generate random names until we find one that doesn't exist */
1467 while(1) {
1468 ifexists = 0;
1469 name = strdup(template);
1470
1471 if (name == NULL)
1472 return NULL;
1473
1474 for (i = 0; i < strlen(name); i++) {
1475 if (name[i] == 'X') {
1476#ifdef HAVE_RAND_R
1477 name[i] = padchar[rand_r(&seed) % (strlen(padchar) - 1)];
1478#else
1479 name[i] = padchar[rand() % (strlen(padchar) - 1)];
1480#endif
1481 }
1482 }
1483
1484 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
1485 if (strcmp(ifa->ifa_name, name) == 0) {
1486 ifexists = 1;
1487 break;
1488 }
1489 }
1490
1491 if (ifexists == 0)
1492 break;
1493
1494 free(name);
1495 }
1496
1497 freeifaddrs(ifaddr);
1498 return name;
1499}
1500
8befa924
SH
1501int setup_private_host_hw_addr(char *veth1)
1502{
1503 struct ifreq ifr;
1504 int err;
1505 int sockfd;
1506
8befa924 1507 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
8befa924
SH
1508 if (sockfd < 0)
1509 return -errno;
1510
1511 snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
1512 err = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
1513 if (err < 0) {
8befa924 1514 close(sockfd);
8befa924
SH
1515 return -errno;
1516 }
1517
1518 ifr.ifr_hwaddr.sa_data[0] = 0xfe;
1519 err = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
8befa924 1520 close(sockfd);
8befa924
SH
1521 if (err < 0)
1522 return -errno;
1523
1524 return 0;
1525}