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