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, ¶m, 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