diff --git a/po/POTFILES.in b/po/POTFILES.in index a39f2814e345f3183255c7f4bf9f6b7ccbe798fb..406e4c223c2f9e998268993cbaba81d9eb6ecb05 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -72,6 +72,7 @@ src/util/bridge.c src/util/conf.c src/util/hooks.c src/util/hostusb.c +src/util/interface.c src/util/json.c src/util/logging.c src/util/macvtap.c diff --git a/src/Makefile.am b/src/Makefile.am index d54e6d05ebd6748fb7ad8b1231df665f2c07418c..df577ead86f52f295e6acc0ddc3bef0508f22724 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,6 +67,7 @@ UTIL_SOURCES = \ util/processinfo.c util/processinfo.h \ util/hostusb.c util/hostusb.h \ util/network.c util/network.h \ + util/interface.c util/interface.h \ util/qparams.c util/qparams.h \ util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b76f2da748f0d7f00e2a6fd8f2642dc9abe52bd1..7950bcd2457eca10ade289904e8e1aaf359682ab 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -681,6 +681,10 @@ virFileWaitForDevices; virFileMatchesNameSuffix; virArgvToString; +# interface.h +ifaceCtrl; +ifaceCheck; +ifaceGetIndex; # usb.h usbGetDevice; diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c index 270dc2b05b17eba48a6878daacd468b6aa33481c..fafe214ff15826119927ba2e412d2c56c1745761 100644 --- a/src/nwfilter/nwfilter_gentech_driver.c +++ b/src/nwfilter/nwfilter_gentech_driver.c @@ -23,16 +23,11 @@ #include -#include -#include -#include -#include - #include "internal.h" #include "memory.h" #include "logging.h" -#include "datatypes.h" +#include "interface.h" #include "domain_conf.h" #include "virterror_internal.h" #include "nwfilter_gentech_driver.h" @@ -792,117 +787,6 @@ _virNWFilterInstantiateFilter(virConnectPtr conn, } -// FIXME: move chgIfFlags, ifUp, checkIf into common file & share w/ macvtap.c - -/* - * chgIfFlags: Change flags on an interface - * @ifname : name of the interface - * @flagclear : the flags to clear - * @flagset : the flags to set - * - * The new flags of the interface will be calculated as - * flagmask = (~0 ^ flagclear) - * newflags = (curflags & flagmask) | flagset; - * - * Returns 0 on success, errno on failure. - */ -static int chgIfFlags(const char *ifname, short flagclear, short flagset) { - struct ifreq ifr; - int rc = 0; - int flags; - short flagmask = (~0 ^ flagclear); - int fd = socket(PF_PACKET, SOCK_DGRAM, 0); - - if (fd < 0) - return errno; - - if (virStrncpy(ifr.ifr_name, - ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) { - rc = ENODEV; - goto err_exit; - } - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { - rc = errno; - goto err_exit; - } - - flags = (ifr.ifr_flags & flagmask) | flagset; - - if (ifr.ifr_flags != flags) { - ifr.ifr_flags = flags; - - if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) - rc = errno; - } - -err_exit: - close(fd); - return rc; -} - -/* - * ifUp - * @name: name of the interface - * @up: 1 for up, 0 for down - * - * Function to control if an interface is activated (up, 1) or not (down, 0) - * - * Returns 0 in case of success or an errno code in case of failure. - */ -static int -ifUp(const char *name, int up) -{ - return chgIfFlags(name, - (up) ? 0 : IFF_UP, - (up) ? IFF_UP : 0); -} - - -/** - * checkIf - * - * @ifname: Name of the interface - * @macaddr: expected MAC address of the interface - * - * FIXME: the interface's index is another good parameter to check - * - * Determine whether a given interface is still available. If so, - * it must have the given MAC address. - * - * Returns an error code ENODEV in case the interface does not exist - * anymore or its MAC address is different, 0 otherwise. - */ -int -checkIf(const char *ifname, const unsigned char *macaddr) -{ - struct ifreq ifr; - int fd = socket(PF_PACKET, SOCK_DGRAM, 0); - int rc = 0; - - if (fd < 0) - return errno; - - if (virStrncpy(ifr.ifr_name, - ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) { - rc = ENODEV; - goto err_exit; - } - - if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { - rc = errno; - goto err_exit; - } - - if (memcmp(&ifr.ifr_hwaddr.sa_data, macaddr, 6) != 0) - rc = ENODEV; - - err_exit: - close(fd); - return rc; -} - - int virNWFilterInstantiateFilterLate(virConnectPtr conn, const char *ifname, @@ -926,7 +810,7 @@ virNWFilterInstantiateFilterLate(virConnectPtr conn, driver); if (rc) { //something went wrong... 'DOWN' the interface - if (ifUp(ifname ,0)) { + if (ifaceDown(ifname)) { // assuming interface disappeared... _virNWFilterTeardownFilter(ifname); } diff --git a/src/nwfilter/nwfilter_gentech_driver.h b/src/nwfilter/nwfilter_gentech_driver.h index ebb0b64f720bf942ea153f3bae7add43750406a2..b65950416de17211080c0a67e38624d04bc1335a 100644 --- a/src/nwfilter/nwfilter_gentech_driver.h +++ b/src/nwfilter/nwfilter_gentech_driver.h @@ -63,6 +63,4 @@ void virNWFilterDomainFWUpdateCB(void *payload, const char *name ATTRIBUTE_UNUSED, void *data); -int checkIf(const char *ifname, const unsigned char *macaddr); - #endif diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c index b242464201b618ccc6ea001e57e17e3beafaad2c..bd4f3a56a29a33038a38ed5a6bf57905d71f8e7d 100644 --- a/src/nwfilter/nwfilter_learnipaddr.c +++ b/src/nwfilter/nwfilter_learnipaddr.c @@ -43,6 +43,7 @@ #include "memory.h" #include "logging.h" #include "datatypes.h" +#include "interface.h" #include "virterror_internal.h" #include "threads.h" #include "conf/nwfilter_params.h" @@ -339,7 +340,7 @@ learnIPAddressThread(void *arg) break; } /* listening on linkdev, check whether VM's dev is still there */ - if (checkIf(req->ifname, req->macaddr)) { + if (ifaceCheck(false, req->ifname, req->macaddr, -1)) { req->status = ENODEV; break; } diff --git a/src/util/interface.c b/src/util/interface.c new file mode 100644 index 0000000000000000000000000000000000000000..9b86f2d9d2be8d07db1997bdedc19cd19da94385 --- /dev/null +++ b/src/util/interface.c @@ -0,0 +1,226 @@ +/* + * interface.c: interface support functions + * + * Copyright (C) 2010 IBM Corp. + * Copyright (C) 2010 Stefan Berger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * chgIfaceFlags originated from bridge.c + * + * Author: Stefan Berger + */ + +#include + +#include +#include +#include + +#include "internal.h" + +#include "util.h" +#include "interface.h" +#include "virterror_internal.h" + +#define ifaceError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_NET, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +/* + * chgIfFlags: Change flags on an interface + * + * @ifname : name of the interface + * @flagclear : the flags to clear + * @flagset : the flags to set + * + * The new flags of the interface will be calculated as + * flagmask = (~0 ^ flagclear) + * newflags = (curflags & flagmask) | flagset; + * + * Returns 0 on success, errno on failure. + */ +static int chgIfaceFlags(const char *ifname, short flagclear, short flagset) { + struct ifreq ifr; + int rc = 0; + int flags; + short flagmask = (~0 ^ flagclear); + int fd = socket(PF_PACKET, SOCK_DGRAM, 0); + + if (fd < 0) + return errno; + + if (virStrncpy(ifr.ifr_name, + ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) { + rc = ENODEV; + goto err_exit; + } + + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + rc = errno; + goto err_exit; + } + + flags = (ifr.ifr_flags & flagmask) | flagset; + + if (ifr.ifr_flags != flags) { + ifr.ifr_flags = flags; + + if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) + rc = errno; + } + +err_exit: + close(fd); + return rc; +} + + +/* + * ifaceCtrl + * @name: name of the interface + * @up: true (1) for up, false (0) for down + * + * Function to control if an interface is activated (up, 1) or not (down, 0) + * + * Returns 0 in case of success or an errno code in case of failure. + */ +int +ifaceCtrl(const char *name, bool up) +{ + return chgIfaceFlags(name, + (up) ? 0 : IFF_UP, + (up) ? IFF_UP : 0); +} + + +/** + * ifaceCheck + * + * @reportError: whether to report errors or keep silent + * @ifname: Name of the interface + * @macaddr: expected MAC address of the interface; not checked if NULL + * @ifindex: expected index of the interface; not checked if '-1' + * + * Determine whether a given interface is still available. If so, + * it must have the given MAC address and if an interface index is + * passed, it must also match the interface index. + * + * Returns 0 on success, an error code on failure. + * ENODEV : if interface with given name does not exist or its interface + * index is different than the one passed + * EINVAL : if interface name is invalid (too long) + */ +int +ifaceCheck(bool reportError, const char *ifname, + const unsigned char *macaddr, int ifindex) +{ + struct ifreq ifr; + int fd = -1; + int rc = 0; + int idx; + + if (macaddr != NULL) { + fd = socket(PF_PACKET, SOCK_DGRAM, 0); + if (fd < 0) + return errno; + + if (virStrncpy(ifr.ifr_name, + ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) { + if (reportError) + ifaceError(VIR_ERR_INTERNAL_ERROR, + _("invalid interface name %s"), + ifname); + rc = EINVAL; + goto err_exit; + } + + if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { + if (reportError) + ifaceError(VIR_ERR_INTERNAL_ERROR, + _("coud not get MAC address of interface %s"), + ifname); + rc = errno; + goto err_exit; + } + + if (memcmp(&ifr.ifr_hwaddr.sa_data, macaddr, VIR_MAC_BUFLEN) != 0) { + rc = ENODEV; + goto err_exit; + } + } + + if (ifindex != -1) { + rc = ifaceGetIndex(reportError, ifname, &idx); + if (rc == 0 && idx != ifindex) + rc = ENODEV; + } + + err_exit: + if (fd >= 0) + close(fd); + + return rc; +} + + +/** + * ifaceGetIndex + * + * @reportError: whether to report errors or keep silent + * @ifname : Name of the interface whose index is to be found + * @ifindex: Pointer to int where the index will be written into + * + * Get the index of an interface given its name. + * + * Returns 0 on success, an error code on failure. + * ENODEV : if interface with given name does not exist + * EINVAL : if interface name is invalid (too long) + */ +int +ifaceGetIndex(bool reportError, const char *ifname, int *ifindex) +{ + int rc = 0; + struct ifreq ifreq; + int fd = socket(PF_PACKET, SOCK_DGRAM, 0); + + if (fd < 0) + return errno; + + if (virStrncpy(ifreq.ifr_name, ifname, strlen(ifname), + sizeof(ifreq.ifr_name)) == NULL) { + if (reportError) + ifaceError(VIR_ERR_INTERNAL_ERROR, + _("invalid interface name %s"), + ifname); + rc = EINVAL; + goto err_exit; + } + + if (ioctl(fd, SIOCGIFINDEX, &ifreq) >= 0) + *ifindex = ifreq.ifr_ifindex; + else { + if (reportError) + ifaceError(VIR_ERR_INTERNAL_ERROR, + _("interface %s does not exist"), + ifname); + rc = ENODEV; + } + +err_exit: + close(fd); + + return rc; +} diff --git a/src/util/interface.h b/src/util/interface.h new file mode 100644 index 0000000000000000000000000000000000000000..fc0ca1d3bcd39855fef4dcf83a09f4b606f7ecb4 --- /dev/null +++ b/src/util/interface.h @@ -0,0 +1,30 @@ +/* + * interface.h: interface helper APIs for libvirt + * + * Copyright (C) 2010 IBM Corporation, Inc. + * + * See COPYING.LIB for the License of this software + * + * Stefan Berger + */ +#ifndef __VIR_INTERFACE_H__ +# define __VIR_INTERFACE_H__ + +# include "datatypes.h" + +int ifaceCtrl(const char *name, bool up); + +static inline int ifaceUp(const char *name) { + return ifaceCtrl(name, true); +} + +static inline int ifaceDown(const char *name) { + return ifaceCtrl(name, false); +} + +int ifaceCheck(bool reportError, const char *ifname, + const unsigned char *macaddr, int ifindex); + +int ifaceGetIndex(bool reportError, const char *ifname, int *ifindex); + +#endif /* __VIR_INTERFACE_H__ */ diff --git a/src/util/macvtap.c b/src/util/macvtap.c index 2a99c6bde11ca29b339ec858413e89037f32daf9..5d129fd11a7bfb7964474a2f09d5a0b3a552ff5d 100644 --- a/src/util/macvtap.c +++ b/src/util/macvtap.c @@ -44,6 +44,7 @@ # include "util.h" # include "memory.h" # include "macvtap.h" +# include "interface.h" # include "conf/domain_conf.h" # include "virterror_internal.h" @@ -192,109 +193,6 @@ nlAppend(struct nlmsghdr *nlm, int totlen, const void *data, int datalen) } -static int -getIfIndex(bool reportError, - const char *ifname, - int *idx) -{ - int rc = 0; - struct ifreq ifreq; - int fd = socket(PF_PACKET, SOCK_DGRAM, 0); - - if (fd < 0) - return errno; - - if (virStrncpy(ifreq.ifr_name, ifname, strlen(ifname), - sizeof(ifreq.ifr_name)) == NULL) { - if (reportError) - macvtapError(VIR_ERR_INTERNAL_ERROR, - _("invalid interface name %s"), - ifname); - rc = EINVAL; - goto err_exit; - } - if (ioctl(fd, SIOCGIFINDEX, &ifreq) >= 0) - *idx = ifreq.ifr_ifindex; - else { - if (reportError) - macvtapError(VIR_ERR_INTERNAL_ERROR, - _("interface %s does not exist"), - ifname); - rc = ENODEV; - } - -err_exit: - close(fd); - - return rc; -} - - -/* - * chgIfFlags: Change flags on an interface - * @ifname : name of the interface - * @flagclear : the flags to clear - * @flagset : the flags to set - * - * The new flags of the interface will be calculated as - * flagmask = (~0 ^ flagclear) - * newflags = (curflags & flagmask) | flagset; - * - * Returns 0 on success, errno on failure. - */ -static int chgIfFlags(const char *ifname, short flagclear, short flagset) { - struct ifreq ifr; - int rc = 0; - int flags; - short flagmask = (~0 ^ flagclear); - int fd = socket(PF_PACKET, SOCK_DGRAM, 0); - - if (fd < 0) - return errno; - - if (virStrncpy(ifr.ifr_name, - ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) { - rc = ENODEV; - goto err_exit; - } - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { - rc = errno; - goto err_exit; - } - - flags = (ifr.ifr_flags & flagmask) | flagset; - - if (ifr.ifr_flags != flags) { - ifr.ifr_flags = flags; - - if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) - rc = errno; - } - -err_exit: - close(fd); - return rc; -} - -/* - * ifUp - * @name: name of the interface - * @up: 1 for up, 0 for down - * - * Function to control if an interface is activated (up, 1) or not (down, 0) - * - * Returns 0 in case of success or an errno code in case of failure. - */ -static int -ifUp(const char *name, int up) -{ - return chgIfFlags(name, - (up) ? 0 : IFF_UP, - (up) ? IFF_UP : 0); -} - - static int link_add(const char *type, const unsigned char *macaddress, int macaddrsize, @@ -314,7 +212,7 @@ link_add(const char *type, char *recvbuf = NULL; int recvbuflen; - if (getIfIndex(true, srcdev, &ifindex) != 0) + if (ifaceGetIndex(true, srcdev, &ifindex) != 0) return -1; *retry = 0; @@ -708,7 +606,7 @@ openMacvtapTap(const char *tgifname, *res_ifname = NULL; if (tgifname) { - if(getIfIndex(false, tgifname, &ifindex) == 0) { + if(ifaceGetIndex(false, tgifname, &ifindex) == 0) { if (STRPREFIX(tgifname, MACVTAP_NAME_PREFIX)) { goto create_name; @@ -727,7 +625,7 @@ create_name: retries = 5; for (c = 0; c < 8192; c++) { snprintf(ifname, sizeof(ifname), MACVTAP_NAME_PATTERN, c); - if (getIfIndex(false, ifname, &ifindex) == ENODEV) { + if (ifaceGetIndex(false, ifname, &ifindex) == ENODEV) { rc = link_add(type, macaddress, 6, ifname, linkdev, macvtapMode, &do_retry); if (rc == 0) @@ -741,7 +639,7 @@ create_name: cr_ifname = ifname; } - rc = ifUp(cr_ifname, 1); + rc = ifaceUp(cr_ifname); if (rc != 0) { virReportSystemError(errno, _("cannot 'up' interface %s -- another "