]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/network.c
ubuntu: iproute is now called iproute2
[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
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/socket.h>
36#include <sys/param.h>
37#include <sys/ioctl.h>
38#include <arpa/inet.h>
39#include <net/if.h>
40#include <net/if_arp.h>
41#include <net/ethernet.h>
42#include <netinet/in.h>
43#include <linux/netlink.h>
44#include <linux/rtnetlink.h>
45#include <linux/sockios.h>
46#include <linux/if_bridge.h>
f549edcc
GK
47
48#include "nl.h"
49#include "network.h"
72d0e1cb 50#include "conf.h"
0ad19a3f 51
52#ifndef IFLA_LINKMODE
53# define IFLA_LINKMODE 17
54#endif
55
56#ifndef IFLA_LINKINFO
57# define IFLA_LINKINFO 18
58#endif
59
60#ifndef IFLA_NET_NS_PID
61# define IFLA_NET_NS_PID 19
62#endif
63
64#ifndef IFLA_INFO_KIND
65# define IFLA_INFO_KIND 1
66#endif
67
26c39028
JHS
68#ifndef IFLA_VLAN_ID
69# define IFLA_VLAN_ID 1
70#endif
71
0ad19a3f 72#ifndef IFLA_INFO_DATA
73# define IFLA_INFO_DATA 2
74#endif
75
76#ifndef VETH_INFO_PEER
77# define VETH_INFO_PEER 1
78#endif
79
e892973e
DL
80#ifndef IFLA_MACVLAN_MODE
81# define IFLA_MACVLAN_MODE 1
82#endif
83
0ad19a3f 84struct link_req {
85 struct nlmsg nlmsg;
86 struct ifinfomsg ifinfomsg;
87};
88
89struct ip_req {
90 struct nlmsg nlmsg;
91 struct ifaddrmsg ifa;
92};
93
f8fee0e2
MK
94struct rt_req {
95 struct nlmsg nlmsg;
96 struct rtmsg rt;
97};
98
d472214b 99int lxc_netdev_move_by_index(int ifindex, pid_t pid)
0ad19a3f 100{
101 struct nl_handler nlh;
102 struct nlmsg *nlmsg = NULL;
103 struct link_req *link_req;
3cfc0f3a 104 int err;
0ad19a3f 105
3cfc0f3a
MN
106 err = netlink_open(&nlh, NETLINK_ROUTE);
107 if (err)
108 return err;
0ad19a3f 109
3cfc0f3a 110 err = -ENOMEM;
0ad19a3f 111 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
112 if (!nlmsg)
113 goto out;
114
0ad19a3f 115 link_req = (struct link_req *)nlmsg;
116 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
82d5ae15 117 link_req->ifinfomsg.ifi_index = ifindex;
0ad19a3f 118 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
119 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
120 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
121
122 if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
123 goto out;
124
3cfc0f3a 125 err = netlink_transaction(&nlh, nlmsg, nlmsg);
0ad19a3f 126out:
127 netlink_close(&nlh);
128 nlmsg_free(nlmsg);
129 return err;
130}
131
b84f58b9 132int lxc_netdev_delete_by_index(int ifindex)
0ad19a3f 133{
134 struct nl_handler nlh;
135 struct nlmsg *nlmsg = NULL, *answer = NULL;
136 struct link_req *link_req;
b84f58b9 137 int err;
0ad19a3f 138
3cfc0f3a
MN
139 err = netlink_open(&nlh, NETLINK_ROUTE);
140 if (err)
141 return err;
0ad19a3f 142
3cfc0f3a 143 err = -ENOMEM;
0ad19a3f 144 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
145 if (!nlmsg)
146 goto out;
147
148 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
149 if (!answer)
150 goto out;
151
0ad19a3f 152 link_req = (struct link_req *)nlmsg;
153 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
b84f58b9 154 link_req->ifinfomsg.ifi_index = ifindex;
0ad19a3f 155 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
156 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
157 nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK;
158
3cfc0f3a 159 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 160out:
161 netlink_close(&nlh);
162 nlmsg_free(answer);
163 nlmsg_free(nlmsg);
164 return err;
165}
166
b84f58b9
DL
167int lxc_netdev_delete_by_name(const char *name)
168{
169 int index;
170
171 index = if_nametoindex(name);
172 if (!index)
173 return -EINVAL;
174
175 return lxc_netdev_delete_by_index(index);
176}
177
178int lxc_netdev_rename_by_index(int ifindex, const char *newname)
b9a5bb58
DL
179{
180 struct nl_handler nlh;
181 struct nlmsg *nlmsg = NULL, *answer = NULL;
182 struct link_req *link_req;
b84f58b9 183 int len, err;
b9a5bb58 184
3cfc0f3a
MN
185 err = netlink_open(&nlh, NETLINK_ROUTE);
186 if (err)
187 return err;
b9a5bb58 188
b84f58b9 189 len = strlen(newname);
dae3fdf6 190 if (len == 1 || len >= IFNAMSIZ)
b84f58b9
DL
191 goto out;
192
3cfc0f3a 193 err = -ENOMEM;
b9a5bb58
DL
194 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
195 if (!nlmsg)
196 goto out;
197
198 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
199 if (!answer)
200 goto out;
201
202 link_req = (struct link_req *)nlmsg;
203 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
204 link_req->ifinfomsg.ifi_index = ifindex;
205 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
206 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
b84f58b9
DL
207 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
208
209 if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
210 goto out;
b9a5bb58 211
3cfc0f3a 212 err = netlink_transaction(&nlh, nlmsg, answer);
b9a5bb58
DL
213out:
214 netlink_close(&nlh);
215 nlmsg_free(answer);
216 nlmsg_free(nlmsg);
217 return err;
218}
219
b84f58b9
DL
220int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
221{
222 int len, index;
223
224 len = strlen(oldname);
dae3fdf6 225 if (len == 1 || len >= IFNAMSIZ)
b84f58b9
DL
226 return -EINVAL;
227
228 index = if_nametoindex(oldname);
229 if (!index)
230 return -EINVAL;
231
232 return lxc_netdev_rename_by_index(index, newname);
233}
234
d472214b 235static int netdev_set_flag(const char *name, int flag)
0ad19a3f 236{
237 struct nl_handler nlh;
238 struct nlmsg *nlmsg = NULL, *answer = NULL;
239 struct link_req *link_req;
3cfc0f3a 240 int index, len, err;
0ad19a3f 241
3cfc0f3a
MN
242 err = netlink_open(&nlh, NETLINK_ROUTE);
243 if (err)
244 return err;
0ad19a3f 245
3cfc0f3a 246 err = -EINVAL;
0ad19a3f 247 len = strlen(name);
dae3fdf6 248 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 249 goto out;
250
3cfc0f3a 251 err = -ENOMEM;
0ad19a3f 252 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
253 if (!nlmsg)
254 goto out;
255
256 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
257 if (!answer)
258 goto out;
259
3cfc0f3a 260 err = -EINVAL;
0ad19a3f 261 index = if_nametoindex(name);
262 if (!index)
263 goto out;
264
265 link_req = (struct link_req *)nlmsg;
266 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
267 link_req->ifinfomsg.ifi_index = index;
268 link_req->ifinfomsg.ifi_change |= IFF_UP;
269 link_req->ifinfomsg.ifi_flags |= flag;
270 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
271 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
272 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
273
274 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 275out:
276 netlink_close(&nlh);
277 nlmsg_free(nlmsg);
278 nlmsg_free(answer);
279 return err;
280}
281
d472214b 282int lxc_netdev_set_mtu(const char *name, int mtu)
75d09f83
DL
283{
284 struct nl_handler nlh;
285 struct nlmsg *nlmsg = NULL, *answer = NULL;
286 struct link_req *link_req;
3cfc0f3a 287 int index, len, err;
75d09f83 288
3cfc0f3a
MN
289 err = netlink_open(&nlh, NETLINK_ROUTE);
290 if (err)
291 return err;
75d09f83 292
3cfc0f3a 293 err = -EINVAL;
75d09f83 294 len = strlen(name);
dae3fdf6 295 if (len == 1 || len >= IFNAMSIZ)
75d09f83
DL
296 goto out;
297
3cfc0f3a 298 err = -ENOMEM;
75d09f83
DL
299 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
300 if (!nlmsg)
301 goto out;
302
303 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
304 if (!answer)
305 goto out;
306
3cfc0f3a 307 err = -EINVAL;
75d09f83
DL
308 index = if_nametoindex(name);
309 if (!index)
310 goto out;
311
312 link_req = (struct link_req *)nlmsg;
313 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
314 link_req->ifinfomsg.ifi_index = index;
315 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
316 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
317 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
318
319 if (nla_put_u32(nlmsg, IFLA_MTU, mtu))
320 goto out;
321
322 err = netlink_transaction(&nlh, nlmsg, answer);
75d09f83
DL
323out:
324 netlink_close(&nlh);
325 nlmsg_free(nlmsg);
326 nlmsg_free(answer);
327 return err;
328}
329
d472214b 330int lxc_netdev_up(const char *name)
0ad19a3f 331{
d472214b 332 return netdev_set_flag(name, IFF_UP);
0ad19a3f 333}
334
d472214b 335int lxc_netdev_down(const char *name)
0ad19a3f 336{
d472214b 337 return netdev_set_flag(name, 0);
0ad19a3f 338}
339
497353b6 340int lxc_veth_create(const char *name1, const char *name2)
0ad19a3f 341{
342 struct nl_handler nlh;
343 struct nlmsg *nlmsg = NULL, *answer = NULL;
344 struct link_req *link_req;
345 struct rtattr *nest1, *nest2, *nest3;
3cfc0f3a 346 int len, err;
0ad19a3f 347
3cfc0f3a
MN
348 err = netlink_open(&nlh, NETLINK_ROUTE);
349 if (err)
350 return err;
0ad19a3f 351
3cfc0f3a 352 err = -EINVAL;
0ad19a3f 353 len = strlen(name1);
dae3fdf6 354 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 355 goto out;
356
357 len = strlen(name2);
dae3fdf6 358 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 359 goto out;
360
3cfc0f3a 361 err = -ENOMEM;
0ad19a3f 362 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
363 if (!nlmsg)
364 goto out;
365
366 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
367 if (!answer)
368 goto out;
369
370 link_req = (struct link_req *)nlmsg;
371 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
372 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
79e68309 373 nlmsg->nlmsghdr.nlmsg_flags =
0ad19a3f 374 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
375 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
376
3cfc0f3a 377 err = -EINVAL;
79e68309 378 nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
0ad19a3f 379 if (!nest1)
380 goto out;
381
382 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
383 goto out;
384
385 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
386 if (!nest2)
387 goto out;
388
389 nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
390 if (!nest3)
391 goto out;
392
393 nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);
394
395 if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
396 goto out;
397
398 nla_end_nested(nlmsg, nest3);
399
400 nla_end_nested(nlmsg, nest2);
401
402 nla_end_nested(nlmsg, nest1);
403
404 if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
405 goto out;
406
3cfc0f3a 407 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 408out:
409 netlink_close(&nlh);
410 nlmsg_free(answer);
411 nlmsg_free(nlmsg);
412 return err;
413}
414
26c39028 415/* XXX: merge with lxc_macvlan_create */
7c11d57a 416int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid)
26c39028
JHS
417{
418 struct nl_handler nlh;
419 struct nlmsg *nlmsg = NULL, *answer = NULL;
420 struct link_req *link_req;
421 struct rtattr *nest, *nest2;
3cfc0f3a 422 int lindex, len, err;
26c39028 423
3cfc0f3a
MN
424 err = netlink_open(&nlh, NETLINK_ROUTE);
425 if (err)
426 return err;
26c39028 427
3cfc0f3a 428 err = -EINVAL;
26c39028 429 len = strlen(master);
dae3fdf6 430 if (len == 1 || len >= IFNAMSIZ)
26c39028
JHS
431 goto err3;
432
433 len = strlen(name);
dae3fdf6 434 if (len == 1 || len >= IFNAMSIZ)
26c39028
JHS
435 goto err3;
436
3cfc0f3a 437 err = -ENOMEM;
26c39028
JHS
438 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
439 if (!nlmsg)
440 goto err3;
441
442 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
443 if (!answer)
444 goto err2;
445
3cfc0f3a 446 err = -EINVAL;
26c39028
JHS
447 lindex = if_nametoindex(master);
448 if (!lindex)
449 goto err1;
450
451 link_req = (struct link_req *)nlmsg;
452 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
453 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
454 nlmsg->nlmsghdr.nlmsg_flags =
455 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
456 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
457
79e68309 458 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
26c39028
JHS
459 if (!nest)
460 goto err1;
461
462 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "vlan"))
463 goto err1;
464
465 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
466 if (!nest2)
467 goto err1;
e892973e 468
26c39028
JHS
469 if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid))
470 goto err1;
e892973e 471
26c39028
JHS
472 nla_end_nested(nlmsg, nest2);
473
474 nla_end_nested(nlmsg, nest);
475
476 if (nla_put_u32(nlmsg, IFLA_LINK, lindex))
477 goto err1;
478
479 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
480 goto err1;
481
3cfc0f3a 482 err = netlink_transaction(&nlh, nlmsg, answer);
26c39028
JHS
483err1:
484 nlmsg_free(answer);
485err2:
486 nlmsg_free(nlmsg);
487err3:
488 netlink_close(&nlh);
489 return err;
490}
491
e892973e 492int lxc_macvlan_create(const char *master, const char *name, int mode)
0ad19a3f 493{
494 struct nl_handler nlh;
495 struct nlmsg *nlmsg = NULL, *answer = NULL;
496 struct link_req *link_req;
e892973e 497 struct rtattr *nest, *nest2;
3cfc0f3a 498 int index, len, err;
0ad19a3f 499
3cfc0f3a
MN
500 err = netlink_open(&nlh, NETLINK_ROUTE);
501 if (err)
502 return err;
0ad19a3f 503
3cfc0f3a 504 err = -EINVAL;
0ad19a3f 505 len = strlen(master);
dae3fdf6 506 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 507 goto out;
508
509 len = strlen(name);
dae3fdf6 510 if (len == 1 || len >= IFNAMSIZ)
0ad19a3f 511 goto out;
512
3cfc0f3a 513 err = -ENOMEM;
0ad19a3f 514 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
515 if (!nlmsg)
516 goto out;
517
518 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
519 if (!answer)
520 goto out;
521
3cfc0f3a 522 err = -EINVAL;
0ad19a3f 523 index = if_nametoindex(master);
524 if (!index)
525 goto out;
526
527 link_req = (struct link_req *)nlmsg;
528 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
529 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
530 nlmsg->nlmsghdr.nlmsg_flags =
531 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
532 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
533
79e68309 534 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
0ad19a3f 535 if (!nest)
536 goto out;
537
538 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan"))
539 goto out;
540
e892973e
DL
541 if (mode) {
542 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
543 if (!nest2)
544 goto out;
545
546 if (nla_put_u32(nlmsg, IFLA_MACVLAN_MODE, mode))
547 goto out;
548
549 nla_end_nested(nlmsg, nest2);
550 }
551
0ad19a3f 552 nla_end_nested(nlmsg, nest);
553
554 if (nla_put_u32(nlmsg, IFLA_LINK, index))
555 goto out;
556
557 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
558 goto out;
559
3cfc0f3a 560 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 561out:
562 netlink_close(&nlh);
563 nlmsg_free(answer);
564 nlmsg_free(nlmsg);
565 return err;
566}
567
568static int proc_sys_net_write(const char *path, const char *value)
569{
570 int fd, err = 0;
571
572 fd = open(path, O_WRONLY);
573 if (fd < 0)
574 return -errno;
575
576 if (write(fd, value, strlen(value)) < 0)
577 err = -errno;
578
579 close(fd);
580 return err;
581}
582
583static int ip_forward_set(const char *ifname, int family, int flag)
584{
22ebac19 585 char path[MAXPATHLEN];
9ba8130c 586 int rc;
0ad19a3f 587
588 if (family != AF_INET && family != AF_INET6)
3cfc0f3a 589 return -EINVAL;
0ad19a3f 590
9ba8130c 591 rc = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/forwarding",
0ad19a3f 592 family == AF_INET?"ipv4":"ipv6" , ifname);
9ba8130c
SH
593 if (rc >= MAXPATHLEN)
594 return -E2BIG;
0ad19a3f 595
22ebac19 596 return proc_sys_net_write(path, flag?"1":"0");
0ad19a3f 597}
598
497353b6 599int lxc_ip_forward_on(const char *ifname, int family)
0ad19a3f 600{
601 return ip_forward_set(ifname, family, 1);
602}
603
497353b6 604int lxc_ip_forward_off(const char *ifname, int family)
0ad19a3f 605{
606 return ip_forward_set(ifname, family, 0);
607}
608
609static int neigh_proxy_set(const char *ifname, int family, int flag)
610{
611 char path[MAXPATHLEN];
9ba8130c 612 int ret;
0ad19a3f 613
614 if (family != AF_INET && family != AF_INET6)
3cfc0f3a 615 return -EINVAL;
0ad19a3f 616
9ba8130c 617 ret = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/%s",
79e68309 618 family == AF_INET?"ipv4":"ipv6" , ifname,
0ad19a3f 619 family == AF_INET?"proxy_arp":"proxy_ndp");
9ba8130c
SH
620 if (ret < 0 || ret >= MAXPATHLEN)
621 return -E2BIG;
0ad19a3f 622
623 return proc_sys_net_write(path, flag?"1":"0");
624}
625
497353b6 626int lxc_neigh_proxy_on(const char *name, int family)
0ad19a3f 627{
628 return neigh_proxy_set(name, family, 1);
629}
630
497353b6 631int lxc_neigh_proxy_off(const char *name, int family)
0ad19a3f 632{
633 return neigh_proxy_set(name, family, 0);
634}
635
636int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr)
637{
1f1b18e7
DL
638 unsigned char *data;
639 char c;
640 int i = 0;
641 unsigned val;
642
643 sockaddr->sa_family = ARPHRD_ETHER;
644 data = (unsigned char *)sockaddr->sa_data;
645
646 while ((*macaddr != '\0') && (i < ETH_ALEN)) {
647 val = 0;
648 c = *macaddr++;
649 if (isdigit(c))
650 val = c - '0';
651 else if (c >= 'a' && c <= 'f')
652 val = c - 'a' + 10;
653 else if (c >= 'A' && c <= 'F')
654 val = c - 'A' + 10;
655 else {
656 return -EINVAL;
657 }
658 val <<= 4;
659 c = *macaddr;
660 if (isdigit(c))
661 val |= c - '0';
662 else if (c >= 'a' && c <= 'f')
663 val |= c - 'a' + 10;
664 else if (c >= 'A' && c <= 'F')
665 val |= c - 'A' + 10;
666 else if (c == ':' || c == 0)
667 val >>= 4;
668 else {
669 return -EINVAL;
670 }
671 if (c != 0)
672 macaddr++;
673 *data++ = (unsigned char) (val & 0377);
674 i++;
675
676 if (*macaddr == ':')
677 macaddr++;
0ad19a3f 678 }
0ad19a3f 679
1f1b18e7 680 return 0;
0ad19a3f 681}
682
1f1b18e7
DL
683static int ip_addr_add(int family, int ifindex,
684 void *addr, void *bcast, void *acast, int prefix)
0ad19a3f 685{
686 struct nl_handler nlh;
0ad19a3f 687 struct nlmsg *nlmsg = NULL, *answer = NULL;
688 struct ip_req *ip_req;
4bf1968d 689 int addrlen;
3cfc0f3a 690 int err;
0ad19a3f 691
4bf1968d
DL
692 addrlen = family == AF_INET ? sizeof(struct in_addr) :
693 sizeof(struct in6_addr);
694
3cfc0f3a
MN
695 err = netlink_open(&nlh, NETLINK_ROUTE);
696 if (err)
697 return err;
0ad19a3f 698
3cfc0f3a 699 err = -ENOMEM;
0ad19a3f 700 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
701 if (!nlmsg)
702 goto out;
703
704 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
705 if (!answer)
706 goto out;
707
0ad19a3f 708 ip_req = (struct ip_req *)nlmsg;
1f1b18e7
DL
709 ip_req->nlmsg.nlmsghdr.nlmsg_len =
710 NLMSG_LENGTH(sizeof(struct ifaddrmsg));
0ad19a3f 711 ip_req->nlmsg.nlmsghdr.nlmsg_flags =
712 NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
713 ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR;
714 ip_req->ifa.ifa_prefixlen = prefix;
715 ip_req->ifa.ifa_index = ifindex;
4bf1968d 716 ip_req->ifa.ifa_family = family;
0ad19a3f 717 ip_req->ifa.ifa_scope = 0;
718
3cfc0f3a 719 err = -EINVAL;
4bf1968d 720 if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen))
0ad19a3f 721 goto out;
722
4bf1968d 723 if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen))
0ad19a3f 724 goto out;
725
d8948a52 726 if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen))
1f1b18e7
DL
727 goto out;
728
729 /* TODO : multicast, anycast with ipv6 */
7ddc8f24 730 err = -EPROTONOSUPPORT;
79881dc6
DL
731 if (family == AF_INET6 &&
732 (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) ||
733 memcmp(acast, &in6addr_any, sizeof(in6addr_any))))
1f1b18e7 734 goto out;
0ad19a3f 735
3cfc0f3a 736 err = netlink_transaction(&nlh, nlmsg, answer);
0ad19a3f 737out:
738 netlink_close(&nlh);
739 nlmsg_free(answer);
740 nlmsg_free(nlmsg);
741 return err;
742}
743
1f1b18e7
DL
744int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr,
745 struct in6_addr *mcast,
746 struct in6_addr *acast, int prefix)
747{
748 return ip_addr_add(AF_INET6, ifindex, addr, mcast, acast, prefix);
749}
750
751int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
752 struct in_addr *bcast, int prefix)
753{
754 return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix);
755}
756
19a26f82
MK
757/* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present)
758 * address from the given RTM_NEWADDR message. Allocates memory for the
759 * address and stores that pointer in *res (so res should be an
760 * in_addr** or in6_addr**).
761 */
762static int ifa_get_local_ip(int family, struct ip_req *ip_info, void** res) {
763 struct rtattr *rta = IFA_RTA(&ip_info->ifa);
764 int attr_len = IFA_PAYLOAD(&ip_info->nlmsg.nlmsghdr);
765 int addrlen;
766
767 if (ip_info->ifa.ifa_family != family)
768 return 0;
769
770 addrlen = family == AF_INET ? sizeof(struct in_addr) :
771 sizeof(struct in6_addr);
772
773 /* Loop over the rtattr's in this message */
774 while(RTA_OK(rta, attr_len)) {
775 /* Found a local address for the requested interface,
776 * return it. */
777 if (rta->rta_type == IFA_LOCAL || rta->rta_type == IFA_ADDRESS) {
778 /* Sanity check. The family check above should
779 * make sure the address length is correct, but
780 * check here just in case */
781 if (RTA_PAYLOAD(rta) != addrlen)
782 return -1;
783
784 /* We might have found an IFA_ADDRESS before,
785 * which we now overwrite with an IFA_LOCAL. */
dd66e5ad 786 if (!*res) {
19a26f82 787 *res = malloc(addrlen);
dd66e5ad
DE
788 if (!*res)
789 return -1;
790 }
19a26f82
MK
791
792 memcpy(*res, RTA_DATA(rta), addrlen);
793
794 if (rta->rta_type == IFA_LOCAL)
795 break;
796 }
797 rta = RTA_NEXT(rta, attr_len);
798 }
799 return 0;
800}
801
802static int ip_addr_get(int family, int ifindex, void **res)
803{
804 struct nl_handler nlh;
805 struct nlmsg *nlmsg = NULL, *answer = NULL;
806 struct ip_req *ip_req, *ip_info;
807 struct nlmsghdr *msg;
808 int err;
809 int recv_len = 0, answer_len;
810 int readmore = 0;
811
812 err = netlink_open(&nlh, NETLINK_ROUTE);
813 if (err)
814 return err;
815
816 err = -ENOMEM;
817 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
818 if (!nlmsg)
819 goto out;
820
821 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
822 if (!answer)
823 goto out;
824
825 /* Save the answer buffer length, since it will be overwritten
826 * on the first receive (and we might need to receive more than
827 * once. */
828 answer_len = answer->nlmsghdr.nlmsg_len;
829
830 ip_req = (struct ip_req *)nlmsg;
831 ip_req->nlmsg.nlmsghdr.nlmsg_len =
832 NLMSG_LENGTH(sizeof(struct ifaddrmsg));
833 ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT;
834 ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETADDR;
835 ip_req->ifa.ifa_family = family;
836
837 /* Send the request for addresses, which returns all addresses
838 * on all interfaces. */
839 err = netlink_send(&nlh, nlmsg);
840 if (err < 0)
841 goto out;
19a26f82
MK
842
843 do {
844 /* Restore the answer buffer length, it might have been
845 * overwritten by a previous receive. */
846 answer->nlmsghdr.nlmsg_len = answer_len;
847
848 /* Get the (next) batch of reply messages */
849 err = netlink_rcv(&nlh, answer);
850 if (err < 0)
851 goto out;
852
853 recv_len = err;
854 err = 0;
855
856 /* Satisfy the typing for the netlink macros */
857 msg = &answer->nlmsghdr;
858
859 while (NLMSG_OK(msg, recv_len)) {
860 /* Stop reading if we see an error message */
861 if (msg->nlmsg_type == NLMSG_ERROR) {
862 struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg);
863 err = errmsg->error;
864 goto out;
865 }
866
867 /* Stop reading if we see a NLMSG_DONE message */
868 if (msg->nlmsg_type == NLMSG_DONE) {
869 readmore = 0;
870 break;
871 }
872
873 if (msg->nlmsg_type != RTM_NEWADDR) {
874 err = -1;
875 goto out;
876 }
877
878 ip_info = (struct ip_req *)msg;
879 if (ip_info->ifa.ifa_index == ifindex) {
880 ifa_get_local_ip(family, ip_info, res);
881 /* Found a result, stop searching */
882 if (*res)
883 goto out;
884 }
885
886 /* Keep reading more data from the socket if the
887 * last message had the NLF_F_MULTI flag set */
888 readmore = (msg->nlmsg_flags & NLM_F_MULTI);
889
890 /* Look at the next message received in this buffer */
891 msg = NLMSG_NEXT(msg, recv_len);
892 }
893 } while (readmore);
894
895 /* If we end up here, we didn't find any result, so signal an
896 * error */
897 err = -1;
898
899out:
900 netlink_close(&nlh);
901 nlmsg_free(answer);
902 nlmsg_free(nlmsg);
903 return err;
904}
905
906int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res)
907{
908 return ip_addr_get(AF_INET6, ifindex, (void**)res);
909}
910
911int lxc_ipv4_addr_get(int ifindex, struct in_addr** res)
912{
913 return ip_addr_get(AF_INET, ifindex, (void**)res);
914}
915
f8fee0e2
MK
916static int ip_gateway_add(int family, int ifindex, void *gw)
917{
918 struct nl_handler nlh;
919 struct nlmsg *nlmsg = NULL, *answer = NULL;
920 struct rt_req *rt_req;
921 int addrlen;
922 int err;
923
924 addrlen = family == AF_INET ? sizeof(struct in_addr) :
925 sizeof(struct in6_addr);
926
927 err = netlink_open(&nlh, NETLINK_ROUTE);
928 if (err)
929 return err;
930
931 err = -ENOMEM;
932 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
933 if (!nlmsg)
934 goto out;
935
936 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
937 if (!answer)
938 goto out;
939
940 rt_req = (struct rt_req *)nlmsg;
941 rt_req->nlmsg.nlmsghdr.nlmsg_len =
942 NLMSG_LENGTH(sizeof(struct rtmsg));
943 rt_req->nlmsg.nlmsghdr.nlmsg_flags =
944 NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
945 rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE;
946 rt_req->rt.rtm_family = family;
947 rt_req->rt.rtm_table = RT_TABLE_MAIN;
948 rt_req->rt.rtm_scope = RT_SCOPE_UNIVERSE;
949 rt_req->rt.rtm_protocol = RTPROT_BOOT;
950 rt_req->rt.rtm_type = RTN_UNICAST;
951 /* "default" destination */
952 rt_req->rt.rtm_dst_len = 0;
953
954 err = -EINVAL;
955 if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
956 goto out;
957
958 /* Adding the interface index enables the use of link-local
959 * addresses for the gateway */
960 if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
961 goto out;
962
963 err = netlink_transaction(&nlh, nlmsg, answer);
964out:
965 netlink_close(&nlh);
966 nlmsg_free(answer);
967 nlmsg_free(nlmsg);
968 return err;
969}
970
971int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw)
972{
973 return ip_gateway_add(AF_INET, ifindex, gw);
974}
975
976int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw)
977{
978 return ip_gateway_add(AF_INET6, ifindex, gw);
979}
980
7d163508
MN
981/*
982 * There is a lxc_bridge_attach, but no need of a bridge detach
d472214b 983 * as automatically done by kernel when a netdev is deleted.
7d163508
MN
984 */
985int lxc_bridge_attach(const char *bridge, const char *ifname)
0ad19a3f 986{
987 int fd, index, err;
988 struct ifreq ifr;
989
dae3fdf6 990 if (strlen(ifname) >= IFNAMSIZ)
3cfc0f3a 991 return -EINVAL;
0ad19a3f 992
993 index = if_nametoindex(ifname);
994 if (!index)
3cfc0f3a 995 return -EINVAL;
0ad19a3f 996
997 fd = socket(AF_INET, SOCK_STREAM, 0);
998 if (fd < 0)
3cfc0f3a 999 return -errno;
0ad19a3f 1000
1001 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
1002 ifr.ifr_ifindex = index;
7d163508 1003 err = ioctl(fd, SIOCBRADDIF, &ifr);
0ad19a3f 1004 close(fd);
3cfc0f3a
MN
1005 if (err)
1006 err = -errno;
0ad19a3f 1007
1008 return err;
1009}
72d0e1cb
SG
1010
1011static char* lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
1012 [LXC_NET_VETH] = "veth",
1013 [LXC_NET_MACVLAN] = "macvlan",
1014 [LXC_NET_VLAN] = "vlan",
1015 [LXC_NET_PHYS] = "phys",
1016 [LXC_NET_EMPTY] = "empty",
1017};
1018
1019const char *lxc_net_type_to_str(int type)
1020{
1021 if (type < 0 || type > LXC_NET_MAXCONFTYPE)
1022 return NULL;
1023 return lxc_network_types[type];
1024}