1 /*
2  * Copyright (C) 2007-2015 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <config.h>
20 
21 #include "virnetdevbridge.h"
22 #include "virnetdev.h"
23 #include "virerror.h"
24 #include "virfile.h"
25 #include "viralloc.h"
26 #include "virlog.h"
27 #include "virstring.h"
28 #include "virsocket.h"
29 
30 #ifdef WITH_NET_IF_H
31 # include <net/if.h>
32 #endif
33 
34 #ifdef __linux__
35 # if defined(WITH_LIBNL)
36 #  include "virnetlink.h"
37 # endif
38 # include <linux/sockios.h>
39 # include <linux/param.h>     /* HZ                 */
40 # include <linux/in6.h>
41 # include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR  */
42 
43 # define JIFFIES_TO_MS(j) (((j)*1000)/HZ)
44 # define MS_TO_JIFFIES(ms) (((ms)*HZ)/1000)
45 #endif
46 
47 #if defined(WITH_BSD_BRIDGE_MGMT)
48 # include <net/ethernet.h>
49 # include <net/bridge/if_bridgevar.h>
50 #endif
51 
52 #define VIR_FROM_THIS VIR_FROM_NONE
53 
54 VIR_LOG_INIT("util.netdevbridge");
55 
56 #if defined(WITH_BSD_BRIDGE_MGMT)
virNetDevBridgeCmd(const char * brname,u_long op,void * arg,size_t argsize)57 static int virNetDevBridgeCmd(const char *brname,
58                               u_long op,
59                               void *arg,
60                               size_t argsize)
61 {
62     struct ifdrv ifd;
63     VIR_AUTOCLOSE s = -1;
64 
65     memset(&ifd, 0, sizeof(ifd));
66 
67     if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
68         virReportSystemError(errno, "%s",
69                              _("Cannot open network interface control socket"));
70         return -1;
71     }
72 
73     if (virStrcpyStatic(ifd.ifd_name, brname) < 0) {
74        virReportSystemError(ERANGE,
75                             _("Network interface name '%s' is too long"),
76                             brname);
77        return -1;
78     }
79 
80     ifd.ifd_cmd = op;
81     ifd.ifd_len = argsize;
82     ifd.ifd_data = arg;
83 
84     return ioctl(s, SIOCSDRVSPEC, &ifd);
85 }
86 #endif
87 
88 #if defined(WITH_STRUCT_IFREQ) && defined(__linux__)
89 /*
90  * Bridge parameters can be set via sysfs on newish kernels,
91  * or by  ioctl on older kernels. Perhaps we could just use
92  * ioctl for every kernel, but its not clear what the long
93  * term lifespan of the ioctl interface is...
94  * Fall back to ioctl if sysfs interface is not available or
95  * failing (e.g. due to container isolation).
96  */
virNetDevBridgeSet(const char * brname,const char * paramname,unsigned long value,int fd,struct ifreq * ifr)97 static int virNetDevBridgeSet(const char *brname,
98                               const char *paramname,  /* sysfs param name */
99                               unsigned long value,    /* new value */
100                               int fd,                 /* control socket */
101                               struct ifreq *ifr)      /* pre-filled bridge name */
102 {
103     g_autofree char *path = NULL;
104     unsigned long args[] = { 0, value, 0, 0 };
105     unsigned long paramid;
106 
107     path = g_strdup_printf(SYSFS_NET_DIR "%s/bridge/%s", brname, paramname);
108 
109     if (virFileExists(path)) {
110         g_autofree char *valuestr = g_strdup_printf("%lu", value);
111         if (virFileWriteStr(path, valuestr, 0) >= 0)
112             return 0;
113         VIR_DEBUG("Unable to set bridge %s %s via sysfs", brname, paramname);
114     }
115 
116     if (STREQ(paramname, "stp_state")) {
117         paramid = BRCTL_SET_BRIDGE_STP_STATE;
118     } else if (STREQ(paramname, "forward_delay")) {
119         paramid = BRCTL_SET_BRIDGE_FORWARD_DELAY;
120     } else {
121         virReportSystemError(EINVAL,
122                              _("Unable to set bridge %s %s via ioctl"),
123                              brname, paramname);
124         return -1;
125     }
126 
127     args[0] = paramid;
128     ifr->ifr_data = (char*)&args;
129     if (ioctl(fd, SIOCDEVPRIVATE, ifr) < 0) {
130         virReportSystemError(errno,
131                              _("Failed to set bridge %s %s via ioctl"),
132                              brname, paramname);
133         return -1;
134     }
135 
136     return 0;
137 }
138 
139 
virNetDevBridgeGet(const char * brname,const char * paramname,unsigned long * value)140 static int virNetDevBridgeGet(const char *brname,
141                               const char *paramname,  /* sysfs param name */
142                               unsigned long *value)   /* current value */
143 {
144     struct ifreq ifr;
145     g_autofree char *path = NULL;
146     VIR_AUTOCLOSE fd = -1;
147 
148     path = g_strdup_printf(SYSFS_NET_DIR "%s/bridge/%s", brname, paramname);
149 
150     if (virFileExists(path)) {
151         g_autofree char *valuestr = NULL;
152 
153         if (virFileReadAll(path, VIR_INT64_STR_BUFLEN,
154                            &valuestr) < 0)
155             return -1;
156 
157         if (virStrToLong_ul(valuestr, NULL, 10, value) < 0) {
158             virReportSystemError(EINVAL,
159                                  _("Unable to get bridge %s %s"),
160                                  brname, paramname);
161             return -1;
162         }
163     } else {
164         struct __bridge_info info;
165         unsigned long args[] = { BRCTL_GET_BRIDGE_INFO, (unsigned long)&info, 0, 0 };
166 
167         if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
168             return -1;
169 
170         ifr.ifr_data = (char*)&args;
171         if (ioctl(fd, SIOCDEVPRIVATE, ifr) < 0) {
172             virReportSystemError(errno,
173                                  _("Unable to get bridge %s %s"), brname, paramname);
174             return -1;
175         }
176 
177         if (STREQ(paramname, "stp_state")) {
178             *value = info.stp_enabled;
179         } else if (STREQ(paramname, "forward_delay")) {
180             *value = info.forward_delay;
181         } else {
182             virReportSystemError(EINVAL,
183                                  _("Unable to get bridge %s %s"), brname, paramname);
184             return -1;
185         }
186     }
187 
188     return 0;
189 }
190 #endif /* __linux__ */
191 
192 #if defined(__linux__)
193 static int
virNetDevBridgePortSet(const char * brname,const char * ifname,const char * paramname,unsigned long value)194 virNetDevBridgePortSet(const char *brname,
195                        const char *ifname,
196                        const char *paramname,
197                        unsigned long value)
198 {
199     char valuestr[VIR_INT64_STR_BUFLEN];
200     int ret = -1;
201     g_autofree char *path = NULL;
202 
203     g_snprintf(valuestr, sizeof(valuestr), "%lu", value);
204 
205     path = g_strdup_printf(SYSFS_NET_DIR "%s/brif/%s/%s", brname, ifname,
206                            paramname);
207 
208     if (!virFileExists(path))
209         errno = EINVAL;
210     else
211         ret = virFileWriteStr(path, valuestr, 0);
212 
213     if (ret < 0) {
214         virReportSystemError(errno,
215                              _("Unable to set bridge %s port %s %s to %s"),
216                              brname, ifname, paramname, valuestr);
217     }
218 
219     return ret;
220 }
221 
222 
223 static int
virNetDevBridgePortGet(const char * brname,const char * ifname,const char * paramname,unsigned long * value)224 virNetDevBridgePortGet(const char *brname,
225                        const char *ifname,
226                        const char *paramname,
227                        unsigned long *value)
228 {
229     g_autofree char *path = NULL;
230     g_autofree char *valuestr = NULL;
231 
232     path = g_strdup_printf(SYSFS_NET_DIR "%s/brif/%s/%s", brname, ifname,
233                            paramname);
234 
235     if (virFileReadAll(path, VIR_INT64_STR_BUFLEN, &valuestr) < 0)
236         return -1;
237 
238     if (virStrToLong_ul(valuestr, NULL, 10, value) < 0) {
239         virReportSystemError(EINVAL,
240                              _("Unable to get bridge %s port %s %s"),
241                              brname, ifname, paramname);
242         return -1;
243     }
244 
245     return 0;
246 }
247 
248 
249 int
virNetDevBridgePortGetLearning(const char * brname,const char * ifname,bool * enable)250 virNetDevBridgePortGetLearning(const char *brname,
251                                const char *ifname,
252                                bool *enable)
253 {
254     unsigned long value;
255 
256     if (virNetDevBridgePortGet(brname, ifname, "learning", &value) < 0)
257        return -1;
258 
259     *enable = !!value;
260     return 0;
261 }
262 
263 
264 int
virNetDevBridgePortSetLearning(const char * brname,const char * ifname,bool enable)265 virNetDevBridgePortSetLearning(const char *brname,
266                                const char *ifname,
267                                bool enable)
268 {
269     return virNetDevBridgePortSet(brname, ifname, "learning", enable ? 1 : 0);
270 }
271 
272 
273 int
virNetDevBridgePortGetUnicastFlood(const char * brname,const char * ifname,bool * enable)274 virNetDevBridgePortGetUnicastFlood(const char *brname,
275                                    const char *ifname,
276                                    bool *enable)
277 {
278     unsigned long value;
279 
280     if (virNetDevBridgePortGet(brname, ifname, "unicast_flood", &value) < 0)
281        return -1;
282 
283     *enable = !!value;
284     return 0;
285 }
286 
287 
288 int
virNetDevBridgePortSetUnicastFlood(const char * brname,const char * ifname,bool enable)289 virNetDevBridgePortSetUnicastFlood(const char *brname,
290                                    const char *ifname,
291                                    bool enable)
292 {
293     return virNetDevBridgePortSet(brname, ifname, "unicast_flood", enable ? 1 : 0);
294 }
295 
296 
297 int
virNetDevBridgePortGetIsolated(const char * brname,const char * ifname,bool * enable)298 virNetDevBridgePortGetIsolated(const char *brname,
299                                const char *ifname,
300                                bool *enable)
301 {
302     unsigned long value;
303 
304     if (virNetDevBridgePortGet(brname, ifname, "isolated", &value) < 0)
305        return -1;
306 
307     *enable = !!value;
308     return 0;
309 }
310 
311 
312 int
virNetDevBridgePortSetIsolated(const char * brname,const char * ifname,bool enable)313 virNetDevBridgePortSetIsolated(const char *brname,
314                                const char *ifname,
315                                bool enable)
316 {
317     return virNetDevBridgePortSet(brname, ifname, "isolated", enable ? 1 : 0);
318 }
319 
320 
321 #else
322 int
virNetDevBridgePortGetLearning(const char * brname G_GNUC_UNUSED,const char * ifname G_GNUC_UNUSED,bool * enable G_GNUC_UNUSED)323 virNetDevBridgePortGetLearning(const char *brname G_GNUC_UNUSED,
324                                const char *ifname G_GNUC_UNUSED,
325                                bool *enable G_GNUC_UNUSED)
326 {
327     virReportSystemError(ENOSYS, "%s",
328                          _("Unable to get bridge port learning on this platform"));
329     return -1;
330 }
331 
332 
333 int
virNetDevBridgePortSetLearning(const char * brname G_GNUC_UNUSED,const char * ifname G_GNUC_UNUSED,bool enable G_GNUC_UNUSED)334 virNetDevBridgePortSetLearning(const char *brname G_GNUC_UNUSED,
335                                const char *ifname G_GNUC_UNUSED,
336                                bool enable G_GNUC_UNUSED)
337 {
338     virReportSystemError(ENOSYS, "%s",
339                          _("Unable to set bridge port learning on this platform"));
340     return -1;
341 }
342 
343 
344 int
virNetDevBridgePortGetUnicastFlood(const char * brname G_GNUC_UNUSED,const char * ifname G_GNUC_UNUSED,bool * enable G_GNUC_UNUSED)345 virNetDevBridgePortGetUnicastFlood(const char *brname G_GNUC_UNUSED,
346                                    const char *ifname G_GNUC_UNUSED,
347                                    bool *enable G_GNUC_UNUSED)
348 {
349     virReportSystemError(ENOSYS, "%s",
350                          _("Unable to get bridge port unicast_flood on this platform"));
351     return -1;
352 }
353 
354 
355 int
virNetDevBridgePortSetUnicastFlood(const char * brname G_GNUC_UNUSED,const char * ifname G_GNUC_UNUSED,bool enable G_GNUC_UNUSED)356 virNetDevBridgePortSetUnicastFlood(const char *brname G_GNUC_UNUSED,
357                                    const char *ifname G_GNUC_UNUSED,
358                                    bool enable G_GNUC_UNUSED)
359 {
360     virReportSystemError(ENOSYS, "%s",
361                          _("Unable to set bridge port unicast_flood on this platform"));
362     return -1;
363 }
364 
365 
366 int
virNetDevBridgePortGetIsolated(const char * brname G_GNUC_UNUSED,const char * ifname G_GNUC_UNUSED,bool * enable G_GNUC_UNUSED)367 virNetDevBridgePortGetIsolated(const char *brname G_GNUC_UNUSED,
368                                const char *ifname G_GNUC_UNUSED,
369                                bool *enable G_GNUC_UNUSED)
370 {
371     virReportSystemError(ENOSYS, "%s",
372                          _("Unable to get bridge port isolated on this platform"));
373     return -1;
374 }
375 
376 
377 int
virNetDevBridgePortSetIsolated(const char * brname G_GNUC_UNUSED,const char * ifname G_GNUC_UNUSED,bool enable G_GNUC_UNUSED)378 virNetDevBridgePortSetIsolated(const char *brname G_GNUC_UNUSED,
379                                const char *ifname G_GNUC_UNUSED,
380                                bool enable G_GNUC_UNUSED)
381 {
382     virReportSystemError(ENOSYS, "%s",
383                          _("Unable to set bridge port isolated on this platform"));
384     return -1;
385 }
386 #endif
387 
388 
389 /**
390  * virNetDevBridgeCreate:
391  * @brname: the bridge name
392  *
393  * This function register a new bridge
394  *
395  * Returns 0 in case of success or -1 on failure
396  */
397 #if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDBR)
398 static int
virNetDevBridgeCreateWithIoctl(const char * brname,const virMacAddr * mac)399 virNetDevBridgeCreateWithIoctl(const char *brname,
400                                const virMacAddr *mac)
401 {
402     VIR_AUTOCLOSE fd = -1;
403 
404     if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
405         return -1;
406 
407     if (ioctl(fd, SIOCBRADDBR, brname) < 0) {
408         virReportSystemError(errno,
409                              _("Unable to create bridge %s"), brname);
410         return -1;
411     }
412 
413     if (virNetDevSetMAC(brname, mac) < 0) {
414         virErrorPtr savederr;
415 
416         virErrorPreserveLast(&savederr);
417         ignore_value(ioctl(fd, SIOCBRDELBR, brname));
418         virErrorRestore(&savederr);
419         return -1;
420     }
421 
422     return 0;
423 }
424 #endif
425 
426 #if defined(WITH_LIBNL)
427 int
virNetDevBridgeCreate(const char * brname,const virMacAddr * mac)428 virNetDevBridgeCreate(const char *brname,
429                       const virMacAddr *mac)
430 {
431     /* use a netlink RTM_NEWLINK message to create the bridge */
432     int error = 0;
433     virNetlinkNewLinkData data = {
434         .mac = mac,
435     };
436 
437 
438     if (virNetlinkNewLink(brname, "bridge", &data, &error) < 0) {
439 # if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDBR)
440         if (error == -EOPNOTSUPP) {
441             /* fallback to ioctl if netlink doesn't support creating bridges */
442             return virNetDevBridgeCreateWithIoctl(brname, mac);
443         }
444 # endif
445         if (error < 0)
446             virReportSystemError(-error, _("error creating bridge interface %s"),
447                                  brname);
448 
449         return -1;
450     }
451 
452     return 0;
453 }
454 
455 
456 #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDBR)
457 int
virNetDevBridgeCreate(const char * brname,const virMacAddr * mac)458 virNetDevBridgeCreate(const char *brname,
459                       const virMacAddr *mac)
460 {
461     return virNetDevBridgeCreateWithIoctl(brname, mac);
462 }
463 
464 
465 #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCIFCREATE2)
466 int
virNetDevBridgeCreate(const char * brname,const virMacAddr * mac)467 virNetDevBridgeCreate(const char *brname,
468                       const virMacAddr *mac)
469 {
470     struct ifreq ifr;
471     VIR_AUTOCLOSE s = -1;
472 
473     if ((s = virNetDevSetupControl("bridge", &ifr)) < 0)
474         return -1;
475 
476     if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) {
477         virReportSystemError(errno, "%s",
478                              _("Unable to create bridge device"));
479         return -1;
480     }
481 
482     if (virNetDevSetName(ifr.ifr_name, brname) == -1)
483         return -1;
484 
485     if (virNetDevSetMAC(brname, mac) < 0) {
486         virErrorPtr savederr;
487 
488         virErrorPreserveLast(&savederr);
489         ignore_value(virNetDevBridgeDelete(brname));
490         virErrorRestore(&savederr);
491         return -1;
492     }
493 
494     return 0;
495 }
496 #else
497 int
virNetDevBridgeCreate(const char * brname,const virMacAddr * mac G_GNUC_UNUSED)498 virNetDevBridgeCreate(const char *brname,
499                       const virMacAddr *mac G_GNUC_UNUSED)
500 {
501     virReportSystemError(ENOSYS,
502                          _("Unable to create bridge %s"), brname);
503     return -1;
504 }
505 #endif
506 
507 /**
508  * virNetDevBridgeDelete:
509  * @brname: the bridge name
510  *
511  * Remove a bridge from the layer.
512  *
513  * Returns 0 in case of success or an errno code in case of failure.
514  */
515 #if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELBR)
516 static int
virNetDevBridgeDeleteWithIoctl(const char * brname)517 virNetDevBridgeDeleteWithIoctl(const char *brname)
518 {
519     VIR_AUTOCLOSE fd = -1;
520 
521     ignore_value(virNetDevSetOnline(brname, false));
522 
523     if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
524         return -1;
525 
526     if (ioctl(fd, SIOCBRDELBR, brname) < 0) {
527         virReportSystemError(errno,
528                              _("Unable to delete bridge %s"), brname);
529         return -1;
530     }
531 
532     return 0;
533 }
534 #endif
535 
536 
537 #if defined(WITH_LIBNL)
538 int
virNetDevBridgeDelete(const char * brname)539 virNetDevBridgeDelete(const char *brname)
540 {
541     /* If netlink is available, use it, as it is successful at
542      * deleting a bridge even if it is currently IFF_UP. fallback to
543      * using ioctl(SIOCBRDELBR) if netlink fails with EOPNOTSUPP.
544      */
545 # if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELBR)
546     return virNetlinkDelLink(brname, virNetDevBridgeDeleteWithIoctl);
547 # else
548     return virNetlinkDelLink(brname, NULL);
549 # endif
550 }
551 
552 
553 #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELBR)
554 int
virNetDevBridgeDelete(const char * brname)555 virNetDevBridgeDelete(const char *brname)
556 {
557     return virNetDevBridgeDeleteWithIoctl(brname);
558 }
559 
560 
561 #elif defined(WITH_STRUCT_IFREQ) && defined(SIOCIFDESTROY)
562 int
virNetDevBridgeDelete(const char * brname)563 virNetDevBridgeDelete(const char *brname)
564 {
565     struct ifreq ifr;
566     VIR_AUTOCLOSE s = -1;
567 
568     if ((s = virNetDevSetupControl(brname, &ifr)) < 0)
569         return -1;
570 
571     if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) {
572         virReportSystemError(errno,
573                              _("Unable to remove bridge %s"),
574                              brname);
575         return -1;
576     }
577 
578     return 0;
579 }
580 #else
virNetDevBridgeDelete(const char * brname G_GNUC_UNUSED)581 int virNetDevBridgeDelete(const char *brname G_GNUC_UNUSED)
582 {
583     virReportSystemError(ENOSYS,
584                          _("Unable to delete bridge %s"), brname);
585     return EINVAL;
586 }
587 #endif
588 
589 /**
590  * virNetDevBridgeAddPort:
591  * @brname: the bridge name
592  * @ifname: the network interface name
593  *
594  * Adds an interface to a bridge
595  *
596  * Returns 0 in case of success or an errno code in case of failure.
597  */
598 #if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRADDIF)
virNetDevBridgeAddPort(const char * brname,const char * ifname)599 int virNetDevBridgeAddPort(const char *brname,
600                            const char *ifname)
601 {
602     struct ifreq ifr;
603     VIR_AUTOCLOSE fd = -1;
604 
605     if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
606         return -1;
607 
608     if (!(ifr.ifr_ifindex = if_nametoindex(ifname))) {
609         virReportSystemError(ENODEV,
610                              _("Unable to get interface index for %s"), ifname);
611         return -1;
612     }
613 
614     if (ioctl(fd, SIOCBRADDIF, &ifr) < 0) {
615         virReportSystemError(errno,
616                              _("Unable to add bridge %s port %s"), brname, ifname);
617         return -1;
618     }
619 
620     return 0;
621 }
622 #elif defined(WITH_BSD_BRIDGE_MGMT)
virNetDevBridgeAddPort(const char * brname,const char * ifname)623 int virNetDevBridgeAddPort(const char *brname,
624                            const char *ifname)
625 {
626     struct ifbreq req;
627 #if defined(__DragonFly__)
628     struct ifreq ifr;
629     int flags, s;
630 
631     memset(&ifr, 0, sizeof(ifr));
632 #endif
633 
634     memset(&req, 0, sizeof(req));
635     if (virStrcpyStatic(req.ifbr_ifsname, ifname) < 0) {
636         virReportSystemError(ERANGE,
637                              _("Network interface name '%s' is too long"),
638                              ifname);
639         return -1;
640     }
641 
642 #if defined(__DragonFly__)
643     snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", ifname);
644 
645     if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
646       virReportSystemError(errno, "%s",
647                              _("Cannot open network interface control socket"));
648       return -1;
649     }
650 
651     /* Set the interface UP */
652     flags = IFF_UP;
653     ifr.ifr_flags |= flags & 0xFFFF;
654     ifr.ifr_flagshigh |= flags >> 16;
655     if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
656       perror("SIOCSIFFLAGS");
657       close(s);
658       return -1;
659     }
660     close(s);
661 #endif
662 
663     if (virNetDevBridgeCmd(brname, BRDGADD, &req, sizeof(req)) < 0) {
664         virReportSystemError(errno,
665                              _("Unable to add bridge %s port %s"), brname, ifname);
666         return -1;
667     }
668 
669     return 0;
670 }
671 #else
virNetDevBridgeAddPort(const char * brname,const char * ifname)672 int virNetDevBridgeAddPort(const char *brname,
673                            const char *ifname)
674 {
675     virReportSystemError(ENOSYS,
676                          _("Unable to add bridge %s port %s"), brname, ifname);
677     return -1;
678 }
679 #endif
680 
681 /**
682  * virNetDevBridgeRemovePort:
683  * @brname: the bridge name
684  * @ifname: the network interface name
685  *
686  * Removes an interface from a bridge
687  *
688  * Returns 0 in case of success or an errno code in case of failure.
689  */
690 #if defined(WITH_STRUCT_IFREQ) && defined(SIOCBRDELIF)
virNetDevBridgeRemovePort(const char * brname,const char * ifname)691 int virNetDevBridgeRemovePort(const char *brname,
692                               const char *ifname)
693 {
694     struct ifreq ifr;
695     VIR_AUTOCLOSE fd = -1;
696 
697     if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
698         return -1;
699 
700     if (!(ifr.ifr_ifindex = if_nametoindex(ifname))) {
701         virReportSystemError(ENODEV,
702                              _("Unable to get interface index for %s"), ifname);
703 
704         return -1;
705     }
706 
707     if (ioctl(fd, SIOCBRDELIF, &ifr) < 0) {
708         virReportSystemError(errno,
709                              _("Unable to remove bridge %s port %s"), brname, ifname);
710         return -1;
711     }
712 
713     return 0;
714 }
715 #elif defined(WITH_BSD_BRIDGE_MGMT)
virNetDevBridgeRemovePort(const char * brname,const char * ifname)716 int virNetDevBridgeRemovePort(const char *brname,
717                               const char *ifname)
718 {
719     struct ifbreq req;
720 
721     memset(&req, 0, sizeof(req));
722     if (virStrcpyStatic(req.ifbr_ifsname, ifname) < 0) {
723         virReportSystemError(ERANGE,
724                              _("Network interface name '%s' is too long"),
725                              ifname);
726         return -1;
727     }
728 
729     if (virNetDevBridgeCmd(brname, BRDGDEL, &req, sizeof(req)) < 0) {
730         virReportSystemError(errno,
731                              _("Unable to remove bridge %s port %s"), brname, ifname);
732        return -1;
733     }
734 
735     return 0;
736 }
737 #else
virNetDevBridgeRemovePort(const char * brname,const char * ifname)738 int virNetDevBridgeRemovePort(const char *brname,
739                               const char *ifname)
740 {
741     virReportSystemError(ENOSYS,
742                          _("Unable to remove bridge %s port %s"), brname, ifname);
743     return -1;
744 }
745 #endif
746 
747 
748 #if defined(WITH_STRUCT_IFREQ) && defined(__linux__)
749 /**
750  * virNetDevBridgeSetSTPDelay:
751  * @brname: the bridge name
752  * @delay: delay in milliseconds
753  *
754  * Set the bridge forward delay
755  *
756  * Returns 0 in case of success or -1 on failure
757  */
758 
virNetDevBridgeSetSTPDelay(const char * brname,int delay)759 int virNetDevBridgeSetSTPDelay(const char *brname,
760                                int delay)
761 {
762     struct ifreq ifr;
763     VIR_AUTOCLOSE fd = -1;
764 
765     if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
766         return -1;
767 
768     return virNetDevBridgeSet(brname, "forward_delay", MS_TO_JIFFIES(delay),
769                               fd, &ifr);
770 }
771 
772 
773 /**
774  * virNetDevBridgeGetSTPDelay:
775  * @brname: the bridge device name
776  * @delayms: the forward delay in milliseconds
777  *
778  * Retrieves the forward delay for the bridge device @brname
779  * storing it in @delayms. The forward delay is only meaningful
780  * if STP is enabled
781  *
782  * Returns 0 on success, -1 on error+
783  */
virNetDevBridgeGetSTPDelay(const char * brname,int * delayms)784 int virNetDevBridgeGetSTPDelay(const char *brname,
785                                int *delayms)
786 {
787     int ret = -1;
788     unsigned long val = 0;
789 
790     ret = virNetDevBridgeGet(brname, "forward_delay", &val);
791     *delayms = JIFFIES_TO_MS(val);
792 
793     return ret;
794 }
795 
796 
797 /**
798  * virNetDevBridgeSetSTP:
799  * @brname: the bridge name
800  * @enable: 1 to enable, 0 to disable
801  *
802  * Control whether the bridge participates in the spanning tree protocol,
803  * in general don't disable it without good reasons.
804  *
805  * Returns 0 in case of success or -1 on failure
806  */
virNetDevBridgeSetSTP(const char * brname,bool enable)807 int virNetDevBridgeSetSTP(const char *brname,
808                           bool enable)
809 {
810     struct ifreq ifr;
811     VIR_AUTOCLOSE fd = -1;
812 
813     if ((fd = virNetDevSetupControl(brname, &ifr)) < 0)
814         return -1;
815 
816     return virNetDevBridgeSet(brname, "stp_state", enable ? 1 : 0,
817                               fd, &ifr);
818 }
819 
820 
821 /**
822  * virNetDevBridgeGetSTP:
823  * @brname: the bridge device name
824  * @enabled: returns the STP state
825  *
826  * Determine the state of the spanning tree protocol on
827  * the device @brname, returning the state in @enabled
828  *
829  * Returns 0 on success, -1 on error
830  */
virNetDevBridgeGetSTP(const char * brname,bool * enabled)831 int virNetDevBridgeGetSTP(const char *brname,
832                           bool *enabled)
833 {
834     int ret = -1;
835     unsigned long val = 0;
836 
837     ret = virNetDevBridgeGet(brname, "stp_state", &val);
838     *enabled = val ? true : false;
839 
840     return ret;
841 }
842 #elif defined(WITH_BSD_BRIDGE_MGMT)
virNetDevBridgeSetSTPDelay(const char * brname,int delay)843 int virNetDevBridgeSetSTPDelay(const char *brname,
844                                int delay)
845 {
846     struct ifbrparam param;
847     u_long delay_seconds = delay / 1000;
848 
849     /* FreeBSD doesn't allow setting STP delay < 4 */
850     delay_seconds = delay_seconds < 4 ? 4 : delay_seconds;
851     param.ifbrp_fwddelay = delay_seconds & 0xff;
852 
853     if (virNetDevBridgeCmd(brname, BRDGSFD, &param, sizeof(param)) < 0) {
854         virReportSystemError(errno,
855                              _("Unable to set STP delay on %s"), brname);
856         return -1;
857     }
858 
859     return 0;
860 }
virNetDevBridgeGetSTPDelay(const char * brname,int * delay G_GNUC_UNUSED)861 int virNetDevBridgeGetSTPDelay(const char *brname,
862                                int *delay G_GNUC_UNUSED)
863 {
864     virReportSystemError(ENOSYS,
865                          _("Unable to get STP delay on %s on this platform"),
866                          brname);
867     return -1;
868 }
869 
virNetDevBridgeSetSTP(const char * brname G_GNUC_UNUSED,bool enable G_GNUC_UNUSED)870 int virNetDevBridgeSetSTP(const char *brname G_GNUC_UNUSED,
871                           bool enable G_GNUC_UNUSED)
872 
873 {
874     /* FreeBSD doesn't allow to set STP per bridge,
875      * only per-device in bridge */
876     return 0;
877 }
virNetDevBridgeGetSTP(const char * brname,bool * enable G_GNUC_UNUSED)878 int virNetDevBridgeGetSTP(const char *brname,
879                           bool *enable G_GNUC_UNUSED)
880 {
881     virReportSystemError(ENOSYS,
882                          _("Unable to get STP on %s on this platform"),
883                          brname);
884     return -1;
885 }
886 #else
virNetDevBridgeSetSTPDelay(const char * brname,int delay G_GNUC_UNUSED)887 int virNetDevBridgeSetSTPDelay(const char *brname,
888                                int delay G_GNUC_UNUSED)
889 {
890     virReportSystemError(ENOSYS,
891                          _("Unable to set STP delay on %s on this platform"),
892                          brname);
893     return -1;
894 }
virNetDevBridgeGetSTPDelay(const char * brname,int * delay G_GNUC_UNUSED)895 int virNetDevBridgeGetSTPDelay(const char *brname,
896                                int *delay G_GNUC_UNUSED)
897 {
898     virReportSystemError(ENOSYS,
899                          _("Unable to get STP delay on %s on this platform"),
900                          brname);
901     return -1;
902 }
903 
virNetDevBridgeSetSTP(const char * brname,bool enable G_GNUC_UNUSED)904 int virNetDevBridgeSetSTP(const char *brname,
905                           bool enable G_GNUC_UNUSED)
906 
907 {
908     virReportSystemError(ENOSYS,
909                          _("Unable to set STP on %s on this platform"),
910                          brname);
911     return -1;
912 }
virNetDevBridgeGetSTP(const char * brname,bool * enable G_GNUC_UNUSED)913 int virNetDevBridgeGetSTP(const char *brname,
914                           bool *enable G_GNUC_UNUSED)
915 {
916     virReportSystemError(ENOSYS,
917                          _("Unable to get STP on %s on this platform"),
918                          brname);
919     return -1;
920 }
921 #endif
922 
923 #if defined(WITH_STRUCT_IFREQ) && defined(__linux__)
924 /**
925  * virNetDevBridgeGetVlanFiltering:
926  * @brname: the bridge device name
927  * @enable: true or false
928  *
929  * Retrieves the vlan_filtering setting for the bridge device @brname
930  * storing it in @enable.
931  *
932  * Returns 0 on success, -1 on error
933  */
934 int
virNetDevBridgeGetVlanFiltering(const char * brname,bool * enable)935 virNetDevBridgeGetVlanFiltering(const char *brname,
936                                 bool *enable)
937 {
938     unsigned long value;
939 
940     if (virNetDevBridgeGet(brname, "vlan_filtering", &value) < 0)
941         return -1;
942 
943     *enable = !!value;
944     return 0;
945 }
946 
947 
948 /**
949  * virNetDevBridgeSetVlanFiltering:
950  * @brname: the bridge name
951  * @enable: true or false
952  *
953  * Set the bridge vlan_filtering mode
954  *
955  * Returns 0 in case of success or -1 on failure
956  */
957 
958 int
virNetDevBridgeSetVlanFiltering(const char * brname,bool enable)959 virNetDevBridgeSetVlanFiltering(const char *brname,
960                                 bool enable)
961 {
962     return virNetDevBridgeSet(brname, "vlan_filtering", enable ? 1 : 0, -1, NULL);
963 }
964 
965 
966 #else
967 int
virNetDevBridgeGetVlanFiltering(const char * brname G_GNUC_UNUSED,bool * enable G_GNUC_UNUSED)968 virNetDevBridgeGetVlanFiltering(const char *brname G_GNUC_UNUSED,
969                                 bool *enable G_GNUC_UNUSED)
970 {
971     virReportSystemError(ENOSYS, "%s",
972                          _("Unable to get bridge vlan_filtering on this platform"));
973     return -1;
974 }
975 
976 
977 int
virNetDevBridgeSetVlanFiltering(const char * brname G_GNUC_UNUSED,bool enable G_GNUC_UNUSED)978 virNetDevBridgeSetVlanFiltering(const char *brname G_GNUC_UNUSED,
979                                 bool enable G_GNUC_UNUSED)
980 {
981     virReportSystemError(ENOSYS, "%s",
982                          _("Unable to set bridge vlan_filtering on this platform"));
983     return -1;
984 }
985 #endif
986 
987 
988 #if defined(WITH_LIBNL)
989 
990 # ifndef NTF_SELF
991 #  define NTF_SELF 0x02
992 # endif
993 
994 # ifndef NTF_MASTER
995 #  define NTF_MASTER 0x04
996 # endif
997 
998 /* virNetDevBridgeFDBAddDel:
999  * @mac: the MAC address being added to the table
1000  * @ifname: name of the port (interface) of the bridge that wants this MAC
1001  * @flags: any of virNetDevBridgeFDBFlags ORed together.
1002  * @isAdd: true if adding the entry, fals if deleting
1003  *
1004  * Use netlink RTM_NEWNEIGH and RTM_DELNEIGH messages to add and
1005  * delete entries from a bridge's fdb. The bridge itself is not
1006  * referenced in the arguments to the function, only the name of the
1007  * device that is attached to the bridge (since a device can only be
1008  * attached to one bridge at a time, and must be attached for this
1009  * function to make sense, the kernel easily infers which bridge's fdb
1010  * is being modified by looking at the device name/index).
1011  *
1012  * Attempting to add an existing entry, or delete a non-existing entry
1013  * *is* an error.
1014  *
1015  * returns 0 on success, -1 on failure.
1016  */
1017 static int
virNetDevBridgeFDBAddDel(const virMacAddr * mac,const char * ifname,unsigned int flags,bool isAdd)1018 virNetDevBridgeFDBAddDel(const virMacAddr *mac, const char *ifname,
1019                          unsigned int flags, bool isAdd)
1020 {
1021     struct nlmsgerr *err;
1022     unsigned int recvbuflen;
1023     struct ndmsg ndm = { .ndm_family = PF_BRIDGE, .ndm_state = NUD_NOARP };
1024     g_autoptr(virNetlinkMsg) nl_msg = NULL;
1025     g_autofree struct nlmsghdr *resp = NULL;
1026 
1027     if (virNetDevGetIndex(ifname, &ndm.ndm_ifindex) < 0)
1028         return -1;
1029 
1030     if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_ROUTER)
1031         ndm.ndm_flags |= NTF_ROUTER;
1032     if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_SELF)
1033         ndm.ndm_flags |= NTF_SELF;
1034     if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_MASTER)
1035         ndm.ndm_flags |= NTF_MASTER;
1036     /* default self (same as iproute2's bridge command */
1037     if (!(ndm.ndm_flags & (NTF_MASTER | NTF_SELF)))
1038         ndm.ndm_flags |= NTF_SELF;
1039 
1040     if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_PERMANENT)
1041         ndm.ndm_state |= NUD_PERMANENT;
1042     if (flags & VIR_NETDEVBRIDGE_FDB_FLAG_TEMP)
1043         ndm.ndm_state |= NUD_REACHABLE;
1044     /* default permanent, same as iproute2's bridge command */
1045     if (!(ndm.ndm_state & (NUD_PERMANENT | NUD_REACHABLE)))
1046         ndm.ndm_state |= NUD_PERMANENT;
1047 
1048     nl_msg = virNetlinkMsgNew(isAdd ? RTM_NEWNEIGH : RTM_DELNEIGH,
1049                               NLM_F_REQUEST |
1050                               (isAdd ? (NLM_F_CREATE | NLM_F_EXCL) : 0));
1051 
1052     if (nlmsg_append(nl_msg, &ndm, sizeof(ndm), NLMSG_ALIGNTO) < 0)
1053         goto buffer_too_small;
1054     if (nla_put(nl_msg, NDA_LLADDR, VIR_MAC_BUFLEN, mac) < 0)
1055         goto buffer_too_small;
1056 
1057     /* NB: this message can also accept a Destination IP, a port, a
1058      * vlan tag, and a via (see iproute2/bridge/fdb.c:fdb_modify()),
1059      * but those aren't required for our application
1060      */
1061 
1062     if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0,
1063                           NETLINK_ROUTE, 0) < 0) {
1064         return -1;
1065     }
1066     if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
1067         goto malformed_resp;
1068 
1069     switch (resp->nlmsg_type) {
1070     case NLMSG_ERROR:
1071         err = (struct nlmsgerr *)NLMSG_DATA(resp);
1072         if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
1073             goto malformed_resp;
1074         if (err->error) {
1075             if (isAdd && -err->error == EEXIST) {
1076                 VIR_DEBUG("fdb entry for %s already exists", ifname);
1077             } else {
1078                 virReportSystemError(-err->error,
1079                                      _("error adding fdb entry for %s"), ifname);
1080                 return -1;
1081             }
1082         }
1083         break;
1084     case NLMSG_DONE:
1085         break;
1086 
1087     default:
1088         goto malformed_resp;
1089     }
1090 
1091     return 0;
1092 
1093  malformed_resp:
1094     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1095                    _("malformed netlink response message"));
1096     return -1;
1097 
1098  buffer_too_small:
1099     virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1100                    _("allocated netlink buffer is too small"));
1101     return -1;
1102 }
1103 
1104 
1105 #else
1106 static int
virNetDevBridgeFDBAddDel(const virMacAddr * mac G_GNUC_UNUSED,const char * ifname G_GNUC_UNUSED,unsigned int fdbFlags G_GNUC_UNUSED,bool isAdd G_GNUC_UNUSED)1107 virNetDevBridgeFDBAddDel(const virMacAddr *mac G_GNUC_UNUSED,
1108                          const char *ifname G_GNUC_UNUSED,
1109                          unsigned int fdbFlags G_GNUC_UNUSED,
1110                          bool isAdd G_GNUC_UNUSED)
1111 {
1112     virReportSystemError(ENOSYS, "%s",
1113                          _("Unable to add/delete fdb entries on this platform"));
1114     return -1;
1115 }
1116 
1117 
1118 #endif
1119 
1120 int
virNetDevBridgeFDBAdd(const virMacAddr * mac,const char * ifname,unsigned int flags)1121 virNetDevBridgeFDBAdd(const virMacAddr *mac, const char *ifname,
1122                       unsigned int flags)
1123 {
1124     return virNetDevBridgeFDBAddDel(mac, ifname, flags, true);
1125 }
1126 
1127 
1128 int
virNetDevBridgeFDBDel(const virMacAddr * mac,const char * ifname,unsigned int flags)1129 virNetDevBridgeFDBDel(const virMacAddr *mac, const char *ifname,
1130                       unsigned int flags)
1131 {
1132     return virNetDevBridgeFDBAddDel(mac, ifname, flags, false);
1133 }
1134