]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/network.c
Add VLAN support in config
[mirror_lxc.git] / src / lxc / network.c
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
66 #ifndef IFLA_VLAN_ID
67 # define IFLA_VLAN_ID 1
68 #endif
69
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
78 struct link_req {
79 struct nlmsg nlmsg;
80 struct ifinfomsg ifinfomsg;
81 };
82
83 struct ip_req {
84 struct nlmsg nlmsg;
85 struct ifaddrmsg ifa;
86 };
87
88 int lxc_device_move(int ifindex, pid_t pid)
89 {
90 struct nl_handler nlh;
91 struct nlmsg *nlmsg = NULL;
92 struct link_req *link_req;
93 int err = -1;
94
95 if (netlink_open(&nlh, NETLINK_ROUTE))
96 return -1;
97
98 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
99 if (!nlmsg)
100 goto out;
101
102 link_req = (struct link_req *)nlmsg;
103 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
104 link_req->ifinfomsg.ifi_index = ifindex;
105 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
106 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
107 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
108
109 if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
110 goto out;
111
112 if (netlink_transaction(&nlh, nlmsg, nlmsg))
113 goto out;
114
115 err = 0;
116 out:
117 netlink_close(&nlh);
118 nlmsg_free(nlmsg);
119 return err;
120 }
121
122 extern int lxc_device_delete(const char *name)
123 {
124 struct nl_handler nlh;
125 struct nlmsg *nlmsg = NULL, *answer = NULL;
126 struct link_req *link_req;
127 int index, len, err = -1;
128
129 if (netlink_open(&nlh, NETLINK_ROUTE))
130 return -1;
131
132 len = strlen(name);
133 if (len == 1 || len > IFNAMSIZ)
134 goto out;
135
136 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
137 if (!nlmsg)
138 goto out;
139
140 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
141 if (!answer)
142 goto out;
143
144 index = if_nametoindex(name);
145 if (!index)
146 goto out;
147
148 link_req = (struct link_req *)nlmsg;
149 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
150 link_req->ifinfomsg.ifi_index = index;
151 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
152 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
153 nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK;
154
155 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
156 goto out;
157
158 if (netlink_transaction(&nlh, nlmsg, answer))
159 goto out;
160
161 err = 0;
162 out:
163 netlink_close(&nlh);
164 nlmsg_free(answer);
165 nlmsg_free(nlmsg);
166 return err;
167 }
168
169 static int device_set_flag(const char *name, int flag)
170 {
171 struct nl_handler nlh;
172 struct nlmsg *nlmsg = NULL, *answer = NULL;
173 struct link_req *link_req;
174 int index, len, err = -1;
175
176 if (netlink_open(&nlh, NETLINK_ROUTE))
177 return -1;
178
179 len = strlen(name);
180 if (len == 1 || len > IFNAMSIZ)
181 goto out;
182
183 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
184 if (!nlmsg)
185 goto out;
186
187 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
188 if (!answer)
189 goto out;
190
191 index = if_nametoindex(name);
192 if (!index)
193 goto out;
194
195 link_req = (struct link_req *)nlmsg;
196 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
197 link_req->ifinfomsg.ifi_index = index;
198 link_req->ifinfomsg.ifi_change |= IFF_UP;
199 link_req->ifinfomsg.ifi_flags |= flag;
200 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
201 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
202 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
203
204 err = netlink_transaction(&nlh, nlmsg, answer);
205 if (err < 0)
206 goto out;
207
208 err = 0;
209 out:
210 netlink_close(&nlh);
211 nlmsg_free(nlmsg);
212 nlmsg_free(answer);
213 return err;
214 }
215
216 extern int lxc_device_set_mtu(const char *name, int mtu)
217 {
218 struct nl_handler nlh;
219 struct nlmsg *nlmsg = NULL, *answer = NULL;
220 struct link_req *link_req;
221 int index, len, err = -1;
222
223 if (netlink_open(&nlh, NETLINK_ROUTE))
224 return -1;
225
226 len = strlen(name);
227 if (len == 1 || len > IFNAMSIZ)
228 goto out;
229
230 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
231 if (!nlmsg)
232 goto out;
233
234 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
235 if (!answer)
236 goto out;
237
238 index = if_nametoindex(name);
239 if (!index)
240 goto out;
241
242 link_req = (struct link_req *)nlmsg;
243 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
244 link_req->ifinfomsg.ifi_index = index;
245 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
246 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
247 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
248
249 if (nla_put_u32(nlmsg, IFLA_MTU, mtu))
250 goto out;
251
252 err = netlink_transaction(&nlh, nlmsg, answer);
253 if (err < 0)
254 goto out;
255
256 err = 0;
257 out:
258 netlink_close(&nlh);
259 nlmsg_free(nlmsg);
260 nlmsg_free(answer);
261 return err;
262 }
263
264 int lxc_device_up(const char *name)
265 {
266 return device_set_flag(name, IFF_UP);
267 }
268
269 int lxc_device_down(const char *name)
270 {
271 return device_set_flag(name, 0);
272 }
273
274 int lxc_device_rename(const char *oldname, const char *newname)
275 {
276 struct nl_handler nlh;
277 struct nlmsg *nlmsg = NULL, *answer = NULL;
278 struct link_req *link_req;
279 int index, len, err = -1;
280
281 if (netlink_open(&nlh, NETLINK_ROUTE))
282 return -1;
283
284 len = strlen(oldname);
285 if (len == 1 || len > IFNAMSIZ)
286 goto out;
287
288 len = strlen(newname);
289 if (len == 1 || len > IFNAMSIZ)
290 goto out;
291
292 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
293 if (!nlmsg)
294 goto out;
295
296 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
297 if (!answer)
298 goto out;
299
300 index = if_nametoindex(oldname);
301 if (!index)
302 goto out;
303
304 link_req = (struct link_req *)nlmsg;
305 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
306 link_req->ifinfomsg.ifi_index = index;
307 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
308 nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
309 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
310
311 if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
312 goto out;
313
314 if (netlink_transaction(&nlh, nlmsg, answer))
315 goto out;
316
317 err = 0;
318 out:
319 netlink_close(&nlh);
320 nlmsg_free(answer);
321 nlmsg_free(nlmsg);
322 return err;
323 }
324
325 int lxc_veth_create(const char *name1, const char *name2)
326 {
327 struct nl_handler nlh;
328 struct nlmsg *nlmsg = NULL, *answer = NULL;
329 struct link_req *link_req;
330 struct rtattr *nest1, *nest2, *nest3;
331 int len, err = -1;
332
333 if (netlink_open(&nlh, NETLINK_ROUTE))
334 return -1;
335
336 len = strlen(name1);
337 if (len == 1 || len > IFNAMSIZ)
338 goto out;
339
340 len = strlen(name2);
341 if (len == 1 || len > IFNAMSIZ)
342 goto out;
343
344 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
345 if (!nlmsg)
346 goto out;
347
348 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
349 if (!answer)
350 goto out;
351
352 link_req = (struct link_req *)nlmsg;
353 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
354 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
355 nlmsg->nlmsghdr.nlmsg_flags =
356 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
357 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
358
359 nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
360 if (!nest1)
361 goto out;
362
363 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
364 goto out;
365
366 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
367 if (!nest2)
368 goto out;
369
370 nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
371 if (!nest3)
372 goto out;
373
374 nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);
375
376 if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
377 goto out;
378
379 nla_end_nested(nlmsg, nest3);
380
381 nla_end_nested(nlmsg, nest2);
382
383 nla_end_nested(nlmsg, nest1);
384
385 if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
386 goto out;
387
388 if (netlink_transaction(&nlh, nlmsg, answer))
389 goto out;
390
391 err = 0;
392 out:
393 netlink_close(&nlh);
394 nlmsg_free(answer);
395 nlmsg_free(nlmsg);
396 return err;
397 }
398
399 /* XXX: merge with lxc_macvlan_create */
400 int lxc_vlan_create(const char *master, const char *name, ushort vlanid)
401 {
402 struct nl_handler nlh;
403 struct nlmsg *nlmsg = NULL, *answer = NULL;
404 struct link_req *link_req;
405 struct rtattr *nest, *nest2;
406 int lindex, len, err = -1;
407
408 if (netlink_open(&nlh, NETLINK_ROUTE))
409 return -1;
410
411 len = strlen(master);
412 if (len == 1 || len > IFNAMSIZ)
413 goto err3;
414
415 len = strlen(name);
416 if (len == 1 || len > IFNAMSIZ)
417 goto err3;
418
419 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
420 if (!nlmsg)
421 goto err3;
422
423 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
424 if (!answer)
425 goto err2;
426
427 lindex = if_nametoindex(master);
428 if (!lindex)
429 goto err1;
430
431 link_req = (struct link_req *)nlmsg;
432 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
433 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
434 nlmsg->nlmsghdr.nlmsg_flags =
435 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
436 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
437
438 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
439 if (!nest)
440 goto err1;
441
442 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "vlan"))
443 goto err1;
444
445 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
446 if (!nest2)
447 goto err1;
448 if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid))
449 goto err1;
450 nla_end_nested(nlmsg, nest2);
451
452 nla_end_nested(nlmsg, nest);
453
454 if (nla_put_u32(nlmsg, IFLA_LINK, lindex))
455 goto err1;
456
457 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
458 goto err1;
459
460 if (netlink_transaction(&nlh, nlmsg, answer))
461 goto err1;
462
463 err = 0;
464 err1:
465 nlmsg_free(answer);
466 err2:
467 nlmsg_free(nlmsg);
468 err3:
469 netlink_close(&nlh);
470 return err;
471 }
472
473 int lxc_macvlan_create(const char *master, const char *name)
474 {
475 struct nl_handler nlh;
476 struct nlmsg *nlmsg = NULL, *answer = NULL;
477 struct link_req *link_req;
478 struct rtattr *nest;
479 int index, len, err = -1;
480
481 if (netlink_open(&nlh, NETLINK_ROUTE))
482 return -1;
483
484 len = strlen(master);
485 if (len == 1 || len > IFNAMSIZ)
486 goto out;
487
488 len = strlen(name);
489 if (len == 1 || len > IFNAMSIZ)
490 goto out;
491
492 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
493 if (!nlmsg)
494 goto out;
495
496 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
497 if (!answer)
498 goto out;
499
500 index = if_nametoindex(master);
501 if (!index)
502 goto out;
503
504 link_req = (struct link_req *)nlmsg;
505 link_req->ifinfomsg.ifi_family = AF_UNSPEC;
506 nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
507 nlmsg->nlmsghdr.nlmsg_flags =
508 NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
509 nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
510
511 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
512 if (!nest)
513 goto out;
514
515 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan"))
516 goto out;
517
518 nla_end_nested(nlmsg, nest);
519
520 if (nla_put_u32(nlmsg, IFLA_LINK, index))
521 goto out;
522
523 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
524 goto out;
525
526 if (netlink_transaction(&nlh, nlmsg, answer))
527 goto out;
528
529 err = 0;
530 out:
531 netlink_close(&nlh);
532 nlmsg_free(answer);
533 nlmsg_free(nlmsg);
534 return err;
535 }
536
537 static int proc_sys_net_write(const char *path, const char *value)
538 {
539 int fd, err = 0;
540
541 fd = open(path, O_WRONLY);
542 if (fd < 0)
543 return -errno;
544
545 if (write(fd, value, strlen(value)) < 0)
546 err = -errno;
547
548 close(fd);
549 return err;
550 }
551
552 static int ip_forward_set(const char *ifname, int family, int flag)
553 {
554 char path[MAXPATHLEN];
555
556 if (family != AF_INET && family != AF_INET6)
557 return -1;
558
559 snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/forwarding",
560 family == AF_INET?"ipv4":"ipv6" , ifname);
561
562 return proc_sys_net_write(path, flag?"1":"0");
563 }
564
565 int lxc_ip_forward_on(const char *ifname, int family)
566 {
567 return ip_forward_set(ifname, family, 1);
568 }
569
570 int lxc_ip_forward_off(const char *ifname, int family)
571 {
572 return ip_forward_set(ifname, family, 0);
573 }
574
575 static int neigh_proxy_set(const char *ifname, int family, int flag)
576 {
577 char path[MAXPATHLEN];
578
579 if (family != AF_INET && family != AF_INET6)
580 return -1;
581
582 sprintf(path, "/proc/sys/net/%s/conf/%s/%s",
583 family == AF_INET?"ipv4":"ipv6" , ifname,
584 family == AF_INET?"proxy_arp":"proxy_ndp");
585
586 return proc_sys_net_write(path, flag?"1":"0");
587 }
588
589 int lxc_neigh_proxy_on(const char *name, int family)
590 {
591 return neigh_proxy_set(name, family, 1);
592 }
593
594 int lxc_neigh_proxy_off(const char *name, int family)
595 {
596 return neigh_proxy_set(name, family, 0);
597 }
598
599 int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr)
600 {
601 unsigned char *data;
602 char c;
603 int i = 0;
604 unsigned val;
605
606 sockaddr->sa_family = ARPHRD_ETHER;
607 data = (unsigned char *)sockaddr->sa_data;
608
609 while ((*macaddr != '\0') && (i < ETH_ALEN)) {
610 val = 0;
611 c = *macaddr++;
612 if (isdigit(c))
613 val = c - '0';
614 else if (c >= 'a' && c <= 'f')
615 val = c - 'a' + 10;
616 else if (c >= 'A' && c <= 'F')
617 val = c - 'A' + 10;
618 else {
619 return -1;
620 }
621 val <<= 4;
622 c = *macaddr;
623 if (isdigit(c))
624 val |= c - '0';
625 else if (c >= 'a' && c <= 'f')
626 val |= c - 'a' + 10;
627 else if (c >= 'A' && c <= 'F')
628 val |= c - 'A' + 10;
629 else if (c == ':' || c == 0)
630 val >>= 4;
631 else {
632 return -1;
633 }
634 if (c != 0)
635 macaddr++;
636 *data++ = (unsigned char) (val & 0377);
637 i++;
638
639 if (*macaddr == ':')
640 macaddr++;
641 }
642
643 return 0;
644 }
645
646 int lxc_ip_addr_add(int family, int ifindex, void *addr, int prefix)
647 {
648 struct nl_handler nlh;
649 struct nlmsg *nlmsg = NULL, *answer = NULL;
650 struct ip_req *ip_req;
651 int addrlen;
652 int err = -1;
653
654 addrlen = family == AF_INET ? sizeof(struct in_addr) :
655 sizeof(struct in6_addr);
656
657 if (netlink_open(&nlh, NETLINK_ROUTE))
658 return -1;
659
660 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
661 if (!nlmsg)
662 goto out;
663
664 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
665 if (!answer)
666 goto out;
667
668 ip_req = (struct ip_req *)nlmsg;
669 ip_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
670 ip_req->nlmsg.nlmsghdr.nlmsg_flags =
671 NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
672 ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR;
673 ip_req->ifa.ifa_prefixlen = prefix;
674 ip_req->ifa.ifa_index = ifindex;
675 ip_req->ifa.ifa_family = family;
676 ip_req->ifa.ifa_scope = 0;
677
678 if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen))
679 goto out;
680
681 if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen))
682 goto out;
683
684 /* if (in_bcast.s_addr != INADDR_ANY) */
685 /* if (nla_put_buffer(nlmsg, IFA_BROADCAST, &in_bcast, */
686 /* sizeof(in_bcast))) */
687 /* goto out; */
688
689 if (netlink_transaction(&nlh, nlmsg, answer))
690 goto out;
691
692 err = 0;
693 out:
694 netlink_close(&nlh);
695 nlmsg_free(answer);
696 nlmsg_free(nlmsg);
697 return err;
698 }
699
700 static int bridge_add_del_interface(const char *bridge,
701 const char *ifname, int detach)
702 {
703 int fd, index, err;
704 struct ifreq ifr;
705
706 if (strlen(ifname) > IFNAMSIZ)
707 return -1;
708
709 index = if_nametoindex(ifname);
710 if (!index)
711 return -1;
712
713 fd = socket(AF_INET, SOCK_STREAM, 0);
714 if (fd < 0)
715 return -1;
716
717 strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
718 ifr.ifr_ifindex = index;
719 err = ioctl(fd, detach?SIOCBRDELIF:SIOCBRADDIF, &ifr);
720 close(fd);
721
722 return err;
723 }
724
725 int lxc_bridge_attach(const char *bridge, const char *ifname)
726 {
727 return bridge_add_del_interface(bridge, ifname, 0);
728 }
729
730 int lxc_bridge_detach(const char *bridge, const char *ifname)
731 {
732 return bridge_add_del_interface(bridge, ifname, 1);
733 }