diff options
author | trasz <trasz@FreeBSD.org> | 2012-08-09 16:22:10 +0800 |
---|---|---|
committer | trasz <trasz@FreeBSD.org> | 2012-08-09 16:22:10 +0800 |
commit | 7e46da337552ec1ef47332cb8b926b9cc98e3aa2 (patch) | |
tree | 9368f9b7396f9da06e7bf9cf0af30e0166ae7d1d /net | |
parent | 4ab6763056ade78c1556b4d1b51ba5afc2a3e0fd (diff) | |
download | freebsd-ports-gnome-7e46da337552ec1ef47332cb8b926b9cc98e3aa2.tar.gz freebsd-ports-gnome-7e46da337552ec1ef47332cb8b926b9cc98e3aa2.tar.zst freebsd-ports-gnome-7e46da337552ec1ef47332cb8b926b9cc98e3aa2.zip |
Update to 1.7.0.
Big thanks to Ed Maste for making this happen.
Diffstat (limited to 'net')
-rw-r--r-- | net/openvswitch/Makefile | 22 | ||||
-rw-r--r-- | net/openvswitch/distinfo | 4 | ||||
-rw-r--r-- | net/openvswitch/files/ovsdb-server.in | 2 | ||||
-rw-r--r-- | net/openvswitch/files/patch-acinclude.m4 | 21 | ||||
-rw-r--r-- | net/openvswitch/files/patch-bsd-netdev.diff | 3188 | ||||
-rw-r--r-- | net/openvswitch/files/patch-lib-backtrace.c | 18 | ||||
-rw-r--r-- | net/openvswitch/files/patch-lib-dpif.c | 14 | ||||
-rw-r--r-- | net/openvswitch/files/patch-lib-netdev-bsd.c | 1581 | ||||
-rw-r--r-- | net/openvswitch/files/patch-porting.diff | 346 | ||||
-rw-r--r-- | net/openvswitch/pkg-plist | 74 |
10 files changed, 3254 insertions, 2016 deletions
diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 028c374a193b..bff31aa9e1d1 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile @@ -6,17 +6,9 @@ # PORTNAME= openvswitch -DISTVERSION= 1.1.0pre2 +PORTVERSION= 1.7.0 CATEGORIES= net MASTER_SITES= http://openvswitch.org/releases/ -#MASTER_SITE_SUBDIR= -#PKGNAMEPREFIX= -#PKGNAMESUFFIX= -#DISTNAME= -#EXTRACT_SUFX= -#DISTFILES= -#DIST_SUBDIR= ${PORTNAME} -#EXTRACT_ONLY= MAINTAINER= trasz@FreeBSD.org COMMENT= A production quality, multilayer virtual switch @@ -30,11 +22,13 @@ USE_AUTOTOOLS= autoconf automake USE_GNOME= pkgconfig USE_PYTHON= yes USE_RC_SUBR= ovs-vswitchd ovsdb-server -MAN1= ovsdb-tool.1 ovsdb-client.1 ovsdb-server.1 +MAN1= ovs-benchmark.1 ovs-pcap.1 ovs-tcpundump.1 ovsdb-client.1 \ + ovsdb-server.1 ovsdb-tool.1 MAN5= ovs-vswitchd.conf.db.5 -MAN8= ovs-appctl.8 ovs-controller.8 ovs-discover.8 ovs-dpctl.8 \ - ovs-kill.8 ovs-ofctl.8 ovs-openflowd.8 ovs-parse-leaks.8 \ - ovs-pki.8 ovs-vsctl.8 ovs-vswitchd.8 ovs-brcompatd.8 +MAN8= ovs-appctl.8 ovs-brcompatd.8 ovs-bugtool.8 ovs-controller.8 \ + ovs-ctl.8 ovs-dpctl.8 ovs-ofctl.8 ovs-parse-leaks.8 ovs-pki.8 \ + ovs-test.8 ovs-vsctl.8 ovs-vswitchd.8 \ + ovs-vlan-bug-workaround.8 ovs-vlan-test.8 .include <bsd.port.pre.mk> @@ -48,6 +42,8 @@ post-patch: @${REINPLACE_CMD} -e 's|1.11.1|%%AUTOMAKE_APIVER%%|g' \ -e 's|2.65|%%AUTOCONF_VERSION%%|g' \ ${WRKSRC}/aclocal.m4 + # Workaround for a makefile bug; if it builds without this line, remove it. + #${TOUCH} ${WRKSRC}/INSTALL post-install: ${INSTALL_DATA} ${WRKSRC}/vswitchd/vswitch.ovsschema ${PREFIX}/share/openvswitch/ diff --git a/net/openvswitch/distinfo b/net/openvswitch/distinfo index c82160c863f8..8c2d6b453f61 100644 --- a/net/openvswitch/distinfo +++ b/net/openvswitch/distinfo @@ -1,2 +1,2 @@ -SHA256 (openvswitch-1.1.0pre2.tar.gz) = af9eea41405c8ae10297c393fad54ee0b70d12e737962e2022dddf530573970b -SIZE (openvswitch-1.1.0pre2.tar.gz) = 1456628 +SHA256 (openvswitch-1.7.0.tar.gz) = 8e3942cbce80048fb2ce8077be5d35bbe50bb12a1feba33d7c1db68ce711eb53 +SIZE (openvswitch-1.7.0.tar.gz) = 2154289 diff --git a/net/openvswitch/files/ovsdb-server.in b/net/openvswitch/files/ovsdb-server.in index 4191a93e912b..fecbdc12abc2 100644 --- a/net/openvswitch/files/ovsdb-server.in +++ b/net/openvswitch/files/ovsdb-server.in @@ -31,7 +31,7 @@ ovsdb_server_precmd() { command_args="--detach --pidfile=$pidfile \ --remote=punix:$ovsdb_server_sock \ - --remote=db:Open_vSwitch,managers \ + --remote=db:Open_vSwitch,manager_options \ --private-key=db:SSL,private_key \ --certificate=db:SSL,certificate \ --bootstrap-ca-cert=db:SSL,ca_cert \ diff --git a/net/openvswitch/files/patch-acinclude.m4 b/net/openvswitch/files/patch-acinclude.m4 deleted file mode 100644 index 87c7938e899b..000000000000 --- a/net/openvswitch/files/patch-acinclude.m4 +++ /dev/null @@ -1,21 +0,0 @@ ---- acinclude.m4.orig 2010-09-10 23:36:43.000000000 +0200 -+++ acinclude.m4 2011-11-02 07:09:19.000000000 +0100 -@@ -220,6 +220,18 @@ - [Define to 1 if net/if_packet.h is available.]) - fi]) - -+dnl Checks for net/if_dl.h. -+AC_DEFUN([OVS_CHECK_IF_DL], -+ [AC_CHECK_HEADER([net/if_dl.h], -+ [HAVE_IF_DL=yes], -+ [HAVE_IF_DL=no]) -+ AM_CONDITIONAL([HAVE_IF_DL], [test "$HAVE_IF_DL" = yes]) -+ if test "$HAVE_IF_DL" = yes; then -+ AC_SEARCH_LIBS([pcap_create], [pcap]) -+ AC_DEFINE([HAVE_IF_DL], [1], -+ [Define to 1 if net/if_dl.h is available.]) -+ fi]) -+ - dnl Checks for buggy strtok_r. - dnl - dnl Some versions of glibc 2.7 has a bug in strtok_r when compiling diff --git a/net/openvswitch/files/patch-bsd-netdev.diff b/net/openvswitch/files/patch-bsd-netdev.diff new file mode 100644 index 000000000000..f8ca7428a277 --- /dev/null +++ b/net/openvswitch/files/patch-bsd-netdev.diff @@ -0,0 +1,3188 @@ +diff --git INSTALL INSTALL +new file mode 100644 +index 0000000..671c4a4 +--- /dev/null ++++ INSTALL +@@ -0,0 +1,341 @@ ++ How to Install Open vSwitch on Linux and FreeBSD ++ ================================================ ++ ++This document describes how to build and install Open vSwitch on a ++generic Linux or FreeBSD host. If you want to install Open vSwitch on ++a Citrix XenServer, see INSTALL.XenServer instead. ++ ++This version of Open vSwitch may be built manually with "configure" ++and "make", as described below. You may also build Debian packages by ++running "dpkg-buildpackage". ++ ++Build Requirements ++------------------ ++ ++To compile the userspace programs in the Open vSwitch distribution, ++you will need the following software: ++ ++ - A make program, e.g. GNU make. BSD make should also work. ++ ++ - The GNU C compiler. We generally test with version 4.1, 4.2, or ++ 4.3. ++ ++ - pkg-config. We test with version 0.22. ++ ++ - libssl, from OpenSSL, is optional but recommended if you plan to ++ connect the Open vSwitch to an OpenFlow controller. libssl is ++ required to establish confidentiality and authenticity in the ++ connections from an Open vSwitch to an OpenFlow controller. If ++ libssl is installed, then Open vSwitch will automatically build ++ with support for it. ++ ++To compile the kernel module on Linux, you must also install the ++following. If you cannot build or install the kernel module, you may ++use the userspace-only implementation, at a cost in performance. The ++userspace implementation may also lack some features. Refer to ++INSTALL.userspace for more information. ++ ++ - A supported Linux kernel version. Please refer to README for a ++ list of supported versions. ++ ++ The Open vSwitch datapath requires bridging support ++ (CONFIG_BRIDGE) to be built as a kernel module. (This is common ++ in kernels provided by Linux distributions.) The bridge module ++ must not be loaded or in use. If the bridge module is running ++ (check with "lsmod | grep bridge"), you must remove it ("rmmod ++ bridge") before starting the datapath. ++ ++ For optional support of ingress policing, you must enable kernel ++ configuration options NET_CLS_BASIC, NET_SCH_INGRESS, and ++ NET_ACT_POLICE, either built-in or as modules. (NET_CLS_POLICE is ++ obsolete and not needed.) ++ ++ If GRE tunneling is being used it is recommended that the kernel ++ be compiled with IPv6 support (CONFIG_IPV6). This allows for ++ special handling (such as path MTU discovery) of IPv6 packets. ++ ++ To configure HTB or HFSC quality of service with Open vSwitch, ++ you must enable the respective configuration options. ++ ++ To use Open vSwitch support for TAP devices, you must enable ++ CONFIG_TUN. ++ ++ - To build a kernel module, you need the same version of GCC that ++ was used to build that kernel. ++ ++ - A kernel build directory corresponding to the Linux kernel image ++ the module is to run on. Under Debian and Ubuntu, for example, ++ each linux-image package containing a kernel binary has a ++ corresponding linux-headers package with the required build ++ infrastructure. ++ ++If you are working from a Git tree or snapshot (instead of from a ++distribution tarball), or if you modify the Open vSwitch build system ++or the database schema, you will also need the following software: ++ ++ - Autoconf version 2.64 or later. ++ ++ - Automake version 1.10 or later. ++ ++ - Python 2.x, for x >= 4. ++ ++If you modify the ovsdbmonitor tool, then you will also need the ++following: ++ ++ - pyuic4 from PyQt4 (http://www.riverbankcomputing.co.uk). ++ ++To run the unit tests, you also need: ++ ++ - Perl. Version 5.10.1 is known to work. Earlier versions should ++ also work. ++ ++If you modify the vswitchd database schema, then the E-R diagram in ++the ovs-vswitchd.conf.db(5) manpage will be updated properly only if ++you have the following: ++ ++ - "dot" from graphviz (http://www.graphviz.org/). ++ ++ - Perl. Version 5.10.1 is known to work. Earlier versions should ++ also work. ++ ++ - Python 2.x, for x >= 4. ++ ++If you are going to extensively modify Open vSwitch, please consider ++installing the following to obtain better warnings: ++ ++ - "sparse" version 0.4.4 or later ++ (http://www.kernel.org/pub/software/devel/sparse/dist/). ++ ++ - GNU make. ++ ++Installation Requirements ++------------------------- ++ ++The machine on which Open vSwitch is to be installed must have the ++following software: ++ ++ - libc compatible with the libc used for build. ++ ++ - libssl compatible with the libssl used for build, if OpenSSL was ++ used for the build. ++ ++ - On Linux, the same kernel version configured as part of the build. ++ ++ - For optional support of ingress policing on Linux, the "tc" program ++ from iproute2 (part of all major distributions and available at ++ http://www.linux-foundation.org/en/Net:Iproute2). ++ ++On Linux you should ensure that /dev/urandom exists. To support TAP ++devices, you must also ensure that /dev/net/tun exists. ++ ++To run the ovsdbmonitor tool, the machine must also have the following ++software: ++ ++ - Python 2.x, for x >= 4. ++ ++ - Python Twisted Conch. ++ ++ - Python JSON. ++ ++ - PySide or PyQt4. ++ ++ - Python Zope interface module. ++ ++(On Debian "lenny" the above can be installed with "apt-get install ++python-json python-qt4 python-zopeinterface python-twisted-conch".) ++ ++Building and Installing Open vSwitch for Linux or FreeBSD ++========================================================= ++ ++Once you have installed all the prerequisites listed above in the Base ++Prerequisites section, follow the procedure below to build. ++ ++1. If you pulled the sources directly from an Open vSwitch Git tree, ++ run boot.sh in the top source directory: ++ ++ % ./boot.sh ++ ++2. In the top source directory, configure the package by running the ++ configure script. You can usually invoke configure without any ++ arguments: ++ ++ % ./configure ++ ++ By default all files are installed under /usr/local. If you want ++ to install into, e.g., /usr and /var instead of /usr/local and ++ /usr/local/var, add options as shown here: ++ ++ % ./configure --prefix=/usr --localstatedir=/var ++ ++ To use a specific C compiler for compiling Open vSwitch user ++ programs, also specify it on the configure command line, like so: ++ ++ % ./configure CC=gcc-4.2 ++ ++ To build the Linux kernel module, so that you can run the ++ kernel-based switch, pass the location of the kernel build ++ directory on --with-linux. For example, to build for a running ++ instance of Linux: ++ ++ % ./configure --with-linux=/lib/modules/`uname -r`/build ++ ++ If you wish to build the kernel module for an architecture other ++ than the architecture of the machine used for the build, you may ++ specify the kernel architecture string using the KARCH variable ++ when invoking the configure script. For example, to build for MIPS ++ with Linux: ++ ++ % ./configure --with-linux=/path/to/linux KARCH=mips ++ ++ The configure script accepts a number of other options and honors ++ additional environment variables. For a full list, invoke ++ configure with the --help option. ++ ++3. Run make in the top source directory: ++ ++ % make ++ ++ On FreeBSD you may need to use GNU make (gmake) or NetBSD make ++ (bmake) instead of the native make. ++ ++ For improved warnings if you installed "sparse" (see ++ "Prerequisites"), add C=1 to the "make" command line. ++ ++4. Become root by running "su" or another program. ++ ++5. Run "make install" to install the executables and manpages into the ++ running system, by default under /usr/local. ++ ++6. If you built kernel modules, you may load them with "insmod", e.g.: ++ ++ % insmod datapath/linux/openvswitch.ko ++ ++ You may need to specify a full path to insmod, e.g. /sbin/insmod. ++ To verify that the modules have been loaded, run "/sbin/lsmod" and ++ check that openvswitch is listed. ++ ++ If the "insmod" operation fails, look at the last few kernel log ++ messages (e.g. with "dmesg | tail"): ++ ++ - The message "openvswitch: exports duplicate symbol ++ br_should_route_hook (owned by bridge)" means that the bridge ++ module is loaded. Run "/sbin/rmmod bridge" to remove it. ++ ++ If "/sbin/rmmod bridge" fails with "ERROR: Module bridge does ++ not exist in /proc/modules", then the bridge is compiled into ++ the kernel, rather than as a module. Open vSwitch does not ++ support this configuration (see "Build Requirements", above). ++ ++ - The message "openvswitch: exports duplicate symbol ++ dp_ioctl_hook (owned by ofdatapath)" means that the ofdatapath ++ module from the OpenFlow reference implementation is loaded. ++ Run "/sbin/rmmod ofdatapath" to remove it. (You might have to ++ delete any existing datapaths beforehand, using the "dpctl" ++ program included with the OpenFlow reference implementation. ++ "ovs-dpctl" will not work.) ++ ++ - Otherwise, the most likely problem is that Open vSwitch was ++ built for a kernel different from the one into which you are ++ trying to load it. Run "modinfo" on openvswitch.ko and on ++ a module built for the running kernel, e.g.: ++ ++ % /sbin/modinfo openvswitch.ko ++ % /sbin/modinfo /lib/modules/`uname -r`/kernel/net/bridge/bridge.ko ++ ++ Compare the "vermagic" lines output by the two commands. If ++ they differ, then Open vSwitch was built for the wrong kernel. ++ ++ - If you decide to report a bug or ask a question related to ++ module loading, please include the output from the "dmesg" and ++ "modinfo" commands mentioned above. ++ ++ There is an optional module parameter to openvswitch.ko called ++ vlan_tso that enables TCP segmentation offload over VLANs on NICs ++ that support it. Many drivers do not expose support for TSO on VLANs ++ in a way that Open vSwitch can use but there is no way to detect ++ whether this is the case. If you know that your particular driver can ++ handle it (for example by testing sending large TCP packets over VLANs) ++ then passing in a value of 1 may improve performance. Modules built for ++ Linux kernels 2.6.37 and later, as well as specially patched versions ++ of earlier kernels, do not need this and do not have this parameter. If ++ you do not understand what this means or do not know if your driver ++ will work, do not set this. ++ ++7. Initialize the configuration database using ovsdb-tool, e.g.: ++ ++ % mkdir -p /usr/local/etc/openvswitch ++ % ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema ++ ++Startup ++======= ++ ++Before starting ovs-vswitchd itself, you need to start its ++configuration database, ovsdb-server. Each machine on which Open ++vSwitch is installed should run its own copy of ovsdb-server. ++Configure it to use the database you created during step 7 of ++installation, above, to listen on a Unix domain socket, to connect to ++any managers specified in the database itself, and to use the SSL ++configuration in the database: ++ ++ % ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \ ++ --remote=db:Open_vSwitch,manager_options \ ++ --private-key=db:SSL,private_key \ ++ --certificate=db:SSL,certificate \ ++ --bootstrap-ca-cert=db:SSL,ca_cert \ ++ --pidfile --detach ++ ++(If you built Open vSwitch without SSL support, then omit ++--private-key, --certificate, and --bootstrap-ca-cert.) ++ ++Then initialize the database using ovs-vsctl. This is only ++necessary the first time after you create the database with ++ovsdb-tool (but running it at any time is harmless): ++ ++ % ovs-vsctl --no-wait init ++ ++Then start the main Open vSwitch daemon, telling it to connect to the ++same Unix domain socket: ++ ++ % ovs-vswitchd --pidfile --detach ++ ++Now you may use ovs-vsctl to set up bridges and other Open vSwitch ++features. For example, to create a bridge named br0 and add ports ++eth0 and vif1.0 to it: ++ ++ % ovs-vsctl add-br br0 ++ % ovs-vsctl add-port br0 eth0 ++ % ovs-vsctl add-port br0 vif1.0 ++ ++Please refer to ovs-vsctl(8) for more details. ++ ++Upgrading ++========= ++ ++When you upgrade Open vSwitch from one version to another, you should ++also upgrade the database schema: ++ ++1. Stop the Open vSwitch daemons, e.g.: ++ ++ % kill `cd /usr/local/var/run/openvswitch && cat ovsdb-server.pid ovs-vswitchd.pid` ++ ++2. Install the new Open vSwitch release. ++ ++3. Upgrade the database, in one of the following two ways: ++ ++ - If there is no important data in your database, then you may ++ delete the database file and recreate it with ovsdb-tool, ++ following the instructions under "Building and Installing Open ++ vSwitch for Linux or FreeBSD". ++ ++ - If you want to preserve the contents of your database, back it ++ up first, then use "ovsdb-tool convert" to upgrade it, e.g.: ++ ++ % ovsdb-tool convert /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema ++ ++4. Start the Open vSwitch daemons as described under "Building and ++ Installing Open vSwitch for Linux or FreeBSD" above. ++ ++Bug Reporting ++------------- ++ ++Please report problems to bugs@openvswitch.org. +diff --git INSTALL.KVM INSTALL.KVM +index 61620e5..18a7bd4 100644 +--- INSTALL.KVM ++++ INSTALL.KVM +@@ -3,12 +3,12 @@ + + This document describes how to use Open vSwitch with the Kernel-based + Virtual Machine (KVM). This document assumes that you have read and +-followed INSTALL.Linux to get Open vSwitch setup on your Linux system. ++followed INSTALL to get Open vSwitch setup on your Linux system. + + Setup + ----- + +-First, follow the setup instructions in INSTALL.Linux to get a working ++First, follow the setup instructions in INSTALL to get a working + Open vSwitch installation. + + KVM uses tunctl to handle various bridging modes, which you can +@@ -43,7 +43,7 @@ switch='br0' + ovs-vsctl del-port ${switch} $1 + -------------------------------------------------------------------- + +-At the end of INSTALL.Linux, it describes basic usage of creating ++At the end of INSTALL, it describes basic usage of creating + bridges and ports. If you haven't already, create a bridge named + br0 with the following command: + +diff --git INSTALL.Libvirt INSTALL.Libvirt +index 4f31831..1bc45d5 100644 +--- INSTALL.Libvirt ++++ INSTALL.Libvirt +@@ -4,7 +4,7 @@ + This document describes how to use Open vSwitch with Libvirt 0.9.11 or + later. The Open vSwitch support in Libvirt 0.9.11 eliminates the need to + use OVS Linux Bridge compatibility layer (brcompatd) and interface up/down +-scripts. This document assumes that you followed INSTALL.Linux or installed ++scripts. This document assumes that you followed INSTALL or installed + Open vSwitch from distribution packaging such as a .deb or .rpm. The Open + vSwitch support is included by default in Libvirt 0.9.11. Consult + www.libvirt.org for instructions on how to build the latest Libvirt, if your +diff --git INSTALL.Linux INSTALL.Linux +deleted file mode 100644 +index 78152b6..0000000 +--- INSTALL.Linux ++++ /dev/null +@@ -1,338 +0,0 @@ +- How to Install Open vSwitch on Linux +- ==================================== +- +-This document describes how to build and install Open vSwitch on a +-generic Linux host. If you want to install Open vSwitch on a Citrix +-XenServer, see INSTALL.XenServer instead. +- +-This version of Open vSwitch may be built manually with "configure" +-and "make", as described below. You may also build Debian packages by +-running "dpkg-buildpackage". +- +-Build Requirements +------------------- +- +-To compile the userspace programs in the Open vSwitch distribution, +-you will need the following software: +- +- - A make program, e.g. GNU make. BSD make should also work. +- +- - The GNU C compiler. We generally test with version 4.1, 4.2, or +- 4.3. +- +- - pkg-config. We test with version 0.22. +- +- - libssl, from OpenSSL, is optional but recommended if you plan to +- connect the Open vSwitch to an OpenFlow controller. libssl is +- required to establish confidentiality and authenticity in the +- connections from an Open vSwitch to an OpenFlow controller. If +- libssl is installed, then Open vSwitch will automatically build +- with support for it. +- +-To compile the kernel module, you must also install the following. If +-you cannot build or install the kernel module, you may use the +-userspace-only implementation, at a cost in performance. The +-userspace implementation may also lack some features. Refer to +-INSTALL.userspace for more information. +- +- - A supported Linux kernel version. Please refer to README for a +- list of supported versions. +- +- The Open vSwitch datapath requires bridging support +- (CONFIG_BRIDGE) to be built as a kernel module. (This is common +- in kernels provided by Linux distributions.) The bridge module +- must not be loaded or in use. If the bridge module is running +- (check with "lsmod | grep bridge"), you must remove it ("rmmod +- bridge") before starting the datapath. +- +- For optional support of ingress policing, you must enable kernel +- configuration options NET_CLS_BASIC, NET_SCH_INGRESS, and +- NET_ACT_POLICE, either built-in or as modules. (NET_CLS_POLICE is +- obsolete and not needed.) +- +- If GRE tunneling is being used it is recommended that the kernel +- be compiled with IPv6 support (CONFIG_IPV6). This allows for +- special handling (such as path MTU discovery) of IPv6 packets. +- +- To configure HTB or HFSC quality of service with Open vSwitch, +- you must enable the respective configuration options. +- +- To use Open vSwitch support for TAP devices, you must enable +- CONFIG_TUN. +- +- - To build a kernel module, you need the same version of GCC that +- was used to build that kernel. +- +- - A kernel build directory corresponding to the Linux kernel image +- the module is to run on. Under Debian and Ubuntu, for example, +- each linux-image package containing a kernel binary has a +- corresponding linux-headers package with the required build +- infrastructure. +- +-If you are working from a Git tree or snapshot (instead of from a +-distribution tarball), or if you modify the Open vSwitch build system +-or the database schema, you will also need the following software: +- +- - Autoconf version 2.64 or later. +- +- - Automake version 1.10 or later. +- +- - Python 2.x, for x >= 4. +- +-If you modify the ovsdbmonitor tool, then you will also need the +-following: +- +- - pyuic4 from PyQt4 (http://www.riverbankcomputing.co.uk). +- +-To run the unit tests, you also need: +- +- - Perl. Version 5.10.1 is known to work. Earlier versions should +- also work. +- +-If you modify the vswitchd database schema, then the E-R diagram in +-the ovs-vswitchd.conf.db(5) manpage will be updated properly only if +-you have the following: +- +- - "dot" from graphviz (http://www.graphviz.org/). +- +- - Perl. Version 5.10.1 is known to work. Earlier versions should +- also work. +- +- - Python 2.x, for x >= 4. +- +-If you are going to extensively modify Open vSwitch, please consider +-installing the following to obtain better warnings: +- +- - "sparse" version 0.4.4 or later +- (http://www.kernel.org/pub/software/devel/sparse/dist/). +- +- - GNU make. +- +-Installation Requirements +-------------------------- +- +-The machine on which Open vSwitch is to be installed must have the +-following software: +- +- - libc compatible with the libc used for build. +- +- - libssl compatible with the libssl used for build, if OpenSSL was +- used for the build. +- +- - The Linux kernel version configured as part of the build. +- +- - For optional support of ingress policing, the "tc" program from +- iproute2 (part of all major distributions and available at +- http://www.linux-foundation.org/en/Net:Iproute2). +- +-You should ensure that /dev/urandom exists. To support TAP devices, +-you must also ensure that /dev/net/tun exists. +- +-To run the ovsdbmonitor tool, the machine must also have the following +-software: +- +- - Python 2.x, for x >= 4. +- +- - Python Twisted Conch. +- +- - Python JSON. +- +- - PySide or PyQt4. +- +- - Python Zope interface module. +- +-(On Debian "lenny" the above can be installed with "apt-get install +-python-json python-qt4 python-zopeinterface python-twisted-conch".) +- +-Building and Installing Open vSwitch for Linux +-============================================== +- +-Once you have installed all the prerequisites listed above in the Base +-Prerequisites section, follow the procedure below to build. +- +-1. If you pulled the sources directly from an Open vSwitch Git tree, +- run boot.sh in the top source directory: +- +- % ./boot.sh +- +-2. In the top source directory, configure the package by running the +- configure script. You can usually invoke configure without any +- arguments: +- +- % ./configure +- +- By default all files are installed under /usr/local. If you want +- to install into, e.g., /usr and /var instead of /usr/local and +- /usr/local/var, add options as shown here: +- +- % ./configure --prefix=/usr --localstatedir=/var +- +- To use a specific C compiler for compiling Open vSwitch user +- programs, also specify it on the configure command line, like so: +- +- % ./configure CC=gcc-4.2 +- +- To build the Linux kernel module, so that you can run the +- kernel-based switch, pass the location of the kernel build +- directory on --with-linux. For example, to build for a running +- instance of Linux: +- +- % ./configure --with-linux=/lib/modules/`uname -r`/build +- +- If you wish to build the kernel module for an architecture other +- than the architecture of the machine used for the build, you may +- specify the kernel architecture string using the KARCH variable +- when invoking the configure script. For example, to build for MIPS +- with Linux: +- +- % ./configure --with-linux=/path/to/linux KARCH=mips +- +- The configure script accepts a number of other options and honors +- additional environment variables. For a full list, invoke +- configure with the --help option. +- +-3. Run make in the top source directory: +- +- % make +- +- For improved warnings if you installed "sparse" (see +- "Prerequisites"), add C=1 to the "make" command line. +- +-4. Become root by running "su" or another program. +- +-5. Run "make install" to install the executables and manpages into the +- running system, by default under /usr/local. +- +-6. If you built kernel modules, you may load them with "insmod", e.g.: +- +- % insmod datapath/linux/openvswitch.ko +- +- You may need to specify a full path to insmod, e.g. /sbin/insmod. +- To verify that the modules have been loaded, run "/sbin/lsmod" and +- check that openvswitch is listed. +- +- If the "insmod" operation fails, look at the last few kernel log +- messages (e.g. with "dmesg | tail"): +- +- - The message "openvswitch: exports duplicate symbol +- br_should_route_hook (owned by bridge)" means that the bridge +- module is loaded. Run "/sbin/rmmod bridge" to remove it. +- +- If "/sbin/rmmod bridge" fails with "ERROR: Module bridge does +- not exist in /proc/modules", then the bridge is compiled into +- the kernel, rather than as a module. Open vSwitch does not +- support this configuration (see "Build Requirements", above). +- +- - The message "openvswitch: exports duplicate symbol +- dp_ioctl_hook (owned by ofdatapath)" means that the ofdatapath +- module from the OpenFlow reference implementation is loaded. +- Run "/sbin/rmmod ofdatapath" to remove it. (You might have to +- delete any existing datapaths beforehand, using the "dpctl" +- program included with the OpenFlow reference implementation. +- "ovs-dpctl" will not work.) +- +- - Otherwise, the most likely problem is that Open vSwitch was +- built for a kernel different from the one into which you are +- trying to load it. Run "modinfo" on openvswitch.ko and on +- a module built for the running kernel, e.g.: +- +- % /sbin/modinfo openvswitch.ko +- % /sbin/modinfo /lib/modules/`uname -r`/kernel/net/bridge/bridge.ko +- +- Compare the "vermagic" lines output by the two commands. If +- they differ, then Open vSwitch was built for the wrong kernel. +- +- - If you decide to report a bug or ask a question related to +- module loading, please include the output from the "dmesg" and +- "modinfo" commands mentioned above. +- +- There is an optional module parameter to openvswitch.ko called +- vlan_tso that enables TCP segmentation offload over VLANs on NICs +- that support it. Many drivers do not expose support for TSO on VLANs +- in a way that Open vSwitch can use but there is no way to detect +- whether this is the case. If you know that your particular driver can +- handle it (for example by testing sending large TCP packets over VLANs) +- then passing in a value of 1 may improve performance. Modules built for +- Linux kernels 2.6.37 and later, as well as specially patched versions +- of earlier kernels, do not need this and do not have this parameter. If +- you do not understand what this means or do not know if your driver +- will work, do not set this. +- +-7. Initialize the configuration database using ovsdb-tool, e.g.: +- +- % mkdir -p /usr/local/etc/openvswitch +- % ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema +- +-Startup +-======= +- +-Before starting ovs-vswitchd itself, you need to start its +-configuration database, ovsdb-server. Each machine on which Open +-vSwitch is installed should run its own copy of ovsdb-server. +-Configure it to use the database you created during step 7 of +-installation, above, to listen on a Unix domain socket, to connect to +-any managers specified in the database itself, and to use the SSL +-configuration in the database: +- +- % ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \ +- --remote=db:Open_vSwitch,manager_options \ +- --private-key=db:SSL,private_key \ +- --certificate=db:SSL,certificate \ +- --bootstrap-ca-cert=db:SSL,ca_cert \ +- --pidfile --detach +- +-(If you built Open vSwitch without SSL support, then omit +---private-key, --certificate, and --bootstrap-ca-cert.) +- +-Then initialize the database using ovs-vsctl. This is only +-necessary the first time after you create the database with +-ovsdb-tool (but running it at any time is harmless): +- +- % ovs-vsctl --no-wait init +- +-Then start the main Open vSwitch daemon, telling it to connect to the +-same Unix domain socket: +- +- % ovs-vswitchd --pidfile --detach +- +-Now you may use ovs-vsctl to set up bridges and other Open vSwitch +-features. For example, to create a bridge named br0 and add ports +-eth0 and vif1.0 to it: +- +- % ovs-vsctl add-br br0 +- % ovs-vsctl add-port br0 eth0 +- % ovs-vsctl add-port br0 vif1.0 +- +-Please refer to ovs-vsctl(8) for more details. +- +-Upgrading +-========= +- +-When you upgrade Open vSwitch from one version to another, you should +-also upgrade the database schema: +- +-1. Stop the Open vSwitch daemons, e.g.: +- +- % kill `cd /usr/local/var/run/openvswitch && cat ovsdb-server.pid ovs-vswitchd.pid` +- +-2. Install the new Open vSwitch release. +- +-3. Upgrade the database, in one of the following two ways: +- +- - If there is no important data in your database, then you may +- delete the database file and recreate it with ovsdb-tool, +- following the instructions under "Building and Installing Open +- vSwitch for Linux". +- +- - If you want to preserve the contents of your database, back it +- up first, then use "ovsdb-tool convert" to upgrade it, e.g.: +- +- % ovsdb-tool convert /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema +- +-4. Start the Open vSwitch daemons as described under "Building and +- Installing Open vSwitch for Linux" above. +- +-Bug Reporting +-------------- +- +-Please report problems to bugs@openvswitch.org. +diff --git INSTALL.RHEL INSTALL.RHEL +index 039a857..ff79c89 100644 +--- INSTALL.RHEL ++++ INSTALL.RHEL +@@ -3,7 +3,7 @@ + + This document describes how to build and install Open vSwitch on a Red + Hat Enterprise Linux (RHEL) host. If you want to install Open vSwitch +-on a generic Linux host, see INSTALL.Linux instead. ++on a generic Linux host, see INSTALL instead. + + We have tested these instructions with RHEL 5.6 and RHEL 6.0. + +diff --git INSTALL.SSL INSTALL.SSL +index f322b41..8511b69 100644 +--- INSTALL.SSL ++++ INSTALL.SSL +@@ -7,8 +7,8 @@ with OpenSSL. SSL support ensures integrity and confidentiality of + the OpenFlow connections, increasing network security. + + This file explains how to configure an Open vSwitch to connect to an +-OpenFlow controller over SSL. Refer to INSTALL.Linux for instructions +-on building Open vSwitch with SSL support. ++OpenFlow controller over SSL. Refer to INSTALL for instructions on ++building Open vSwitch with SSL support. + + Open vSwitch uses TLS version 1.0 or later (TLSv1), as specified by + RFC 2246, which is very similar to SSL version 3.0. TLSv1 was +diff --git INSTALL.XenServer INSTALL.XenServer +index e45d5bc..7a4dd76 100644 +--- INSTALL.XenServer ++++ INSTALL.XenServer +@@ -3,7 +3,7 @@ + + This document describes how to build and install Open vSwitch on a + Citrix XenServer host. If you want to install Open vSwitch on a +-generic Linux host, see INSTALL.Linux instead. ++generic Linux or BSD host, see INSTALL instead. + + These instructions have been tested with XenServer 5.6 FP1. + +@@ -19,8 +19,8 @@ RPMs for Citrix XenServer is the DDK VM available from Citrix. + ./configure; make dist" in the Git tree. You cannot run this in + the DDK VM, because it lacks tools that are necessary to bootstrap + the Open vSwitch distribution. Instead, you must run this on a +- machine that has the tools listed in INSTALL.Linux as prerequisites +- for building from a Git tree. ++ machine that has the tools listed in INSTALL as prerequisites for ++ building from a Git tree. + + 2. Copy the distribution tarball into /usr/src/redhat/SOURCES inside + the DDK VM. +diff --git INSTALL.bridge INSTALL.bridge +index dec09d8..af20bff 100644 +--- INSTALL.bridge ++++ INSTALL.bridge +@@ -25,7 +25,7 @@ that the Open vSwitch kernel modules are loaded before the Linux + kernel bridge module. + + 1. Build, install, and start up the Open vSwitch kernel modules and +- userspace programs as described in INSTALL.Linux. ++ userspace programs as described in INSTALL. + + It is important to run "make install", because some Open vSwitch + programs expect to find files in locations selected at installation +diff --git INSTALL.userspace INSTALL.userspace +index 6e6fcd4..feb108c 100644 +--- INSTALL.userspace ++++ INSTALL.userspace +@@ -17,7 +17,7 @@ Building and Installing + ----------------------- + + The requirements and procedure for building, installing, and +-configuring Open vSwitch are the same as those given in INSTALL.Linux. ++configuring Open vSwitch are the same as those given in INSTALL. + You may omit configuring, building, and installing the kernel module, + and the related requirements. + +@@ -31,6 +31,10 @@ The tun device must also exist as /dev/net/tun. If it does not exist, + then create /dev/net (if necessary) with "mkdir /dev/net", then create + /dev/net/tun with "mknod /dev/net/tun c 10 200". + ++On FreeBSD, the userspace switch additionally requires the kernel ++tap(4) driver to be available, either built into the kernel or loaded ++as a module. ++ + Using the Userspace Datapath with ovs-vswitchd + ---------------------------------------------- + +diff --git Makefile.am Makefile.am +index 91adf05..cbe94a6 100644 +--- Makefile.am ++++ Makefile.am +@@ -33,9 +33,9 @@ PYCOV_CLEAN_FILES = build-aux/check-structs,cover + EXTRA_DIST = \ + CodingStyle \ + DESIGN \ ++ INSTALL \ + INSTALL.KVM \ + INSTALL.Libvirt \ +- INSTALL.Linux \ + INSTALL.RHEL \ + INSTALL.SSL \ + INSTALL.XenServer \ +diff --git NOTICE NOTICE +index 912d7b8..dafd25f 100644 +--- NOTICE ++++ NOTICE +@@ -4,6 +4,9 @@ available at http://www.apache.org/licenses/LICENSE-2.0.html + Open vSwitch + Copyright (c) 2007, 2008, 2009, 2010, 2011 Nicira, Inc. + ++Open vSwitch BSD port ++Copyright (c) 2011 Gaetano Catalli ++ + Apache Portable Runtime + Copyright 2008 The Apache Software Foundation. + +diff --git README README +index 251a92e..3ce45b7 100644 +--- README ++++ README +@@ -88,7 +88,7 @@ Open vSwitch also provides some tools: + What other documentation is available? + -------------------------------------- + +-To install Open vSwitch on a regular Linux machine, read INSTALL.Linux. ++To install Open vSwitch on a regular Linux machine, read INSTALL. + + To use Open vSwitch as a drop-in replacement for the Linux bridge, + read INSTALL.bridge. +@@ -99,7 +99,7 @@ or resource pool, read INSTALL.XenServer. + To build RPMs for installing Open vSwitch on a Red Hat Enterprise + Linux host, read INSTALL.RHEL. + +-To use Open vSwitch with KVM on Linux, read INSTALL.Linux, then ++To use Open vSwitch with KVM on Linux, read INSTALL, then + INSTALL.KVM. + + To use Open vSwitch with Libvirt, read INSTALL.Libvirt. +diff --git acinclude.m4 acinclude.m4 +index d33653d..51e784b 100644 +--- acinclude.m4 ++++ acinclude.m4 +@@ -287,6 +287,17 @@ AC_DEFUN([OVS_CHECK_IF_PACKET], + [Define to 1 if net/if_packet.h is available.]) + fi]) + ++dnl Checks for net/if_dl.h. ++AC_DEFUN([OVS_CHECK_IF_DL], ++ [AC_CHECK_HEADER([net/if_dl.h], ++ [HAVE_IF_DL=yes], ++ [HAVE_IF_DL=no]) ++ AM_CONDITIONAL([HAVE_IF_DL], [test "$HAVE_IF_DL" = yes]) ++ if test "$HAVE_IF_DL" = yes; then ++ AC_DEFINE([HAVE_IF_DL], [1], ++ [Define to 1 if net/if_dl.h is available.]) ++ fi]) ++ + dnl Checks for buggy strtok_r. + dnl + dnl Some versions of glibc 2.7 has a bug in strtok_r when compiling +diff --git configure.ac configure.ac +index 1160cdb..5692b86 100644 +--- configure.ac ++++ configure.ac +@@ -41,6 +41,7 @@ AC_SYS_LARGEFILE + AC_SEARCH_LIBS([pow], [m]) + AC_SEARCH_LIBS([clock_gettime], [rt]) + AC_SEARCH_LIBS([timer_create], [rt]) ++AC_SEARCH_LIBS([pcap_open_live], [pcap]) + + OVS_CHECK_COVERAGE + OVS_CHECK_NDEBUG +@@ -52,6 +53,7 @@ OVS_CHECK_PYUIC4 + OVS_CHECK_OVSDBMONITOR + OVS_CHECK_DOT + OVS_CHECK_IF_PACKET ++OVS_CHECK_IF_DL + OVS_CHECK_STRTOK_R + AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec], + [], [], [[#include <sys/stat.h>]]) +diff --git debian/copyright.in debian/copyright.in +index 71aa680..16e5559 100644 +--- debian/copyright.in ++++ debian/copyright.in +@@ -12,6 +12,7 @@ Upstream Copyright Holders: + Copyright (c) 2010 Jean Tourrilhes - HP-Labs. + Copyright (c) 2008,2009,2010 Citrix Systems, Inc. + and authors listed above. ++ Copyright (c) 2011 Gaetano Catalli + + License: + +diff --git lib/automake.mk lib/automake.mk +index 6217526..13622b3 100644 +--- lib/automake.mk ++++ lib/automake.mk +@@ -230,6 +230,14 @@ lib_libopenvswitch_a_SOURCES += \ + lib/route-table.h + endif + ++if HAVE_IF_DL ++lib_libopenvswitch_a_SOURCES += \ ++ lib/netdev-bsd.c \ ++ lib/rtbsd.c \ ++ lib/rtbsd.h \ ++ lib/route-table-bsd.c ++endif ++ + if HAVE_OPENSSL + lib_libopenvswitch_a_SOURCES += lib/stream-ssl.c + nodist_lib_libopenvswitch_a_SOURCES += lib/dhparams.c +diff --git lib/netdev-bsd.c lib/netdev-bsd.c +new file mode 100644 +index 0000000..0b1a37c +--- /dev/null ++++ lib/netdev-bsd.c +@@ -0,0 +1,1485 @@ ++/* ++ * Copyright (c) 2011 Gaetano Catalli. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include <config.h> ++ ++#include <stdlib.h> ++#include <config.h> ++#include <assert.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <sys/types.h> ++#include <sys/time.h> ++#include <sys/ioctl.h> ++#include <sys/socket.h> ++#include <sys/sockio.h> ++#include <ifaddrs.h> ++#include <pcap/pcap.h> ++#include <net/if.h> ++#include <net/if_dl.h> ++#include <net/if_media.h> ++#include <net/if_tap.h> ++#include <netinet/in.h> ++#include <net/if_mib.h> ++#include <poll.h> ++#include <string.h> ++#include <unistd.h> ++#include <sys/sysctl.h> ++ ++#include "rtbsd.h" ++#include "coverage.h" ++#include "dynamic-string.h" ++#include "fatal-signal.h" ++#include "netdev-provider.h" ++#include "ofpbuf.h" ++#include "openflow/openflow.h" ++#include "packets.h" ++#include "poll-loop.h" ++#include "socket-util.h" ++#include "shash.h" ++#include "svec.h" ++#include "vlog.h" ++ ++VLOG_DEFINE_THIS_MODULE(netdev_bsd); ++ ++ ++/* ++ * This file implements objects to access interfaces. ++ * Externally, interfaces are represented by two structures: ++ * + struct netdev_dev, representing a network device, ++ * containing e.g. name and a refcount; ++ * We can have private variables by embedding the ++ * struct netdev_dev into our own structure ++ * (e.g. netdev_dev_bsd) ++ * ++ * + struct netdev, representing an instance of an open netdev_dev. ++ * The structure contains a pointer to the 'struct netdev' ++ * representing the device. Again, private information ++ * such as file descriptor etc. are stored in our ++ * own struct netdev_bsd which includes a struct netdev. ++ * ++ * Both 'struct netdev' and 'struct netdev_dev' are referenced ++ * in containers which hold pointers to the data structures. ++ * We can reach our own struct netdev_XXX_bsd by putting a ++ * struct netdev_XXX within our own struct, and using CONTAINER_OF ++ * to access the parent structure. ++ */ ++struct netdev_bsd { ++ struct netdev netdev; ++ ++ int netdev_fd; /* Selectable file descriptor for the network device. ++ This descriptor will be used for polling operations */ ++ ++ pcap_t *pcap_handle; /* Packet capture descriptor for a system network ++ device */ ++}; ++ ++struct netdev_dev_bsd { ++ struct netdev_dev netdev_dev; ++ unsigned int cache_valid; ++ unsigned int change_seq; ++ ++ int ifindex; ++ uint8_t etheraddr[ETH_ADDR_LEN]; ++ struct in_addr in4; ++ struct in6_addr in6; ++ int mtu; ++ int carrier; ++ ++ bool tap_opened; ++ int tap_fd; /* TAP character device, if any */ ++}; ++ ++ ++enum { ++ VALID_IFINDEX = 1 << 0, ++ VALID_ETHERADDR = 1 << 1, ++ VALID_IN4 = 1 << 2, ++ VALID_IN6 = 1 << 3, ++ VALID_MTU = 1 << 4, ++ VALID_CARRIER = 1 << 5 ++}; ++ ++/* An AF_INET socket (used for ioctl operations). */ ++static int af_inet_sock = -1; ++ ++#define PCAP_SNAPLEN 2048 ++ ++ ++/* ++ * Notifier used to invalidate device informations in case of status change. ++ * ++ * It will be registered with a 'rtbsd_notifier_register()' when the first ++ * device will be created with the call of either 'netdev_bsd_tap_create()' or ++ * 'netdev_bsd_system_create()'. ++ * ++ * The callback associated with this notifier ('netdev_bsd_cache_cb()') will ++ * invalidate cached information about the device. ++ */ ++static struct rtbsd_notifier netdev_bsd_cache_notifier; ++static int cache_notifier_refcount; ++ ++static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); ++ ++static int netdev_bsd_do_ioctl(const struct netdev *, struct ifreq *, ++ unsigned long cmd, const char *cmd_name); ++static void destroy_tap(int fd, const char *name); ++static int get_flags(const struct netdev *, int *flagsp); ++static int set_flags(struct netdev *, int flags); ++static int do_set_addr(struct netdev *netdev, ++ int ioctl_nr, const char *ioctl_name, ++ struct in_addr addr); ++static int get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]); ++static int set_etheraddr(const char *netdev_name, int hwaddr_family, ++ int hwaddr_len, const uint8_t[ETH_ADDR_LEN]); ++static int get_ifindex(const struct netdev *, int *ifindexp); ++ ++static int netdev_bsd_init(void); ++ ++static bool ++is_netdev_bsd_class(const struct netdev_class *netdev_class) ++{ ++ return netdev_class->init == netdev_bsd_init; ++} ++ ++static struct netdev_bsd * ++netdev_bsd_cast(const struct netdev *netdev) ++{ ++ assert(is_netdev_bsd_class(netdev_dev_get_class(netdev_get_dev(netdev)))); ++ return CONTAINER_OF(netdev, struct netdev_bsd, netdev); ++} ++ ++static struct netdev_dev_bsd * ++netdev_dev_bsd_cast(const struct netdev_dev *netdev_dev) ++{ ++ assert(is_netdev_bsd_class(netdev_dev_get_class(netdev_dev))); ++ return CONTAINER_OF(netdev_dev, struct netdev_dev_bsd, netdev_dev); ++} ++ ++/* Initialize the AF_INET socket used for ioctl operations */ ++static int ++netdev_bsd_init(void) ++{ ++ static int status = -1; ++ ++ if (status >= 0) { /* already initialized */ ++ return status; ++ } ++ ++ af_inet_sock = socket(AF_INET, SOCK_DGRAM, 0); ++ status = af_inet_sock >= 0 ? 0 : errno; ++ ++ if (status) { ++ VLOG_ERR("failed to create inet socket: %s", strerror(status)); ++ } ++ ++ return status; ++} ++ ++/* ++ * Perform periodic work needed by netdev. In BSD netdevs it checks for any ++ * interface status changes, and eventually calls all the user callbacks. ++ */ ++static void ++netdev_bsd_run(void) ++{ ++ rtbsd_notifier_run(); ++} ++ ++/* ++ * Arranges for poll_block() to wake up if the "run" member function needs to ++ * be called. ++ */ ++static void ++netdev_bsd_wait(void) ++{ ++ rtbsd_notifier_wait(); ++} ++ ++static void ++netdev_dev_bsd_changed(struct netdev_dev_bsd *dev) ++{ ++ dev->change_seq++; ++ if (!dev->change_seq) { ++ dev->change_seq++; ++ } ++} ++ ++/* Invalidate cache in case of interface status change. */ ++static void ++netdev_bsd_cache_cb(const struct rtbsd_change *change, ++ void *aux OVS_UNUSED) ++{ ++ struct netdev_dev_bsd *dev; ++ ++ if (change) { ++ struct netdev_dev *base_dev = netdev_dev_from_name(change->if_name); ++ ++ if (base_dev) { ++ const struct netdev_class *netdev_class = ++ netdev_dev_get_class(base_dev); ++ ++ if (is_netdev_bsd_class(netdev_class)) { ++ dev = netdev_dev_bsd_cast(base_dev); ++ dev->cache_valid = 0; ++ netdev_dev_bsd_changed(dev); ++ } ++ } ++ } else { ++ /* ++ * XXX the API is lacking, we should be able to iterate on the list of ++ * netdevs without having to store the info in a temp shash. ++ */ ++ struct shash device_shash; ++ struct shash_node *node; ++ ++ shash_init(&device_shash); ++ netdev_dev_get_devices(&netdev_bsd_class, &device_shash); ++ SHASH_FOR_EACH (node, &device_shash) { ++ dev = node->data; ++ dev->cache_valid = 0; ++ netdev_dev_bsd_changed(dev); ++ } ++ shash_destroy(&device_shash); ++ } ++} ++ ++static int ++cache_notifier_ref(void) ++{ ++ int ret = 0; ++ ++ if (!cache_notifier_refcount) { ++ ret = rtbsd_notifier_register(&netdev_bsd_cache_notifier, ++ netdev_bsd_cache_cb, NULL); ++ if (ret) { ++ return ret; ++ } ++ } ++ cache_notifier_refcount++; ++ return 0; ++} ++ ++static int ++cache_notifier_unref(void) ++{ ++ cache_notifier_refcount--; ++ if (cache_notifier_refcount == 0) { ++ rtbsd_notifier_unregister(&netdev_bsd_cache_notifier); ++ } ++ return 0; ++} ++ ++/* Allocate a netdev_dev_bsd structure */ ++static int ++netdev_bsd_create_system(const struct netdev_class *class, const char *name, ++ struct netdev_dev **netdev_devp) ++{ ++ struct netdev_dev_bsd *netdev_dev; ++ int error; ++ ++ error = cache_notifier_ref(); ++ if (error) { ++ return error; ++ } ++ ++ netdev_dev = xzalloc(sizeof *netdev_dev); ++ netdev_dev->change_seq = 1; ++ netdev_dev_init(&netdev_dev->netdev_dev, name, class); ++ *netdev_devp = &netdev_dev->netdev_dev; ++ ++ return 0; ++} ++ ++/* ++ * Allocate a netdev_dev_bsd structure with 'tap' class. ++ */ ++static int ++netdev_bsd_create_tap(const struct netdev_class *class, const char *name, ++ struct netdev_dev **netdev_devp) ++{ ++ struct netdev_dev_bsd *netdev_dev = NULL; ++ int error = 0; ++ struct ifreq ifr; ++ ++ error = cache_notifier_ref(); ++ if (error) { ++ goto error; ++ } ++ ++ /* allocate the device structure and set the internal flag */ ++ netdev_dev = xzalloc(sizeof *netdev_dev); ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ ++ /* Create a tap device by opening /dev/tap. The TAPGIFNAME ioctl is used ++ * to retrieve the name of the tap device. */ ++ netdev_dev->tap_fd = open("/dev/tap", O_RDWR); ++ netdev_dev->change_seq = 1; ++ if (netdev_dev->tap_fd < 0) { ++ error = errno; ++ VLOG_WARN("opening \"/dev/tap\" failed: %s", strerror(error)); ++ goto error_undef_notifier; ++ } ++ ++ /* Retrieve tap name (e.g. tap0) */ ++ if (ioctl(netdev_dev->tap_fd, TAPGIFNAME, &ifr) == -1) { ++ /* XXX Need to destroy the device? */ ++ error = errno; ++ goto error_undef_notifier; ++ } ++ ++ /* Change the name of the tap device */ ++ ifr.ifr_data = (void *)name; ++ if (ioctl(af_inet_sock, SIOCSIFNAME, &ifr) == -1) { ++ error = errno; ++ destroy_tap(netdev_dev->tap_fd, ifr.ifr_name); ++ goto error_undef_notifier; ++ } ++ ++ /* set non-blocking. */ ++ error = set_nonblocking(netdev_dev->tap_fd); ++ if (error) { ++ destroy_tap(netdev_dev->tap_fd, name); ++ goto error_undef_notifier; ++ } ++ ++ /* Turn device UP */ ++ ifr.ifr_flags = (uint16_t)IFF_UP; ++ ifr.ifr_flagshigh = 0; ++ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); ++ if (ioctl(af_inet_sock, SIOCSIFFLAGS, &ifr) == -1) { ++ error = errno; ++ destroy_tap(netdev_dev->tap_fd, name); ++ goto error_undef_notifier; ++ } ++ ++ /* initialize the device structure and ++ * link the structure to its netdev */ ++ netdev_dev_init(&netdev_dev->netdev_dev, name, class); ++ *netdev_devp = &netdev_dev->netdev_dev; ++ ++ return 0; ++ ++error_undef_notifier: ++ cache_notifier_unref(); ++error: ++ free(netdev_dev); ++ return error; ++} ++ ++static void ++netdev_bsd_destroy(struct netdev_dev *netdev_dev_) ++{ ++ struct netdev_dev_bsd *netdev_dev = netdev_dev_bsd_cast(netdev_dev_); ++ ++ cache_notifier_unref(); ++ ++ if (netdev_dev->tap_fd >= 0 && ++ !strcmp(netdev_dev_get_type(netdev_dev_), "tap")) { ++ destroy_tap(netdev_dev->tap_fd, netdev_dev_get_name(netdev_dev_)); ++ } ++ free(netdev_dev); ++} ++ ++ ++static int ++netdev_bsd_open_system(struct netdev_dev *netdev_dev_, struct netdev **netdevp) ++{ ++ struct netdev_dev_bsd *netdev_dev = netdev_dev_bsd_cast(netdev_dev_); ++ struct netdev_bsd *netdev; ++ int error; ++ enum netdev_flags flags; ++ ++ /* Allocate network device. */ ++ netdev = xcalloc(1, sizeof *netdev); ++ netdev->netdev_fd = -1; ++ netdev_init(&netdev->netdev, netdev_dev_); ++ ++ /* Verify that the netdev really exists by attempting to read its flags */ ++ error = netdev_get_flags(&netdev->netdev, &flags); ++ if (error == ENXIO) { ++ goto error; ++ } ++ ++ /* The first user that opens a tap port(from dpif_create_and_open()) will ++ * receive the file descriptor associated with the tap device. Instead, the ++ * following users will open the tap device as a normal 'system' device. */ ++ if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") && ++ !netdev_dev->tap_opened) { ++ netdev_dev->tap_opened = true; ++ netdev->netdev_fd = netdev_dev->tap_fd; ++ } ++ ++ *netdevp = &netdev->netdev; ++ return 0; ++ ++error: ++ netdev_uninit(&netdev->netdev, true); ++ return error; ++} ++ ++ ++ ++/* Close a 'netdev'. */ ++static void ++netdev_bsd_close(struct netdev *netdev_) ++{ ++ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); ++ ++ if (netdev->netdev_fd >= 0 && strcmp(netdev_get_type(netdev_), "tap")) { ++ pcap_close(netdev->pcap_handle); ++ } ++ ++ free(netdev); ++} ++ ++static int ++netdev_bsd_listen(struct netdev *netdev_) ++{ ++ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); ++ char errbuf[PCAP_ERRBUF_SIZE]; ++ int error; ++ int fd; ++ int one = 1; ++ ++ if (netdev->netdev_fd >= 0) { ++ return 0; ++ } ++ ++ /* open the pcap device. The device is opened in non-promiscuous mode ++ * because the interface flags are manually set by the caller. */ ++ errbuf[0] = '\0'; ++ netdev->pcap_handle = pcap_open_live(netdev_get_name(netdev_), PCAP_SNAPLEN, ++ 0, 1000, errbuf); ++ if (netdev->pcap_handle == NULL) { ++ VLOG_ERR("%s: pcap_open_live failed: %s", ++ netdev_get_name(netdev_), errbuf); ++ error = EIO; ++ goto error; ++ } else if (errbuf[0] != '\0') { ++ VLOG_WARN("%s: pcap_open_live: %s", ++ netdev_get_name(netdev_), errbuf); ++ } ++ ++ netdev_dev_bsd_changed(netdev_dev_bsd_cast(netdev_get_dev(netdev_))); ++ ++ /* initialize netdev->netdev_fd */ ++ fd = pcap_get_selectable_fd(netdev->pcap_handle); ++ if (fd == -1) { ++ error = errno; ++ goto error; ++ } ++ ++ /* Set non-blocking mode. Also the BIOCIMMEDIATE ioctl must be called ++ * on the file descriptor returned by pcap_get_selectable_fd to achieve ++ * a real non-blocking behaviour.*/ ++ error = pcap_setnonblock(netdev->pcap_handle, 1, errbuf); ++ if (error == -1) { ++ error = errno; ++ goto error; ++ } ++ ++ /* This call assure that reads return immediately upon packet reception. ++ * Otherwise, a read will block until either the kernel buffer becomes ++ * full or a timeout occurs. */ ++ if(ioctl(fd, BIOCIMMEDIATE, &one) < 0 ) { ++ VLOG_ERR("ioctl(BIOCIMMEDIATE) on %s device failed: %s", ++ netdev_get_name(netdev_), strerror(errno)); ++ error = errno; ++ goto error; ++ } ++ ++ /* Capture only incoming packets */ ++ error = pcap_setdirection(netdev->pcap_handle, PCAP_D_IN); ++ if (error == -1) { ++ error = errno; ++ goto error; ++ } ++ ++ netdev->netdev_fd = fd; ++ return 0; ++ ++error: ++ if (fd >= 0) { ++ close(netdev->netdev_fd); ++ } ++ return error; ++} ++ ++ ++/* The recv callback of the netdev class returns the number of bytes of the ++ * received packet. ++ * ++ * This can be done by the pcap_next() function. Unfortunately pcap_next() does ++ * not make difference between a missing packet on the capture interface and ++ * an error during the file capture. We can use the pcap_dispatch() function ++ * instead, which is able to distinguish between errors and null packet. ++ * ++ * To make pcap_dispatch() returns the number of bytes read from the interface ++ * we need to define the following callback and argument. ++ */ ++struct pcap_arg { ++ void *data; ++ int size; ++ int retval; ++}; ++ ++/* ++ * This callback will be executed on every captured packet. ++ * ++ * If the packet captured by pcap_dispatch() does not fit the pcap buffer, ++ * pcap returns a truncated packet and we follow this behavior. ++ * ++ * The argument args->retval is the packet size in bytes. ++ */ ++static void ++proc_pkt(u_char *args_, const struct pcap_pkthdr *hdr, const u_char *packet) ++{ ++ struct pcap_arg *args = (struct pcap_arg *)args_; ++ ++ if (args->size < hdr->len) { ++ VLOG_WARN_RL(&rl, "packet truncated"); ++ args->retval = args->size; ++ } else { ++ args->retval = hdr->len; ++ } ++ ++ /* copy the packet to our buffer */ ++ memcpy(args->data, packet, args->retval); ++} ++ ++/* ++ * This function attempts to receive a packet from the specified network ++ * device. It is assumed that the network device is a system device or a tap ++ * device opened as a system one. In this case the read operation is performed ++ * on the 'netdev' pcap descriptor. ++ */ ++static int ++netdev_bsd_recv_system(struct netdev_bsd *netdev, void *data, size_t size) ++{ ++ struct pcap_arg arg; ++ int ret; ++ ++ if (netdev->netdev_fd < 0) { ++ return -EAGAIN; ++ } ++ ++ /* prepare the pcap argument to store the packet */ ++ arg.size = size; ++ arg.data = data; ++ ++ for (;;) { ++ ret = pcap_dispatch(netdev->pcap_handle, 1, proc_pkt, (u_char *)&arg); ++ ++ if (ret > 0) { ++ return arg.retval; /* arg.retval < 0 is handled in the caller */ ++ } ++ if (ret == -1) { ++ if (errno == EINTR) { ++ continue; ++ } ++ } ++ ++ return -EAGAIN; ++ } ++} ++ ++/* ++ * This function attempts to receive a packet from the specified network ++ * device. It is assumed that the network device is a tap device and the ++ * 'netdev_fd' member of the 'netdev' structure is initialized with the tap ++ * file descriptor. ++ */ ++static int ++netdev_bsd_recv_tap(struct netdev_bsd *netdev, void *data, size_t size) ++{ ++ if (netdev->netdev_fd < 0) { ++ return -EAGAIN; ++ } ++ ++ for (;;) { ++ ssize_t retval = read(netdev->netdev_fd, data, size); ++ if (retval >= 0) { ++ return retval; ++ } else if (errno != EINTR) { ++ if (errno != EAGAIN) { ++ VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s", ++ strerror(errno), netdev->netdev.netdev_dev->name); ++ } ++ return -errno; ++ } ++ } ++} ++ ++ ++/* ++ * According with the nature of the device a different function must be called. ++ * If the device is the bridge local port the 'netdev_bsd_recv_tap' function ++ * must be called, otherwise the 'netdev_bsd_recv_system' function is called. ++ * ++ * type!="tap" ---> system device. ++ * type=="tap" && netdev_fd == tap_fd ---> internal tap device ++ * type=="tap" && netdev_fd != tap_fd ---> internal tap device ++ * opened as a system ++ * device. ++ */ ++static int ++netdev_bsd_recv(struct netdev *netdev_, void* data, size_t size) ++{ ++ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); ++ struct netdev_dev_bsd * netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ ++ if (!strcmp(netdev_get_type(netdev_), "tap") && ++ netdev->netdev_fd == netdev_dev->tap_fd) { ++ return netdev_bsd_recv_tap(netdev, data, size); ++ } else { ++ return netdev_bsd_recv_system(netdev, data, size); ++ } ++} ++ ++ ++/* ++ * Registers with the poll loop to wake up from the next call to poll_block() ++ * when a packet is ready to be received with netdev_recv() on 'netdev'. ++ */ ++static void ++netdev_bsd_recv_wait(struct netdev *netdev_) ++{ ++ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); ++ ++ if (netdev->netdev_fd >= 0) { ++ poll_fd_wait(netdev->netdev_fd, POLLIN); ++ } ++} ++ ++/* Discards all packets waiting to be received from 'netdev'. */ ++static int ++netdev_bsd_drain(struct netdev *netdev_) ++{ ++ struct ifreq ifr; ++ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); ++ ++ strcpy(ifr.ifr_name, netdev_get_name(netdev_)); ++ if (ioctl(netdev->netdev_fd, BIOCFLUSH, &ifr) == -1) { ++ VLOG_DBG_RL(&rl, "%s: ioctl(BIOCFLUSH) failed: %s", ++ netdev_get_name(netdev_), strerror(errno)); ++ return errno; ++ } ++ return 0; ++} ++ ++/* ++ * Send a packet on the specified network device. The device could be either a ++ * system or a tap device. ++ */ ++static int ++netdev_bsd_send(struct netdev *netdev_, const void *data, size_t size) ++{ ++ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); ++ struct netdev_dev_bsd * netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ ++ if (netdev->netdev_fd < 0) { ++ return EPIPE; ++ } ++ ++ for (;;) { ++ ssize_t retval; ++ if (!strcmp(netdev_get_type(netdev_), "tap") && ++ netdev_dev->tap_fd == netdev->netdev_fd) { ++ retval = write(netdev->netdev_fd, data, size); ++ } else { ++ retval = pcap_inject(netdev->pcap_handle, data, size); ++ } ++ if (retval < 0) { ++ if (errno == EINTR) { ++ continue; ++ } else if (errno != EAGAIN) { ++ VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s", ++ netdev_get_name(netdev_), strerror(errno)); ++ } ++ return errno; ++ } else if (retval != size) { ++ VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%zd bytes of " ++ "%zu) on %s", retval, size, ++ netdev_get_name(netdev_)); ++ return EMSGSIZE; ++ } else { ++ return 0; ++ } ++ } ++} ++ ++/* ++ * Registers with the poll loop to wake up from the next call to poll_block() ++ * when the packet transmission queue has sufficient room to transmit a packet ++ * with netdev_send(). ++ */ ++static void ++netdev_bsd_send_wait(struct netdev *netdev_) ++{ ++ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); ++ ++ if (netdev->netdev_fd < 0) { /* Nothing to do. */ ++ return; ++ } ++ ++ if (strcmp(netdev_get_type(netdev_), "tap")) { ++ poll_fd_wait(netdev->netdev_fd, POLLOUT); ++ } else { ++ /* TAP device always accepts packets. */ ++ poll_immediate_wake(); ++ } ++} ++ ++/* ++ * Attempts to set 'netdev''s MAC address to 'mac'. Returns 0 if successful, ++ * otherwise a positive errno value. ++ */ ++static int ++netdev_bsd_set_etheraddr(struct netdev *netdev_, ++ const uint8_t mac[ETH_ADDR_LEN]) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ int error; ++ ++ if (!(netdev_dev->cache_valid & VALID_ETHERADDR) ++ || !eth_addr_equals(netdev_dev->etheraddr, mac)) { ++ error = set_etheraddr(netdev_get_name(netdev_), AF_LINK, ETH_ADDR_LEN, ++ mac); ++ if (!error) { ++ netdev_dev->cache_valid |= VALID_ETHERADDR; ++ memcpy(netdev_dev->etheraddr, mac, ETH_ADDR_LEN); ++ netdev_dev_bsd_changed(netdev_dev); ++ } ++ } else { ++ error = 0; ++ } ++ return error; ++} ++ ++/* ++ * Returns a pointer to 'netdev''s MAC address. The caller must not modify or ++ * free the returned buffer. ++ */ ++static int ++netdev_bsd_get_etheraddr(const struct netdev *netdev_, ++ uint8_t mac[ETH_ADDR_LEN]) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ ++ if (!(netdev_dev->cache_valid & VALID_ETHERADDR)) { ++ int error = get_etheraddr(netdev_get_name(netdev_), ++ netdev_dev->etheraddr); ++ if (error) { ++ return error; ++ } ++ netdev_dev->cache_valid |= VALID_ETHERADDR; ++ } ++ memcpy(mac, netdev_dev->etheraddr, ETH_ADDR_LEN); ++ ++ return 0; ++} ++ ++/* ++ * Returns the maximum size of transmitted (and received) packets on 'netdev', ++ * in bytes, not including the hardware header; thus, this is typically 1500 ++ * bytes for Ethernet devices. ++ */ ++static int ++netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ ++ if (!(netdev_dev->cache_valid & VALID_MTU)) { ++ struct ifreq ifr; ++ int error; ++ ++ error = netdev_bsd_do_ioctl(netdev_, &ifr, SIOCGIFMTU, "SIOCGIFMTU"); ++ if (error) { ++ return error; ++ } ++ netdev_dev->mtu = ifr.ifr_mtu; ++ netdev_dev->cache_valid |= VALID_MTU; ++ } ++ ++ *mtup = netdev_dev->mtu; ++ return 0; ++} ++ ++static int ++netdev_bsd_get_ifindex(const struct netdev *netdev) ++{ ++ int ifindex, error; ++ ++ error = get_ifindex(netdev, &ifindex); ++ return error ? -error : ifindex; ++} ++ ++static int ++netdev_bsd_get_carrier(const struct netdev *netdev_, bool *carrier) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ ++ if (!(netdev_dev->cache_valid & VALID_CARRIER)) { ++ struct ifmediareq ifmr; ++ ++ memset(&ifmr, 0, sizeof(ifmr)); ++ strncpy(ifmr.ifm_name, netdev_get_name(netdev_), sizeof ifmr.ifm_name); ++ ++ if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { ++ VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", ++ netdev_get_name(netdev_), strerror(errno)); ++ return errno; ++ } ++ ++ netdev_dev->carrier = (ifmr.ifm_status & IFM_ACTIVE) == IFM_ACTIVE; ++ netdev_dev->cache_valid |= VALID_CARRIER; ++ ++ /* If the interface doesn't report whether the media is active, ++ * just assume it is active. */ ++ if ((ifmr.ifm_status & IFM_AVALID) == 0) { ++ netdev_dev->carrier = true; ++ } ++ } ++ *carrier = netdev_dev->carrier; ++ ++ return 0; ++} ++ ++/* Retrieves current device stats for 'netdev'. */ ++static int ++netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) ++{ ++ int if_count, i; ++ int mib[6]; ++ size_t len; ++ struct ifmibdata ifmd; ++ ++ ++ mib[0] = CTL_NET; ++ mib[1] = PF_LINK; ++ mib[2] = NETLINK_GENERIC; ++ mib[3] = IFMIB_SYSTEM; ++ mib[4] = IFMIB_IFCOUNT; ++ ++ len = sizeof(if_count); ++ ++ if (sysctl(mib, 5, &if_count, &len, (void *)0, 0) == -1) { ++ VLOG_DBG_RL(&rl, "%s: sysctl failed: %s", ++ netdev_get_name(netdev_), strerror(errno)); ++ return errno; ++ } ++ ++ mib[5] = IFDATA_GENERAL; ++ mib[3] = IFMIB_IFDATA; ++ len = sizeof(ifmd); ++ for (i = 1; i <= if_count; i++) { ++ mib[4] = i; //row ++ if (sysctl(mib, 6, &ifmd, &len, (void *)0, 0) == -1) { ++ VLOG_DBG_RL(&rl, "%s: sysctl failed: %s", ++ netdev_get_name(netdev_), strerror(errno)); ++ return errno; ++ } else if (!strcmp(ifmd.ifmd_name, netdev_get_name(netdev_))) { ++ stats->rx_packets = ifmd.ifmd_data.ifi_ipackets; ++ stats->tx_packets = ifmd.ifmd_data.ifi_opackets; ++ stats->rx_bytes = ifmd.ifmd_data.ifi_ibytes; ++ stats->tx_bytes = ifmd.ifmd_data.ifi_obytes; ++ stats->rx_errors = ifmd.ifmd_data.ifi_ierrors; ++ stats->tx_errors = ifmd.ifmd_data.ifi_oerrors; ++ stats->rx_dropped = ifmd.ifmd_data.ifi_iqdrops; ++ stats->tx_dropped = 0; ++ stats->multicast = ifmd.ifmd_data.ifi_imcasts; ++ stats->collisions = ifmd.ifmd_data.ifi_collisions; ++ ++ stats->rx_length_errors = 0; ++ stats->rx_over_errors = 0; ++ stats->rx_crc_errors = 0; ++ stats->rx_frame_errors = 0; ++ stats->rx_fifo_errors = 0; ++ stats->rx_missed_errors = 0; ++ ++ stats->tx_aborted_errors = 0; ++ stats->tx_carrier_errors = 0; ++ stats->tx_fifo_errors = 0; ++ stats->tx_heartbeat_errors = 0; ++ stats->tx_window_errors = 0; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static uint32_t ++netdev_bsd_parse_media(int media) ++{ ++ uint32_t supported = 0; ++ bool half_duplex = media & IFM_HDX ? true : false; ++ ++ switch (IFM_SUBTYPE(media)) { ++ case IFM_10_2: ++ case IFM_10_5: ++ case IFM_10_STP: ++ case IFM_10_T: ++ supported |= half_duplex ? NETDEV_F_10MB_HD : NETDEV_F_10MB_FD; ++ supported |= NETDEV_F_COPPER; ++ break; ++ ++ case IFM_10_FL: ++ supported |= half_duplex ? NETDEV_F_10MB_HD : NETDEV_F_10MB_FD; ++ supported |= NETDEV_F_FIBER; ++ break; ++ ++ case IFM_100_T2: ++ case IFM_100_T4: ++ case IFM_100_TX: ++ case IFM_100_VG: ++ supported |= half_duplex ? NETDEV_F_100MB_HD : NETDEV_F_100MB_FD; ++ supported |= NETDEV_F_COPPER; ++ break; ++ ++ case IFM_100_FX: ++ supported |= half_duplex ? NETDEV_F_100MB_HD : NETDEV_F_100MB_FD; ++ supported |= NETDEV_F_FIBER; ++ break; ++ ++ case IFM_1000_CX: ++ case IFM_1000_T: ++ supported |= half_duplex ? NETDEV_F_1GB_HD : NETDEV_F_1GB_FD; ++ supported |= NETDEV_F_COPPER; ++ break; ++ ++ case IFM_1000_LX: ++ case IFM_1000_SX: ++ supported |= half_duplex ? NETDEV_F_1GB_HD : NETDEV_F_1GB_FD; ++ supported |= NETDEV_F_FIBER; ++ break; ++ ++ case IFM_10G_CX4: ++ supported |= NETDEV_F_10GB_FD; ++ supported |= NETDEV_F_COPPER; ++ break; ++ ++ case IFM_10G_LR: ++ case IFM_10G_SR: ++ supported |= NETDEV_F_10GB_FD; ++ supported |= NETDEV_F_FIBER; ++ break; ++ ++ default: ++ return 0; ++ } ++ ++ if (IFM_SUBTYPE(media) == IFM_AUTO) { ++ supported |= NETDEV_F_AUTONEG; ++ } ++ /* ++ if (media & IFM_ETH_FMASK) { ++ supported |= NETDEV_F_PAUSE; ++ } ++ */ ++ ++ return supported; ++} ++ ++/* ++ * Stores the features supported by 'netdev' into each of '*current', ++ * '*advertised', '*supported', and '*peer' that are non-null. Each value is a ++ * bitmap of "enum ofp_port_features" bits, in host byte order. Returns 0 if ++ * successful, otherwise a positive errno value. On failure, all of the ++ * passed-in values are set to 0. ++ */ ++static int ++netdev_bsd_get_features(const struct netdev *netdev, ++ enum netdev_features *current, uint32_t *advertised, ++ enum netdev_features *supported, uint32_t *peer) ++{ ++ struct ifmediareq ifmr; ++ int *media_list; ++ int i; ++ int error; ++ ++ ++ /* XXX Look into SIOCGIFCAP instead of SIOCGIFMEDIA */ ++ ++ memset(&ifmr, 0, sizeof(ifmr)); ++ strncpy(ifmr.ifm_name, netdev_get_name(netdev), sizeof ifmr.ifm_name); ++ ++ /* We make two SIOCGIFMEDIA ioctl calls. The first to determine the ++ * number of supported modes, and a second with a buffer to retrieve ++ * them. */ ++ if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { ++ VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", ++ netdev_get_name(netdev), strerror(errno)); ++ return errno; ++ } ++ ++ media_list = xcalloc(ifmr.ifm_count, sizeof(int)); ++ ifmr.ifm_ulist = media_list; ++ ++ if (!IFM_TYPE(ifmr.ifm_current) & IFM_ETHER) { ++ VLOG_DBG_RL(&rl, "%s: doesn't appear to be ethernet", ++ netdev_get_name(netdev)); ++ error = EINVAL; ++ goto cleanup; ++ } ++ ++ if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { ++ VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", ++ netdev_get_name(netdev), strerror(errno)); ++ error = errno; ++ goto cleanup; ++ } ++ ++ /* Current settings. */ ++ *current = netdev_bsd_parse_media(ifmr.ifm_active); ++ ++ /* Advertised features. */ ++ *advertised = netdev_bsd_parse_media(ifmr.ifm_current); ++ ++ /* Supported features. */ ++ *supported = 0; ++ for (i = 0; i < ifmr.ifm_count; i++) { ++ *supported |= netdev_bsd_parse_media(ifmr.ifm_ulist[i]); ++ } ++ ++ /* Peer advertisements. */ ++ *peer = 0; /* XXX */ ++ ++ error = 0; ++cleanup: ++ free(media_list); ++ return error; ++} ++ ++/* ++ * If 'netdev' has an assigned IPv4 address, sets '*in4' to that address (if ++ * 'in4' is non-null) and returns true. Otherwise, returns false. ++ */ ++static int ++netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4, ++ struct in_addr *netmask) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ ++ if (!(netdev_dev->cache_valid & VALID_IN4)) { ++ const struct sockaddr_in *sin; ++ struct ifreq ifr; ++ int error; ++ ++ ifr.ifr_addr.sa_family = AF_INET; ++ error = netdev_bsd_do_ioctl(netdev_, &ifr, ++ SIOCGIFADDR, "SIOCGIFADDR"); ++ if (error) { ++ return error; ++ } ++ ++ sin = (struct sockaddr_in *) &ifr.ifr_addr; ++ netdev_dev->in4 = sin->sin_addr; ++ netdev_dev->cache_valid |= VALID_IN4; ++ error = netdev_bsd_do_ioctl(netdev_, &ifr, ++ SIOCGIFNETMASK, "SIOCGIFNETMASK"); ++ if (error) { ++ return error; ++ } ++ *netmask = ((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr; ++ } ++ *in4 = netdev_dev->in4; ++ ++ return in4->s_addr == INADDR_ANY ? EADDRNOTAVAIL : 0; ++} ++ ++/* ++ * Assigns 'addr' as 'netdev''s IPv4 address and 'mask' as its netmask. If ++ * 'addr' is INADDR_ANY, 'netdev''s IPv4 address is cleared. Returns a ++ * positive errno value. ++ */ ++static int ++netdev_bsd_set_in4(struct netdev *netdev_, struct in_addr addr, ++ struct in_addr mask) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ int error; ++ ++ error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", addr); ++ if (!error) { ++ netdev_dev->cache_valid |= VALID_IN4; ++ netdev_dev->in4 = addr; ++ if (addr.s_addr != INADDR_ANY) { ++ error = do_set_addr(netdev_, SIOCSIFNETMASK, ++ "SIOCSIFNETMASK", mask); ++ } ++ netdev_dev_bsd_changed(netdev_dev); ++ } ++ return error; ++} ++ ++static int ++netdev_bsd_get_in6(const struct netdev *netdev_, struct in6_addr *in6) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ if (!(netdev_dev->cache_valid & VALID_IN6)) { ++ struct ifaddrs *ifa, *head; ++ struct sockaddr_in6 *sin6; ++ const char *netdev_name = netdev_get_name(netdev_); ++ ++ if (getifaddrs(&head) != 0) { ++ VLOG_ERR("getifaddrs on %s device failed: %s", netdev_name, ++ strerror(errno)); ++ return errno; ++ } ++ ++ for (ifa = head; ifa; ifa = ifa->ifa_next) { ++ if (ifa->ifa_addr->sa_family == AF_INET6 && ++ !strcmp(ifa->ifa_name, netdev_name)) { ++ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; ++ if (sin6) { ++ memcpy(&netdev_dev->in6, &sin6->sin6_addr, sin6->sin6_len); ++ netdev_dev->cache_valid |= VALID_IN6; ++ *in6 = netdev_dev->in6; ++ freeifaddrs(head); ++ return 0; ++ } ++ } ++ } ++ return EADDRNOTAVAIL; ++ } ++ *in6 = netdev_dev->in6; ++ return 0; ++} ++ ++static void ++make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr) ++{ ++ struct sockaddr_in sin; ++ memset(&sin, 0, sizeof sin); ++ sin.sin_family = AF_INET; ++ sin.sin_addr = addr; ++ sin.sin_port = 0; ++ ++ memset(sa, 0, sizeof *sa); ++ memcpy(sa, &sin, sizeof sin); ++} ++ ++static int ++do_set_addr(struct netdev *netdev, ++ int ioctl_nr, const char *ioctl_name, struct in_addr addr) ++{ ++ struct ifreq ifr; ++ make_in4_sockaddr(&ifr.ifr_addr, addr); ++ return netdev_bsd_do_ioctl(netdev, &ifr, ioctl_nr, ioctl_name); ++} ++ ++static int ++nd_to_iff_flags(enum netdev_flags nd) ++{ ++ int iff = 0; ++ if (nd & NETDEV_UP) { ++ iff |= IFF_UP; ++ } ++ if (nd & NETDEV_PROMISC) { ++ iff |= IFF_PROMISC; ++ iff |= IFF_PPROMISC; ++ } ++ return iff; ++} ++ ++static int ++iff_to_nd_flags(int iff) ++{ ++ enum netdev_flags nd = 0; ++ if (iff & IFF_UP) { ++ nd |= NETDEV_UP; ++ } ++ if (iff & IFF_PROMISC) { ++ nd |= NETDEV_PROMISC; ++ } ++ return nd; ++} ++ ++static int ++netdev_bsd_update_flags(struct netdev *netdev, enum netdev_flags off, ++ enum netdev_flags on, enum netdev_flags *old_flagsp) ++{ ++ int old_flags, new_flags; ++ int error; ++ ++ error = get_flags(netdev, &old_flags); ++ if (!error) { ++ *old_flagsp = iff_to_nd_flags(old_flags); ++ new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on); ++ if (new_flags != old_flags) { ++ error = set_flags(netdev, new_flags); ++ netdev_dev_bsd_changed(netdev_dev_bsd_cast(netdev_get_dev(netdev))); ++ } ++ } ++ return error; ++} ++ ++static unsigned int ++netdev_bsd_change_seq(const struct netdev *netdev) ++{ ++ return netdev_dev_bsd_cast(netdev_get_dev(netdev))->change_seq; ++} ++ ++ ++const struct netdev_class netdev_bsd_class = { ++ "system", ++ ++ netdev_bsd_init, ++ netdev_bsd_run, ++ netdev_bsd_wait, ++ netdev_bsd_create_system, ++ netdev_bsd_destroy, ++ NULL, /* get_config */ ++ NULL, /* set_config */ ++ netdev_bsd_open_system, ++ netdev_bsd_close, ++ ++ netdev_bsd_listen, ++ ++ netdev_bsd_recv, ++ netdev_bsd_recv_wait, ++ netdev_bsd_drain, ++ ++ netdev_bsd_send, ++ netdev_bsd_send_wait, ++ ++ netdev_bsd_set_etheraddr, ++ netdev_bsd_get_etheraddr, ++ netdev_bsd_get_mtu, ++ NULL, /* set_mtu */ ++ netdev_bsd_get_ifindex, ++ netdev_bsd_get_carrier, ++ NULL, /* get_carrier_resets */ ++ NULL, /* set_miimon_interval */ ++ netdev_bsd_get_stats, ++ NULL, /* set_stats */ ++ ++ netdev_bsd_get_features, ++ NULL, /* set_advertisement */ ++ NULL, /* set_policing */ ++ NULL, /* get_qos_type */ ++ NULL, /* get_qos_capabilities */ ++ NULL, /* get_qos */ ++ NULL, /* set_qos */ ++ NULL, /* get_queue */ ++ NULL, /* set_queue */ ++ NULL, /* delete_queue */ ++ NULL, /* get_queue_stats */ ++ NULL, /* dump_queue */ ++ NULL, /* dump_queue_stats */ ++ ++ netdev_bsd_get_in4, ++ netdev_bsd_set_in4, ++ netdev_bsd_get_in6, ++ NULL, /* add_router */ ++ NULL, /* get_next_hop */ ++ NULL, /* get_drv_info */ ++ NULL, /* arp_lookup */ ++ ++ netdev_bsd_update_flags, ++ ++ netdev_bsd_change_seq ++}; ++ ++const struct netdev_class netdev_tap_class = { ++ "tap", ++ ++ netdev_bsd_init, ++ netdev_bsd_run, ++ netdev_bsd_wait, ++ netdev_bsd_create_tap, ++ netdev_bsd_destroy, ++ NULL, /* get_config */ ++ NULL, /* set_config */ ++ netdev_bsd_open_system, ++ netdev_bsd_close, ++ ++ netdev_bsd_listen, ++ ++ netdev_bsd_recv, ++ netdev_bsd_recv_wait, ++ netdev_bsd_drain, ++ ++ netdev_bsd_send, ++ netdev_bsd_send_wait, ++ ++ netdev_bsd_set_etheraddr, ++ netdev_bsd_get_etheraddr, ++ netdev_bsd_get_mtu, ++ NULL, /* set_mtu */ ++ netdev_bsd_get_ifindex, ++ netdev_bsd_get_carrier, ++ NULL, /* get_carrier_resets */ ++ NULL, /* set_miimon_interval */ ++ netdev_bsd_get_stats, ++ NULL, /* set_stats */ ++ ++ netdev_bsd_get_features, ++ NULL, /* set_advertisement */ ++ NULL, /* set_policing */ ++ NULL, /* get_qos_type */ ++ NULL, /* get_qos_capabilities */ ++ NULL, /* get_qos */ ++ NULL, /* set_qos */ ++ NULL, /* get_queue */ ++ NULL, /* set_queue */ ++ NULL, /* delete_queue */ ++ NULL, /* get_queue_stats */ ++ NULL, /* dump_queue */ ++ NULL, /* dump_queue_stats */ ++ ++ netdev_bsd_get_in4, ++ netdev_bsd_set_in4, ++ netdev_bsd_get_in6, ++ NULL, /* add_router */ ++ NULL, /* get_next_hop */ ++ NULL, /* get_drv_info */ ++ NULL, /* arp_lookup */ ++ ++ netdev_bsd_update_flags, ++ ++ netdev_bsd_change_seq ++}; ++ ++ ++static void ++destroy_tap(int fd, const char *name) ++{ ++ struct ifreq ifr; ++ ++ close(fd); ++ strcpy(ifr.ifr_name, name); ++ /* XXX What to do if this call fails? */ ++ ioctl(af_inet_sock, SIOCIFDESTROY, &ifr); ++} ++ ++static int ++get_flags(const struct netdev *netdev, int *flags) ++{ ++ struct ifreq ifr; ++ int error; ++ ++ error = netdev_bsd_do_ioctl(netdev, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); ++ ++ *flags = 0xFFFF0000 & (ifr.ifr_flagshigh << 16); ++ *flags |= 0x0000FFFF & ifr.ifr_flags; ++ ++ return error; ++} ++ ++static int ++set_flags(struct netdev *netdev, int flags) ++{ ++ struct ifreq ifr; ++ ++ ifr.ifr_flags = 0x0000FFFF & flags; ++ ifr.ifr_flagshigh = (0xFFFF0000 & flags) >> 16; ++ ++ return netdev_bsd_do_ioctl(netdev, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); ++} ++ ++static int ++get_ifindex(const struct netdev *netdev_, int *ifindexp) ++{ ++ struct netdev_dev_bsd *netdev_dev = ++ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); ++ *ifindexp = 0; ++ if (!(netdev_dev->cache_valid & VALID_IFINDEX)) { ++ int ifindex = if_nametoindex(netdev_get_name(netdev_)); ++ if (ifindex <= 0) { ++ return errno; ++ } ++ netdev_dev->cache_valid |= VALID_IFINDEX; ++ netdev_dev->ifindex = ifindex; ++ } ++ *ifindexp = netdev_dev->ifindex; ++ return 0; ++} ++ ++static int ++get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]) ++{ ++ struct ifaddrs *head; ++ struct ifaddrs *ifa; ++ struct sockaddr_dl *sdl; ++ ++ if (getifaddrs(&head) != 0) { ++ VLOG_ERR("getifaddrs on %s device failed: %s", netdev_name, ++ strerror(errno)); ++ return errno; ++ } ++ ++ for (ifa = head; ifa; ifa = ifa->ifa_next) { ++ if (ifa->ifa_addr->sa_family == AF_LINK) { ++ if (!strcmp(ifa->ifa_name, netdev_name)) { ++ sdl = (struct sockaddr_dl *)ifa->ifa_addr; ++ if (sdl) { ++ memcpy(ea, LLADDR(sdl), sdl->sdl_alen); ++ freeifaddrs(head); ++ return 0; ++ } ++ } ++ } ++ } ++ ++ VLOG_ERR("could not find ethernet address for %s device", netdev_name); ++ freeifaddrs(head); ++ return ENODEV; ++} ++ ++static int ++set_etheraddr(const char *netdev_name, int hwaddr_family, ++ int hwaddr_len, const uint8_t mac[ETH_ADDR_LEN]) ++{ ++ struct ifreq ifr; ++ ++ memset(&ifr, 0, sizeof ifr); ++ strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); ++ ifr.ifr_addr.sa_family = hwaddr_family; ++ ifr.ifr_addr.sa_len = hwaddr_len; ++ memcpy(ifr.ifr_addr.sa_data, mac, hwaddr_len); ++ if (ioctl(af_inet_sock, SIOCSIFLLADDR, &ifr) < 0) { ++ VLOG_ERR("ioctl(SIOCSIFLLADDR) on %s device failed: %s", ++ netdev_name, strerror(errno)); ++ return errno; ++ } ++ return 0; ++} ++ ++static int ++netdev_bsd_do_ioctl(const struct netdev *netdev, struct ifreq *ifr, ++ unsigned long cmd, const char *cmd_name) ++{ ++ strncpy(ifr->ifr_name, netdev_get_name(netdev), sizeof ifr->ifr_name); ++ if (ioctl(af_inet_sock, cmd, ifr) == -1) { ++ VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", ++ netdev_get_name(netdev), cmd_name, strerror(errno)); ++ return errno; ++ } ++ return 0; ++} +diff --git lib/netdev-provider.h lib/netdev-provider.h +index 080b76a..2a91f05 100644 +--- lib/netdev-provider.h ++++ lib/netdev-provider.h +@@ -596,6 +596,9 @@ const struct netdev_class *netdev_lookup_provider(const char *type); + extern const struct netdev_class netdev_linux_class; + extern const struct netdev_class netdev_internal_class; + extern const struct netdev_class netdev_tap_class; ++#ifdef __FreeBSD__ ++extern const struct netdev_class netdev_bsd_class; ++#endif + + #ifdef __cplusplus + } +diff --git lib/netdev.c lib/netdev.c +index e4e7ab1..be7cdd2 100644 +--- lib/netdev.c ++++ lib/netdev.c +@@ -80,6 +80,10 @@ netdev_initialize(void) + netdev_register_provider(&netdev_tap_class); + netdev_vport_register(); + #endif ++#ifdef __FreeBSD__ ++ netdev_register_provider(&netdev_tap_class); ++ netdev_register_provider(&netdev_bsd_class); ++#endif + } + } + +diff --git lib/route-table-bsd.c lib/route-table-bsd.c +new file mode 100644 +index 0000000..c145091 +--- /dev/null ++++ lib/route-table-bsd.c +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (c) 2012 Ed Maste. All rights reserved. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include <config.h> ++ ++#include "route-table.h" ++ ++#include <sys/socket.h> ++#include <sys/types.h> ++ ++#include <net/if.h> ++#include <net/route.h> ++#include <net/if_dl.h> ++#include <netinet/in.h> ++ ++#include <string.h> ++#include <unistd.h> ++ ++VLOG_DEFINE_THIS_MODULE(route_table); ++ ++static int pid; ++static unsigned int register_count = 0; ++ ++bool ++route_table_get_name(ovs_be32 ip, char name[IFNAMSIZ]) ++{ ++ struct { ++ struct rt_msghdr rtm; ++ char space[512]; ++ } rtmsg; ++ ++ struct rt_msghdr *rtm = &rtmsg.rtm; ++ struct sockaddr_dl *ifp = NULL; ++ struct sockaddr_in *sin; ++ struct sockaddr *sa; ++ static int seq; ++ int i, len, namelen, rtsock; ++ ++ rtsock = socket(PF_ROUTE, SOCK_RAW, 0); ++ if (rtsock < 0) ++ return false; ++ ++ memset(&rtmsg, 0, sizeof(rtmsg)); ++ ++ rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in); ++ rtm->rtm_version = RTM_VERSION; ++ rtm->rtm_type = RTM_GET; ++ rtm->rtm_addrs = RTA_DST | RTA_IFP; ++ rtm->rtm_seq = ++seq; ++ ++ sin = (struct sockaddr_in *)(rtm + 1); ++ sin->sin_len = len = sizeof(struct sockaddr_in); ++ sin->sin_family = AF_INET; ++ sin->sin_addr.s_addr = ip; ++ ++ if ((write(rtsock, (char *)&rtmsg, rtm->rtm_msglen)) < 0) { ++ close(rtsock); ++ return false; ++ } ++ ++ do { ++ len = read(rtsock, (char *)&rtmsg, sizeof(rtmsg)); ++ } while (len > 0 && (rtmsg.rtm.rtm_seq != seq || ++ rtmsg.rtm.rtm_pid != pid)); ++ ++ close(rtsock); ++ ++ if (len < 0) { ++ return false; ++ } ++ ++ sa = (struct sockaddr *)(rtm + 1); ++ for (i = 1; i; i <<= 1) { ++ if (rtm->rtm_addrs & i) { ++ if (i == RTA_IFP && sa->sa_family == AF_LINK && ++ ((struct sockaddr_dl *)sa)->sdl_nlen) { ++ ifp = (struct sockaddr_dl *)sa; ++ namelen = ifp->sdl_nlen; ++ if (namelen > IFNAMSIZ - 1) ++ namelen = IFNAMSIZ - 1; ++ memcpy(name, ifp->sdl_data, namelen); ++ name[namelen] = '\0'; ++ return true; ++ } ++ sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); ++ } ++ } ++ return false; ++} ++ ++void ++route_table_register() ++{ ++ if (!register_count) ++ { ++ pid = getpid(); ++ } ++ ++ register_count++; ++} ++ ++void ++route_table_unregister() ++{ ++ register_count--; ++} ++ ++void ++route_table_run(void) ++{ ++} ++ ++void ++route_table_wait(void) ++{ ++} +diff --git lib/route-table.h lib/route-table.h +index 1479249..804cb3f 100644 +--- lib/route-table.h ++++ lib/route-table.h +@@ -17,6 +17,7 @@ + #ifndef ROUTE_TABLE_H + #define ROUTE_TABLE_H 1 + ++#include <sys/socket.h> + #include <net/if.h> + #include <stdbool.h> + #include <stdint.h> +diff --git lib/rtbsd.c lib/rtbsd.c +new file mode 100644 +index 0000000..c5fe03a +--- /dev/null ++++ lib/rtbsd.c +@@ -0,0 +1,167 @@ ++/* ++ * Copyright (c) 2011 Gaetano Catalli. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include <config.h> ++ ++#include <unistd.h> ++#include <errno.h> ++#include <sys/socket.h> ++#include <net/if.h> ++#include <net/route.h> ++#include <poll.h> ++ ++#include "coverage.h" ++#include "socket-util.h" ++#include "poll-loop.h" ++#include "vlog.h" ++#include "rtbsd.h" ++ ++VLOG_DEFINE_THIS_MODULE(rtbsd); ++COVERAGE_DEFINE(rtbsd_changed); ++ ++/* PF_ROUTE socket. */ ++static int notify_sock = -1; ++ ++/* All registered notifiers. */ ++static struct list all_notifiers = LIST_INITIALIZER(&all_notifiers); ++ ++static void rtbsd_report_change(const struct if_msghdr *); ++static void rtbsd_report_notify_error(void); ++ ++/* Registers 'cb' to be called with auxiliary data 'aux' with network device ++ * change notifications. The notifier is stored in 'notifier', which the ++ * caller must not modify or free. ++ * ++ * Returns 0 if successful, otherwise a positive errno value. */ ++int ++rtbsd_notifier_register(struct rtbsd_notifier *notifier, ++ rtbsd_notify_func *cb, void *aux) ++{ ++ if (notify_sock < 0) { ++ int error; ++ notify_sock = socket(PF_ROUTE, SOCK_RAW, 0); ++ if (notify_sock < 0) { ++ VLOG_WARN("could not create PF_ROUTE socket: %s", ++ strerror(errno)); ++ return errno; ++ } ++ error = set_nonblocking(notify_sock); ++ if (error) { ++ VLOG_WARN("error set_nonblocking PF_ROUTE socket: %s", ++ strerror(error)); ++ return error; ++ } ++ } else { ++ /* Catch up on notification work so that the new notifier won't ++ * receive any stale notifications. XXX*/ ++ rtbsd_notifier_run(); ++ } ++ ++ list_push_back(&all_notifiers, ¬ifier->node); ++ notifier->cb = cb; ++ notifier->aux = aux; ++ return 0; ++} ++ ++/* Cancels notification on 'notifier', which must have previously been ++ * registered with rtbsd_notifier_register(). */ ++void ++rtbsd_notifier_unregister(struct rtbsd_notifier *notifier) ++{ ++ list_remove(¬ifier->node); ++ if (list_is_empty(&all_notifiers)) { ++ close(notify_sock); ++ notify_sock = -1; ++ } ++} ++ ++/* Calls all of the registered notifiers, passing along any as-yet-unreported ++ * netdev change events. */ ++void ++rtbsd_notifier_run(void) ++{ ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); ++ struct if_msghdr msg; ++ if (notify_sock < 0) { ++ return; ++ } ++ ++ for (;;) { ++ int retval; ++ ++ msg.ifm_type = RTM_IFINFO; ++ msg.ifm_version = RTM_VERSION; //XXX check if necessary ++ ++ /* read from PF_ROUTE socket */ ++ retval = read(notify_sock, (char *)&msg, sizeof(msg)); ++ if (retval >= 0) { ++ /* received packet from PF_ROUTE socket ++ * XXX check for bad packets */ ++ if (msg.ifm_type == RTM_IFINFO) { ++ rtbsd_report_change(&msg); ++ } ++ } else if (errno == EAGAIN) { ++ return; ++ } else { ++ if (errno == ENOBUFS) { ++ VLOG_WARN_RL(&rl, "PF_ROUTE receive buffer overflowed"); ++ } else { ++ VLOG_WARN_RL(&rl, "error reading PF_ROUTE socket: %s", ++ strerror(errno)); ++ } ++ rtbsd_report_notify_error(); ++ } ++ } ++} ++ ++/* Causes poll_block() to wake up when network device change notifications are ++ * ready. */ ++void ++rtbsd_notifier_wait(void) ++{ ++ if (notify_sock >= 0) { ++ poll_fd_wait(notify_sock, POLLIN); ++ } ++} ++ ++static void ++rtbsd_report_change(const struct if_msghdr *msg) ++{ ++ struct rtbsd_notifier *notifier; ++ struct rtbsd_change change; ++ ++ COVERAGE_INC(rtbsd_changed); ++ ++ change.msg_type = msg->ifm_type; //XXX ++ change.if_index = msg->ifm_index; ++ if_indextoname(msg->ifm_index, change.if_name); ++ change.master_ifindex = 0; //XXX ++ ++ LIST_FOR_EACH (notifier, node, &all_notifiers) { ++ notifier->cb(&change, notifier->aux); ++ } ++} ++ ++/* If an error occurs the notifiers' callbacks are called with NULL changes */ ++static void ++rtbsd_report_notify_error(void) ++{ ++ struct rtbsd_notifier *notifier; ++ ++ LIST_FOR_EACH (notifier, node, &all_notifiers) { ++ notifier->cb(NULL, notifier->aux); ++ } ++} +diff --git lib/rtbsd.h lib/rtbsd.h +new file mode 100644 +index 0000000..60bfae9 +--- /dev/null ++++ lib/rtbsd.h +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2011 Gaetano Catalli. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef RTBSD_H ++#define RTBSD_H 1 ++ ++#include "list.h" ++ ++/* ++ * A digested version of a message received from a PF_ROUTE socket which ++ * indicates that a network device has been created or destroyed or changed. ++ */ ++struct rtbsd_change { ++ /* Copied from struct if_msghdr. */ ++ int msg_type; /* e.g. XXX. */ ++ ++ /* Copied from struct if_msghdr. */ ++ int if_index; /* Index of network device. */ ++ ++ char if_name[IF_NAMESIZE]; /* Name of network device. */ ++ int master_ifindex; /* Ifindex of datapath master (0 if none). */ ++}; ++ ++/* ++ * Function called to report that a netdev has changed. 'change' describes the ++ * specific change. It may be null if the buffer of change information ++ * overflowed, in which case the function must assume that every device may ++ * have changed. 'aux' is as specified in the call to ++ * rtbsd_notifier_register(). ++ */ ++typedef void rtbsd_notify_func(const struct rtbsd_change *, void *aux); ++ ++struct rtbsd_notifier { ++ struct list node; ++ rtbsd_notify_func *cb; ++ void *aux; ++}; ++ ++int rtbsd_notifier_register(struct rtbsd_notifier *, ++ rtbsd_notify_func *, void *aux); ++void rtbsd_notifier_unregister(struct rtbsd_notifier *); ++void rtbsd_notifier_run(void); ++void rtbsd_notifier_wait(void); ++ ++#endif /* rtbsd.h */ +diff --git lib/socket-util.c lib/socket-util.c +index 82a33c2..b14eef5 100644 +--- lib/socket-util.c ++++ lib/socket-util.c +@@ -85,12 +85,14 @@ set_nonblocking(int fd) + static int + set_dscp(int fd, uint8_t dscp) + { ++ int val; ++ + if (dscp > 63) { + return EINVAL; + } + +- dscp = dscp << 2; +- if (setsockopt(fd, IPPROTO_IP, IP_TOS, &dscp, sizeof dscp)) { ++ val = dscp << 2; ++ if (setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val)) { + return errno; + } + +diff --git lib/vconn.c lib/vconn.c +index 5cd708d..dd198bc 100644 +--- lib/vconn.c ++++ lib/vconn.c +@@ -286,13 +286,7 @@ vconn_open_block(const char *name, int min_version, struct vconn **vconnp) + + error = vconn_open(name, min_version, &vconn, DSCP_DEFAULT); + if (!error) { +- while ((error = vconn_connect(vconn)) == EAGAIN) { +- vconn_run(vconn); +- vconn_run_wait(vconn); +- vconn_connect_wait(vconn); +- poll_block(); +- } +- assert(error != EINPROGRESS); ++ error = vconn_connect_block(vconn); + } + + if (error) { +@@ -621,6 +615,24 @@ do_send(struct vconn *vconn, struct ofpbuf *msg) + return retval; + } + ++/* Same as vconn_connect(), except that it waits until the connection on ++ * 'vconn' completes or fails. Thus, it will never return EAGAIN. */ ++int ++vconn_connect_block(struct vconn *vconn) ++{ ++ int error; ++ ++ while ((error = vconn_connect(vconn)) == EAGAIN) { ++ vconn_run(vconn); ++ vconn_run_wait(vconn); ++ vconn_connect_wait(vconn); ++ poll_block(); ++ } ++ assert(error != EINPROGRESS); ++ ++ return error; ++} ++ + /* Same as vconn_send, except that it waits until 'msg' can be transmitted. */ + int + vconn_send_block(struct vconn *vconn, struct ofpbuf *msg) +diff --git lib/vconn.h lib/vconn.h +index ee4a568..913364e 100644 +--- lib/vconn.h ++++ lib/vconn.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc. ++ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. +@@ -55,6 +55,7 @@ void vconn_run(struct vconn *); + void vconn_run_wait(struct vconn *); + + int vconn_open_block(const char *name, int min_version, struct vconn **); ++int vconn_connect_block(struct vconn *); + int vconn_send_block(struct vconn *, struct ofpbuf *); + int vconn_recv_block(struct vconn *, struct ofpbuf **); + +diff --git lib/vlandev.c lib/vlandev.c +index 77e8e93..ffb8e73 100644 +--- lib/vlandev.c ++++ lib/vlandev.c +@@ -23,13 +23,13 @@ + #include <sys/stat.h> + + #include "hash.h" +-#include "rtnetlink-link.h" + #include "shash.h" + #include "vlog.h" + + VLOG_DEFINE_THIS_MODULE(vlandev); + + #ifdef __linux__ ++#include "rtnetlink-link.h" + #include <linux/if_vlan.h> + #include <linux/sockios.h> + #include "netdev-linux.h" +diff --git ofproto/ofproto-dpif-sflow.c ofproto/ofproto-dpif-sflow.c +index 611f89a..23f5498 100644 +--- ofproto/ofproto-dpif-sflow.c ++++ ofproto/ofproto-dpif-sflow.c +@@ -18,6 +18,7 @@ + #include <config.h> + #include "ofproto-dpif-sflow.h" + #include <inttypes.h> ++#include <sys/socket.h> + #include <net/if.h> + #include <stdlib.h> + #include "collectors.h" +diff --git tests/ofproto-dpif.at tests/ofproto-dpif.at +index 9c3e0dc..b3d1947 100644 +--- tests/ofproto-dpif.at ++++ tests/ofproto-dpif.at +@@ -962,7 +962,7 @@ ovs-appctl -t test-netflow exit + + AT_CHECK([[sed -e 's/, uptime [0-9]*// + s/, now [0-9.]*// +-s/time \([0-9]*\)\.\.\.\1\b/time <moment>/ ++s/time \([0-9]*\)\.\.\.\1$/time <moment>/ + s/time [0-9]*\.\.\.[0-9]*/time <range>/ + ' netflow.log]], [0], + [header: v5, seq 0, engine 2,1 +diff --git tests/ovs-vsctl.at tests/ovs-vsctl.at +index 584ee79..9e6b4a9 100644 +--- tests/ovs-vsctl.at ++++ tests/ovs-vsctl.at +@@ -769,7 +769,7 @@ AT_CHECK( + + ]) + m4_define([VSCTL_CHECK_FIND], +- [AT_CHECK([ovs-vsctl --bare --timeout=5 --no-wait -vreconnect:ANY:emer --db=unix:socket -- --columns=name find bridge '$1' | sort | xargs echo], [0], [$2 ++ [AT_CHECK([echo `ovs-vsctl --bare --timeout=5 --no-wait -vreconnect:ANY:emer --db=unix:socket -- --columns=name find bridge '$1' | sort`], [0], [$2 + ])]) + + # Arithmetic relational operators without keys. +diff --git tests/ovsdb-server.at tests/ovsdb-server.at +index f5db1a8..b81878c 100644 +--- tests/ovsdb-server.at ++++ tests/ovsdb-server.at +@@ -322,8 +322,8 @@ dnl We can't fully re-check the contents of the database log, because the + dnl order of the records is not predictable, but there should only be 4 lines + dnl in it now. + AT_CAPTURE_FILE([db]) +-AT_CHECK([wc -l < db], [0], [4 +-], [], [test ! -e pid || kill `cat pid`]) ++AT_CHECK([test `wc -l < db` -eq 4], [0], [], [], ++ [test ! -e pid || kill `cat pid`]) + dnl And check that the dumped data is the same too: + AT_CHECK([ovsdb-client dump unix:socket ordinals], [0], [stdout], [ignore], + [test ! -e pid || kill `cat pid`]) +@@ -348,8 +348,8 @@ AT_CHECK( + [0], [[[{"count":3}] + ]], [ignore], [test ! -e pid || kill `cat pid`]) + dnl There should be 6 lines in the log now. +-AT_CHECK([wc -l < db], [0], [6 +-], [], [test ! -e pid || kill `cat pid`]) ++AT_CHECK([test `wc -l < db` -eq 6], [0], [], [], ++ [test ! -e pid || kill `cat pid`]) + dnl Then check that the dumped data is correct. + AT_CHECK([ovsdb-client dump unix:socket ordinals], [0], [stdout], [ignore], + [test ! -e pid || kill `cat pid`]) +diff --git tests/ovsdb-tool.at tests/ovsdb-tool.at +index 2d19b32..87949bb 100644 +--- tests/ovsdb-tool.at ++++ tests/ovsdb-tool.at +@@ -121,8 +121,7 @@ dnl We can't fully re-check the contents of the database log, because the + dnl order of the records is not predictable, but there should only be 4 lines + dnl in it now. + AT_CAPTURE_FILE([db]) +-AT_CHECK([wc -l < db], [0], [4 +-]) ++AT_CHECK([test `wc -l < db` -eq 4]) + dnl And check that the dumped data is the same too: + AT_CHECK([[ovsdb-server --unixctl="`pwd`"/unixctl --remote=punix:socket --run "ovsdb-client dump unix:socket ordinals" db]], + [0], [stdout], [ignore]) +@@ -185,8 +184,7 @@ dnl We can't fully re-check the contents of the database log, because the + dnl order of the records is not predictable, but there should only be 4 lines + dnl in it now. + AT_CAPTURE_FILE([db]) +-AT_CHECK([wc -l < db], [0], [4 +-]) ++AT_CHECK([test `wc -l < db` -eq 4]) + dnl And check that the dumped data is the same except for the removed column: + AT_CHECK([[ovsdb-server --unixctl="`pwd`"/unixctl --remote=punix:socket --run "ovsdb-client dump unix:socket ordinals" db]], + [0], [stdout], [ignore]) +@@ -248,8 +246,7 @@ dnl We can't fully re-check the contents of the database log, because the + dnl order of the records is not predictable, but there should only be 4 lines + dnl in it now. + AT_CAPTURE_FILE([db]) +-AT_CHECK([wc -l < db], [0], [4 +-]) ++AT_CHECK([test `wc -l < db` -eq 4]) + dnl And check that the dumped data is the same except for the added column: + AT_CHECK([[ovsdb-server --unixctl="`pwd`"/unixctl --remote=punix:socket --run "ovsdb-client dump unix:socket ordinals" db]], + [0], [stdout], [ignore]) +diff --git tests/test-vconn.c tests/test-vconn.c +index 31451a2..3f57b6d 100644 +--- tests/test-vconn.c ++++ tests/test-vconn.c +@@ -140,20 +140,26 @@ static void + test_refuse_connection(int argc OVS_UNUSED, char *argv[]) + { + const char *type = argv[1]; +- int expected_error; + struct fake_pvconn fpv; + struct vconn *vconn; +- +- expected_error = (!strcmp(type, "unix") ? EPIPE +- : !strcmp(type, "tcp") ? ECONNRESET +- : EPROTO); ++ int error; + + fpv_create(type, &fpv); + CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn, + DSCP_DEFAULT), 0); + fpv_close(&fpv); + vconn_run(vconn); +- CHECK_ERRNO(vconn_connect(vconn), expected_error); ++ ++ error = vconn_connect_block(vconn); ++ if (!strcmp(type, "tcp")) { ++ if (error != ECONNRESET && error != EPIPE) { ++ ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", ++ error, strerror(error)); ++ } ++ } else { ++ CHECK_ERRNO(error, !strcmp(type, "unix") ? EPIPE : EPROTO); ++ } ++ + vconn_close(vconn); + fpv_destroy(&fpv); + } +@@ -194,6 +200,7 @@ test_read_hello(int argc OVS_UNUSED, char *argv[]) + struct fake_pvconn fpv; + struct vconn *vconn; + struct stream *stream; ++ int error; + + fpv_create(type, &fpv); + CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn, +@@ -223,7 +230,11 @@ test_read_hello(int argc OVS_UNUSED, char *argv[]) + poll_block(); + } + stream_close(stream); +- CHECK_ERRNO(vconn_connect(vconn), ECONNRESET); ++ error = vconn_connect_block(vconn); ++ if (error != ECONNRESET && error != EPIPE) { ++ ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)", ++ error, strerror(error)); ++ } + vconn_close(vconn); + } + +@@ -313,7 +324,7 @@ test_send_hello(const char *type, const void *out, size_t out_size, + poll_block(); + } + stream_close(stream); +- CHECK_ERRNO(vconn_recv(vconn, &msg), EOF); ++ CHECK_ERRNO(vconn_recv_block(vconn, &msg), EOF); + vconn_close(vconn); + } + +diff --git utilities/ovs-pki.in utilities/ovs-pki.in +index 019ffcf..2dc4060 100755 +--- utilities/ovs-pki.in ++++ utilities/ovs-pki.in +@@ -24,6 +24,38 @@ batch=no + log='@LOGDIR@/ovs-pki.log' + keytype=rsa + bits=2048 ++ ++# OS-specific compatibility routines ++case $(uname -s) in ++FreeBSD) ++ file_mod_epoch() ++ { ++ stat -r "$1" | awk '{print $10}' ++ } ++ ++ file_mod_date() ++ { ++ stat -f '%Sm' "$1" ++ } ++ ++ sha1sum() ++ { ++ sha1 "$@" ++ } ++ ;; ++*) ++ file_mod_epoch() ++ { ++ date -r "$1" +%s ++ } ++ ++ file_mod_date() ++ { ++ date -r "$1" ++ } ++ ;; ++esac ++ + for option; do + # This option-parsing mechanism borrowed from a Autoconf-generated + # configure script under the following license: +@@ -365,7 +397,7 @@ make_tmpdir() { + fingerprint() { + file=$1 + name=${1-$2} +- date=$(date -r $file) ++ date=$(file_mod_date "$file") + if grep -e '-BEGIN CERTIFICATE-' "$file" > /dev/null; then + fingerprint=$(openssl x509 -noout -in "$file" -fingerprint | + sed 's/SHA1 Fingerprint=//' | tr -d ':') +@@ -609,7 +641,7 @@ elif test "$command" = expire; then + for type in switch controller; do + cd "$pkidir/${type}ca/incoming" || exit 1 + for file in $(glob "*"); do +- time=$(date -r "$file" +%s) ++ time=$(file_mod_epoch "$file") + if test "$time" -lt "$cutoff"; then + rm -f "$file" + fi +diff --git xenserver/opt_xensource_libexec_interface-reconfigure xenserver/opt_xensource_libexec_interface-reconfigure +index 6c6de9f..72bd5e4 100755 +--- xenserver/opt_xensource_libexec_interface-reconfigure ++++ xenserver/opt_xensource_libexec_interface-reconfigure +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/env python + # + # Copyright (c) 2008,2009 Citrix Systems, Inc. + # diff --git a/net/openvswitch/files/patch-lib-backtrace.c b/net/openvswitch/files/patch-lib-backtrace.c deleted file mode 100644 index 5fc96f82b3b7..000000000000 --- a/net/openvswitch/files/patch-lib-backtrace.c +++ /dev/null @@ -1,18 +0,0 @@ ---- lib/backtrace.c.orig 2011-11-01 12:07:55.000000000 +0100 -+++ lib/backtrace.c 2011-11-01 12:09:28.000000000 +0100 -@@ -83,6 +83,7 @@ - void - backtrace_capture(struct backtrace *backtrace) - { -+#ifndef __FreeBSD__ - void **frame; - size_t n; - -@@ -95,4 +96,7 @@ - backtrace->frames[n++] = (uintptr_t) frame[1]; - } - backtrace->n_frames = n; -+#else -+ backtrace->n_frames = 0; -+#endif - } diff --git a/net/openvswitch/files/patch-lib-dpif.c b/net/openvswitch/files/patch-lib-dpif.c deleted file mode 100644 index f2d2276e6550..000000000000 --- a/net/openvswitch/files/patch-lib-dpif.c +++ /dev/null @@ -1,14 +0,0 @@ ---- lib/dpif.c.orig 2011-11-02 07:36:34.000000000 +0100 -+++ lib/dpif.c 2011-11-02 07:36:56.000000000 +0100 -@@ -247,7 +247,11 @@ - dp_initialize(); - - if (!type || *type == '\0') { -+#ifdef HAVE_NETLINK - type = "system"; -+#else -+ type = "netdev"; -+#endif - } - - registered_class = shash_find_data(&dpif_classes, type); diff --git a/net/openvswitch/files/patch-lib-netdev-bsd.c b/net/openvswitch/files/patch-lib-netdev-bsd.c deleted file mode 100644 index 80255ad43aa5..000000000000 --- a/net/openvswitch/files/patch-lib-netdev-bsd.c +++ /dev/null @@ -1,1581 +0,0 @@ -diff -NBubrw lib/netdev-bsd.c.orig lib/netdev-bsd.c ---- lib/netdev-bsd.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ lib/netdev-bsd.c 2011-11-28 15:13:26.920783291 +0100 -@@ -0,0 +1,1577 @@ -+/* -+ * Copyright (c) 2011 Gaetano Catalli. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND. -+ * -+ */ -+ -+#include <stdlib.h> -+#include <config.h> -+#include <assert.h> -+#include <errno.h> -+#include <fcntl.h> -+#include <sys/types.h> -+#include <sys/time.h> -+#include <sys/ioctl.h> -+#include <sys/socket.h> -+#include <sys/sockio.h> -+#include <ifaddrs.h> -+#include <pcap/pcap.h> -+#include <net/if.h> -+#include <net/if_dl.h> -+#include <net/if_media.h> -+#include <net/if_tap.h> -+#include <netinet/in.h> -+#include <net/if_mib.h> -+#include <poll.h> -+#include <string.h> -+#include <unistd.h> -+#include <sys/sysctl.h> -+ -+#include "rtbsd.h" -+#include "coverage.h" -+#include "dynamic-string.h" -+#include "fatal-signal.h" -+#include "netdev-provider.h" -+#include "ofpbuf.h" -+#include "openflow/openflow.h" -+#include "packets.h" -+#include "poll-loop.h" -+#include "socket-util.h" -+#include "shash.h" -+#include "svec.h" -+#include "vlog.h" -+ -+VLOG_DEFINE_THIS_MODULE(netdev_bsd) -+ -+ -+/* -+ * This file implements objects to access interfaces. -+ * Externally, interfaces are represented by two structures: -+ * + struct netdev_dev, representing a network device, -+ * containing e.g. name and a refcount; -+ * We can have private variables by embedding the -+ * struct netdev_dev into our own structure -+ * (e.g. netdev_dev_bsd) -+ * -+ * + struct netdev, representing an instance of an open netdev_dev. -+ * The structure contains a pointer to the 'struct netdev' -+ * representing the device. Again, private information -+ * such as file descriptor etc. are stored in our -+ * own struct netdev_bsd which includes a struct netdev. -+ * -+ * Both 'struct netdev' and 'struct netdev_dev' are referenced -+ * in containers which hold pointers to the data structures. -+ * We can reach our own struct netdev_XXX_bsd by putting a -+ * struct netdev_XXX within our own struct, and using CONTAINER_OF -+ * to access the parent structure. -+ */ -+struct netdev_bsd { -+ struct netdev netdev; -+ -+ int netdev_fd; /* Selectable file descriptor for the network device. -+ This descriptor will be used for polling operations */ -+ -+ pcap_t *pcap_handle; /* Packet capture descriptor for a system network -+ device */ -+}; -+ -+struct netdev_dev_bsd { -+ struct netdev_dev netdev_dev; -+ unsigned int cache_valid; -+ -+ int ifindex; -+ uint8_t etheraddr[ETH_ADDR_LEN]; -+ struct in_addr in4; -+ struct in6_addr in6; -+ int mtu; -+ int carrier; -+ -+ bool tap_opened; -+ int tap_fd; /* TAP character device, if any */ -+}; -+ -+ -+enum { -+ VALID_IFINDEX = 1 << 0, -+ VALID_ETHERADDR = 1 << 1, -+ VALID_IN4 = 1 << 2, -+ VALID_IN6 = 1 << 3, -+ VALID_MTU = 1 << 4, -+ VALID_CARRIER = 1 << 5 -+}; -+ -+/* An AF_INET socket (used for ioctl operations). */ -+static int af_inet_sock = -1; -+ -+#define PCAP_SNAPLEN 1024 -+ -+/* -+ * A BSD network device notifier. -+ * -+ * Represents a handler to be invoked on a device when some event occurs. -+ * Contains handler, parameters (in netdev_notifier) and link fields for the -+ * list (in struct list). -+ */ -+struct netdev_bsd_notifier { -+ struct netdev_notifier notifier; /* Handler and arguments */ -+ struct list node; /* Link fields for the list */ -+}; -+ -+/* -+ * All 'struct netdev_bsd_notifier' objects are linked as children of a generic -+ * 'struct shash_node', there is one shash_node per interface, and the -+ * interface name is the search key. In turn, all the 'struct shash_node' are -+ * stored in a container, all_bsd_notifiers. -+ * -+ * A 'netdev_bsd_notifier' is created and added to the all_bsd_notifiers -+ * using 'netdev_bsd_poll_add()' XXX again, same code as netdev-linux -+ */ -+static struct shash all_bsd_notifiers = -+ SHASH_INITIALIZER(&all_bsd_notifiers); -+ -+/* -+ * Openvswitch can register multiple handlers on route-related events. -+ * The descriptor for each handler is a struct rtbsd_notifier -+ * that contains the function and a parameter. -+ * -+ * In this module we call rtbsd_notifier_register() to invoke -+ * the function netdev_bsd_poll_cb() on the all_bsd_notifiers above. -+ */ -+static struct rtbsd_notifier netdev_bsd_poll_notifier; -+ -+/* -+ * Notifier used to invalidate device informations in case of status change. -+ * -+ * It will be registered with a 'rtbsd_notifier_register()' when the first -+ * device will be created with the call of either 'netdev_bsd_tap_create()' or -+ * 'netdev_bsd_system_create()'. -+ * -+ * The callback associated with this notifier ('netdev_bsd_cache_cb()') will -+ * invalidate cached information about the device. -+ */ -+static struct rtbsd_notifier netdev_bsd_cache_notifier; -+static int cache_notifier_refcount; -+ -+static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); -+ -+static int netdev_bsd_do_ioctl(const struct netdev *, struct ifreq *, -+ unsigned long cmd, const char *cmd_name); -+static void destroy_tap(int fd, const char *name); -+static int get_flags(const struct netdev *, int *flagsp); -+static int set_flags(struct netdev *, int flags); -+static int do_set_addr(struct netdev *netdev, -+ int ioctl_nr, const char *ioctl_name, -+ struct in_addr addr); -+static int get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]); -+static int set_etheraddr(const char *netdev_name, int hwaddr_family, -+ int hwaddr_len, const uint8_t[ETH_ADDR_LEN]); -+static int get_ifindex(const struct netdev *, int *ifindexp); -+ -+static int netdev_bsd_init(void); -+ -+static bool -+is_netdev_bsd_class(const struct netdev_class *netdev_class) -+{ -+ return netdev_class->init == netdev_bsd_init; -+} -+ -+static struct netdev_bsd * -+netdev_bsd_cast(const struct netdev *netdev) -+{ -+ assert(is_netdev_bsd_class(netdev_dev_get_class(netdev_get_dev(netdev)))); -+ return CONTAINER_OF(netdev, struct netdev_bsd, netdev); -+} -+ -+static struct netdev_dev_bsd * -+netdev_dev_bsd_cast(const struct netdev_dev *netdev_dev) -+{ -+ assert(is_netdev_bsd_class(netdev_dev_get_class(netdev_dev))); -+ return CONTAINER_OF(netdev_dev, struct netdev_dev_bsd, netdev_dev); -+} -+ -+/* Initialize the AF_INET socket used for ioctl operations */ -+static int -+netdev_bsd_init(void) -+{ -+ static int status = -1; -+ -+ if (status >= 0) { /* already initialized */ -+ return status; -+ } -+ -+ af_inet_sock = socket(AF_INET, SOCK_DGRAM, 0); -+ status = af_inet_sock >= 0 ? 0 : errno; -+ -+ if (status) { -+ VLOG_ERR("failed to create inet socket: %s", strerror(status)); -+ } -+ -+ return status; -+} -+ -+/* -+ * Perform periodic work needed by netdev. In BSD netdevs it checks for any -+ * interface status changes, and eventually calls all the user callbacks. -+ */ -+static void -+netdev_bsd_run(void) -+{ -+ rtbsd_notifier_run(); -+} -+ -+/* -+ * Arranges for poll_block() to wake up if the "run" member function needs to -+ * be called. -+ */ -+static void -+netdev_bsd_wait(void) -+{ -+ rtbsd_notifier_wait(); -+} -+ -+/* Invalidate cache in case of interface status change. */ -+static void -+netdev_bsd_cache_cb(const struct rtbsd_change *change, -+ void *aux OVS_UNUSED) -+{ -+ struct netdev_dev_bsd *dev; -+ -+ if (change) { -+ struct netdev_dev *base_dev = netdev_dev_from_name(change->if_name); -+ -+ if (base_dev) { -+ const struct netdev_class *netdev_class = -+ netdev_dev_get_class(base_dev); -+ -+ if (is_netdev_bsd_class(netdev_class)) { -+ dev = netdev_dev_bsd_cast(base_dev); -+ dev->cache_valid = 0; -+ } -+ } -+ } else { -+ /* -+ * XXX the API is lacking, we should be able to iterate on the list of -+ * netdevs without having to store the info in a temp shash. -+ */ -+ struct shash device_shash; -+ struct shash_node *node; -+ -+ shash_init(&device_shash); -+ netdev_dev_get_devices(&netdev_bsd_class, &device_shash); -+ SHASH_FOR_EACH (node, &device_shash) { -+ dev = node->data; -+ dev->cache_valid = 0; -+ } -+ shash_destroy(&device_shash); -+ } -+} -+ -+/* Allocate a netdev_dev_bsd structure */ -+static int -+netdev_bsd_create_system(const char *name, const char *type OVS_UNUSED, -+ const struct shash *args OVS_UNUSED, -+ struct netdev_dev **netdev_devp) -+{ -+ struct netdev_dev_bsd *netdev_dev; -+ int ret = 0; -+ -+ if (!cache_notifier_refcount) { -+ ret = rtbsd_notifier_register(&netdev_bsd_cache_notifier, -+ netdev_bsd_cache_cb, NULL); -+ if (ret) { -+ return ret; -+ } -+ } -+ cache_notifier_refcount++; -+ -+ netdev_dev = xzalloc(sizeof *netdev_dev); -+ netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_bsd_class); -+ *netdev_devp = &netdev_dev->netdev_dev; -+ -+ return ret; -+} -+ -+/* -+ * Allocate a netdev_dev_bsd structure with 'tap' class. -+ */ -+static int -+netdev_bsd_create_tap(const char *name, const char *type OVS_UNUSED, -+ const struct shash *args OVS_UNUSED, -+ struct netdev_dev **netdev_devp) -+{ -+ struct netdev_dev_bsd *netdev_dev; -+ int error = 0; -+ struct ifreq ifr; -+ -+ if (!cache_notifier_refcount) { -+ error = rtbsd_notifier_register(&netdev_bsd_cache_notifier, -+ netdev_bsd_cache_cb, NULL); -+ if (error) { -+ return error; -+ } -+ } -+ cache_notifier_refcount++; -+ -+ /* allocate the device structure and set the internal flag */ -+ netdev_dev = xzalloc(sizeof *netdev_dev); -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ -+ /* Create a tap device by opening /dev/tap. The TAPGIFNAME ioctl is used -+ * to retrieve the name of the tap device. */ -+ netdev_dev->tap_fd = open("/dev/tap", O_RDWR); -+ if (netdev_dev->tap_fd < 0) { -+ error = errno; -+ VLOG_WARN("opening \"/dev/tap\" failed: %s", strerror(error)); -+ goto error; -+ } -+ -+ /* Retrieve tap name (e.g. tap0) */ -+ if (ioctl(netdev_dev->tap_fd, TAPGIFNAME, &ifr) == -1) { -+ /* XXX Need to destroy the device? */ -+ error = errno; -+ goto error; -+ } -+ -+ /* Change the name of the tap device */ -+ ifr.ifr_data = (void *)name; -+ if (ioctl(af_inet_sock, SIOCSIFNAME, &ifr) == -1) { -+ error = errno; -+ destroy_tap(netdev_dev->tap_fd, ifr.ifr_name); -+ goto error; -+ } -+ -+ /* set non-blocking. */ -+ error = set_nonblocking(netdev_dev->tap_fd); -+ if (error) { -+ destroy_tap(netdev_dev->tap_fd, name); -+ goto error; -+ } -+ -+ /* Turn device UP */ -+ ifr.ifr_flags = (uint16_t)IFF_UP; -+ ifr.ifr_flagshigh = 0; -+ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); -+ if (ioctl(af_inet_sock, SIOCSIFFLAGS, &ifr) == -1) { -+ error = errno; -+ destroy_tap(netdev_dev->tap_fd, name); -+ goto error; -+ } -+ -+ /* initialize the device structure and -+ * link the structure to its netdev */ -+ netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_tap_class); -+ *netdev_devp = &netdev_dev->netdev_dev; -+ -+ return 0; -+ -+error: -+ free(netdev_dev); -+ return error; -+} -+ -+static void -+netdev_bsd_destroy(struct netdev_dev *netdev_dev_) -+{ -+ struct netdev_dev_bsd *netdev_dev = netdev_dev_bsd_cast(netdev_dev_); -+ -+ cache_notifier_refcount--; -+ if (cache_notifier_refcount == 0) { -+ rtbsd_notifier_unregister(&netdev_bsd_cache_notifier); -+ } -+ -+ if (netdev_dev->tap_fd >= 0 && -+ !strcmp(netdev_dev_get_type(netdev_dev_), "tap")) { -+ destroy_tap(netdev_dev->tap_fd, netdev_dev_get_name(netdev_dev_)); -+ } -+ free(netdev_dev); -+} -+ -+ -+static int -+netdev_bsd_open_system(struct netdev_dev *netdev_dev_, int ethertype, -+ struct netdev **netdevp) -+{ -+ struct netdev_dev_bsd *netdev_dev = netdev_dev_bsd_cast(netdev_dev_); -+ struct netdev_bsd *netdev; -+ int error; -+ enum netdev_flags flags; -+ -+ /* Allocate network device. */ -+ netdev = xcalloc(1, sizeof *netdev); -+ netdev->netdev_fd = -1; -+ netdev_init(&netdev->netdev, netdev_dev_); -+ -+ /* Verify that the netdev really exists by attempting to read its flags */ -+ error = netdev_get_flags(&netdev->netdev, &flags); -+ if (error == ENXIO) { -+ goto error; -+ } -+ -+ /* The first user that opens a tap port(from dpif_create_and_open()) will -+ * receive the file descriptor associated with the tap device. Instead, the -+ * following users will open the tap device as a normal 'system' device. */ -+ if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") && -+ !netdev_dev->tap_opened) { -+ netdev_dev->tap_opened = true; -+ netdev->netdev_fd = netdev_dev->tap_fd; -+ } else if (ethertype != NETDEV_ETH_TYPE_NONE) { -+ char errbuf[PCAP_ERRBUF_SIZE]; -+ int one = 1; -+ -+ /* open the pcap device. The device is opened in non-promiscuous mode -+ * because the interface flags are manually set by the caller. */ -+ netdev->pcap_handle = pcap_open_live(netdev_dev_->name, PCAP_SNAPLEN, -+ 0, 1000, errbuf); -+ if (netdev->pcap_handle == NULL) { -+ error = errno; -+ goto error; -+ } -+ -+ /* initialize netdev->netdev_fd */ -+ netdev->netdev_fd = pcap_get_selectable_fd(netdev->pcap_handle); -+ if (netdev->netdev_fd == -1) { -+ error = errno; -+ goto error; -+ } -+ -+ /* Set non-blocking mode. Also the BIOCIMMEDIATE ioctl must be called -+ * on the file descriptor returned by pcap_get_selectable_fd to achieve -+ * a real non-blocking behaviour.*/ -+ error = pcap_setnonblock(netdev->pcap_handle, 1, errbuf); -+ if (error == -1) { -+ error = errno; -+ goto error; -+ } -+ -+ /* This call assure that reads return immediately upon packet reception. -+ * Otherwise, a read will block until either the kernel buffer becomes -+ * full or a timeout occurs. */ -+ if(ioctl(netdev->netdev_fd, BIOCIMMEDIATE, &one) < 0 ) { -+ VLOG_ERR("ioctl(BIOCIMMEDIATE) on %s device failed: %s", -+ netdev_dev_get_name(netdev_dev_), strerror(errno)); -+ error = errno; -+ goto error; -+ } -+ -+ /* Capture only incoming packets */ -+ error = pcap_setdirection(netdev->pcap_handle, PCAP_D_IN); -+ if (error == -1) { -+ error = errno; -+ goto error; -+ } -+ } -+ *netdevp = &netdev->netdev; -+ -+ return 0; -+ -+error: -+ netdev_uninit(&netdev->netdev, true); -+ return error; -+} -+ -+ -+/* Close a 'netdev'. */ -+static void -+netdev_bsd_close(struct netdev *netdev_) -+{ -+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); -+ -+ if (netdev->netdev_fd >= 0 && strcmp(netdev_get_type(netdev_), "tap")) { -+ pcap_close(netdev->pcap_handle); -+ } -+ -+ free(netdev); -+} -+ -+ -+/* Initializes 'svec' with a list of the names of all known network devices. */ -+static int -+netdev_bsd_enumerate(struct svec *svec) -+{ -+ struct if_nameindex *names; -+ -+ names = if_nameindex(); -+ if (names) { -+ size_t i; -+ -+ for (i = 0; names[i].if_name != NULL; i++) { -+ svec_add(svec, names[i].if_name); -+ } -+ if_freenameindex(names); -+ return 0; -+ } else { -+ VLOG_WARN("could not obtain list of network device names: %s", -+ strerror(errno)); -+ return errno; -+ } -+} -+ -+/* The recv callback of the netdev class returns the number of bytes of the -+ * received packet. -+ * -+ * This can be done by the pcap_next() function. Unfortunately pcap_next() does -+ * not make difference between a missing packet on the capture interface and -+ * an error during the file capture. We can use the pcap_dispatch() function -+ * instead, which is able to distinguish between errors and null packet. -+ * -+ * To make pcap_dispatch() returns the number of bytes read from the interface -+ * we need to define the following callback and argument. -+ */ -+struct pcap_arg { -+ void *data; -+ int size; -+ int retval; -+}; -+ -+/* -+ * This callback will be executed on every captured packet. -+ * -+ * If the packet captured by pcap_dispatch() does not fit the pcap buffer, -+ * pcap returns a truncated packet and we follow this behavior. -+ * -+ * The argument args->retval is the packet size in bytes. -+ */ -+static void -+proc_pkt(u_char *args_, const struct pcap_pkthdr *hdr, const u_char *packet) -+{ -+ struct pcap_arg *args = (struct pcap_arg *)args_; -+ -+ if (args->size < hdr->len) { -+ printf("%s Warning: Packet truncated'n", __func__); -+ args->retval = args->size; -+ } else { -+ args->retval = hdr->len; -+ } -+ -+ /* copy the packet to our buffer */ -+ memcpy(args->data, packet, args->retval); -+} -+ -+/* -+ * This function attempts to receive a packet from the specified network -+ * device. It is assumed that the network device is a system device or a tap -+ * device opened as a system one. In this case the read operation is performed -+ * on the 'netdev' pcap descriptor. -+ */ -+static int -+netdev_bsd_recv_system(struct netdev_bsd *netdev, void *data, size_t size) -+{ -+ struct pcap_arg arg; -+ int ret; -+ -+ if (netdev->netdev_fd < 0) { -+ /* Device was opened with NETDEV_ETH_TYPE_NONE. */ -+ return -EAGAIN; -+ } -+ -+ /* prepare the pcap argument to store the packet */ -+ arg.size = size; -+ arg.data = data; -+ -+ for (;;) { -+ ret = pcap_dispatch(netdev->pcap_handle, 1, proc_pkt, (u_char *)&arg); -+ -+ if (ret > 0) { -+ return arg.retval; /* arg.retval < 0 is handled in the caller */ -+ } -+ if (ret == -1) { -+ if (errno == EINTR) { -+ continue; -+ } -+ } -+ -+ return -EAGAIN; -+ } -+} -+ -+/* -+ * This function attempts to receive a packet from the specified network -+ * device. It is assumed that the network device is a tap device and the -+ * 'netdev_fd' member of the 'netdev' structure is initialized with the tap -+ * file descriptor. -+ */ -+static int -+netdev_bsd_recv_tap(struct netdev_bsd *netdev, void *data, size_t size) -+{ -+ if (netdev->netdev_fd < 0) { -+ /* Device was opened with NETDEV_ETH_TYPE_NONE. */ -+ return -EAGAIN; -+ } -+ -+ for (;;) { -+ ssize_t retval = read(netdev->netdev_fd, data, size); -+ if (retval >= 0) { -+ return retval; -+ } else if (errno != EINTR) { -+ if (errno != EAGAIN) { -+ VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s", -+ strerror(errno), netdev->netdev.netdev_dev->name); -+ } -+ return -errno; -+ } -+ } -+} -+ -+ -+/* -+ * According with the nature of the device a different function must be called. -+ * If the device is the bridge local port the 'netdev_bsd_recv_tap' function -+ * must be called, otherwise the 'netdev_bsd_recv_system' function is called. -+ * -+ * type!="tap" ---> system device. -+ * type=="tap" && netdev_fd == tap_fd ---> internal tap device -+ * type=="tap" && netdev_fd != tap_fd ---> internal tap device -+ * opened as a system -+ * device. -+ */ -+static int -+netdev_bsd_recv(struct netdev *netdev_, void* data, size_t size) -+{ -+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); -+ struct netdev_dev_bsd * netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ -+ if (!strcmp(netdev_get_type(netdev_), "tap") && -+ netdev->netdev_fd == netdev_dev->tap_fd) { -+ return netdev_bsd_recv_tap(netdev, data, size); -+ } else { -+ return netdev_bsd_recv_system(netdev, data, size); -+ } -+} -+ -+ -+/* -+ * Registers with the poll loop to wake up from the next call to poll_block() -+ * when a packet is ready to be received with netdev_recv() on 'netdev'. -+ */ -+static void -+netdev_bsd_recv_wait(struct netdev *netdev_) -+{ -+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); -+ -+ if (netdev->netdev_fd >= 0) { -+ poll_fd_wait(netdev->netdev_fd, POLLIN); -+ } -+} -+ -+/* Discards all packets waiting to be received from 'netdev'. */ -+static int -+netdev_bsd_drain(struct netdev *netdev_) -+{ -+ struct ifreq ifr; -+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); -+ -+ strcpy(ifr.ifr_name, netdev_get_name(netdev_)); -+ if (ioctl(netdev->netdev_fd, BIOCFLUSH, &ifr) == -1) { -+ VLOG_DBG_RL(&rl, "%s: ioctl(BIOCFLUSH) failed: %s", -+ netdev_get_name(netdev_), strerror(errno)); -+ return errno; -+ } -+ return 0; -+} -+ -+/* -+ * Send a packet on the specified network device. The device could be either a -+ * system or a tap device. -+ */ -+static int -+netdev_bsd_send(struct netdev *netdev_, const void *data, size_t size) -+{ -+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); -+ struct netdev_dev_bsd * netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ -+ /* XXX should support sending even if 'ethertype' was NETDEV_ETH_TYPE_NONE. -+ */ -+ if (netdev->netdev_fd < 0) { -+ return EPIPE; -+ } -+ -+ for (;;) { -+ ssize_t retval; -+ if (!strcmp(netdev_get_type(netdev_), "tap") && -+ netdev_dev->tap_fd == netdev->netdev_fd) { -+ retval = write(netdev->netdev_fd, data, size); -+ } else { -+ retval = pcap_inject(netdev->pcap_handle, data, size); -+ } -+ if (retval < 0) { -+ if (errno == EINTR) { -+ continue; -+ } else if (errno != EAGAIN) { -+ VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s", -+ netdev_get_name(netdev_), strerror(errno)); -+ } -+ return errno; -+ } else if (retval != size) { -+ VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%zd bytes of " -+ "%zu) on %s", retval, size, -+ netdev_get_name(netdev_)); -+ return EMSGSIZE; -+ } else { -+ return 0; -+ } -+ } -+} -+ -+/* -+ * Registers with the poll loop to wake up from the next call to poll_block() -+ * when the packet transmission queue has sufficient room to transmit a packet -+ * with netdev_send(). -+ */ -+static void -+netdev_bsd_send_wait(struct netdev *netdev_) -+{ -+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_); -+ -+ if (netdev->netdev_fd < 0) { /* Nothing to do. */ -+ return; -+ } -+ -+ if (strcmp(netdev_get_type(netdev_), "tap")) { -+ poll_fd_wait(netdev->netdev_fd, POLLOUT); -+ } else { -+ /* TAP device always accepts packets. */ -+ poll_immediate_wake(); -+ } -+} -+ -+/* -+ * Attempts to set 'netdev''s MAC address to 'mac'. Returns 0 if successful, -+ * otherwise a positive errno value. -+ */ -+static int -+netdev_bsd_set_etheraddr(struct netdev *netdev_, -+ const uint8_t mac[ETH_ADDR_LEN]) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ int error; -+ -+ if (!(netdev_dev->cache_valid & VALID_ETHERADDR) -+ || !eth_addr_equals(netdev_dev->etheraddr, mac)) { -+ error = set_etheraddr(netdev_get_name(netdev_), AF_LINK, ETH_ADDR_LEN, -+ mac); -+ if (!error) { -+ netdev_dev->cache_valid |= VALID_ETHERADDR; -+ memcpy(netdev_dev->etheraddr, mac, ETH_ADDR_LEN); -+ } -+ } else { -+ error = 0; -+ } -+ return error; -+} -+ -+/* -+ * Returns a pointer to 'netdev''s MAC address. The caller must not modify or -+ * free the returned buffer. -+ */ -+static int -+netdev_bsd_get_etheraddr(const struct netdev *netdev_, -+ uint8_t mac[ETH_ADDR_LEN]) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ -+ if (!(netdev_dev->cache_valid & VALID_ETHERADDR)) { -+ int error = get_etheraddr(netdev_get_name(netdev_), -+ netdev_dev->etheraddr); -+ if (error) { -+ return error; -+ } -+ netdev_dev->cache_valid |= VALID_ETHERADDR; -+ } -+ memcpy(mac, netdev_dev->etheraddr, ETH_ADDR_LEN); -+ -+ return 0; -+} -+ -+/* -+ * Returns the maximum size of transmitted (and received) packets on 'netdev', -+ * in bytes, not including the hardware header; thus, this is typically 1500 -+ * bytes for Ethernet devices. -+ */ -+static int -+netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ -+ if (!(netdev_dev->cache_valid & VALID_MTU)) { -+ struct ifreq ifr; -+ int error; -+ -+ error = netdev_bsd_do_ioctl(netdev_, &ifr, SIOCGIFMTU, "SIOCGIFMTU"); -+ if (error) { -+ return error; -+ } -+ netdev_dev->mtu = ifr.ifr_mtu; -+ netdev_dev->cache_valid |= VALID_MTU; -+ } -+ -+ *mtup = netdev_dev->mtu; -+ return 0; -+} -+ -+static int -+netdev_bsd_get_ifindex(const struct netdev *netdev) -+{ -+ int ifindex, error; -+ -+ error = get_ifindex(netdev, &ifindex); -+ return error ? -error : ifindex; -+} -+ -+static int -+netdev_bsd_get_carrier(const struct netdev *netdev_, bool *carrier) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ -+ if (!(netdev_dev->cache_valid & VALID_CARRIER)) { -+ struct ifmediareq ifmr; -+ -+ memset(&ifmr, 0, sizeof(ifmr)); -+ strncpy(ifmr.ifm_name, netdev_get_name(netdev_), sizeof ifmr.ifm_name); -+ -+ if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { -+ VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", -+ netdev_get_name(netdev_), strerror(errno)); -+ return errno; -+ } -+ -+ netdev_dev->carrier = (ifmr.ifm_status & IFM_ACTIVE) == IFM_ACTIVE; -+ netdev_dev->cache_valid |= VALID_CARRIER; -+ -+ /* If the interface doesn't report whether the media is active, -+ * just assume it is active. */ -+ if ((ifmr.ifm_status & IFM_AVALID) == 0) { -+ netdev_dev->carrier = true; -+ } -+ } -+ *carrier = netdev_dev->carrier; -+ -+ return 0; -+} -+ -+/* Retrieves current device stats for 'netdev'. */ -+static int -+netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) -+{ -+ int if_count, i; -+ int mib[6]; -+ size_t len; -+ struct ifmibdata ifmd; -+ -+ COVERAGE_INC(netdev_get_stats); -+ -+ mib[0] = CTL_NET; -+ mib[1] = PF_LINK; -+ mib[2] = NETLINK_GENERIC; -+ mib[3] = IFMIB_SYSTEM; -+ mib[4] = IFMIB_IFCOUNT; -+ -+ len = sizeof(if_count); -+ -+ if (sysctl(mib, 5, &if_count, &len, (void *)0, 0) == -1) { -+ VLOG_DBG_RL(&rl, "%s: sysctl failed: %s", -+ netdev_get_name(netdev_), strerror(errno)); -+ return errno; -+ } -+ -+ mib[5] = IFDATA_GENERAL; -+ mib[3] = IFMIB_IFDATA; -+ len = sizeof(ifmd); -+ for (i = 1; i <= if_count; i++) { -+ mib[4] = i; //row -+ if (sysctl(mib, 6, &ifmd, &len, (void *)0, 0) == -1) { -+ VLOG_DBG_RL(&rl, "%s: sysctl failed: %s", -+ netdev_get_name(netdev_), strerror(errno)); -+ return errno; -+ } else if (!strcmp(ifmd.ifmd_name, netdev_get_name(netdev_))) { -+ stats->rx_packets = ifmd.ifmd_data.ifi_ipackets; -+ stats->tx_packets = ifmd.ifmd_data.ifi_opackets; -+ stats->rx_bytes = ifmd.ifmd_data.ifi_ibytes; -+ stats->tx_bytes = ifmd.ifmd_data.ifi_obytes; -+ stats->rx_errors = ifmd.ifmd_data.ifi_ierrors; -+ stats->tx_errors = ifmd.ifmd_data.ifi_oerrors; -+ stats->rx_dropped = ifmd.ifmd_data.ifi_iqdrops; -+ stats->tx_dropped = 0; -+ stats->multicast = ifmd.ifmd_data.ifi_imcasts; -+ stats->collisions = ifmd.ifmd_data.ifi_collisions; -+ -+ stats->rx_length_errors = 0; -+ stats->rx_over_errors = 0; -+ stats->rx_crc_errors = 0; -+ stats->rx_frame_errors = 0; -+ stats->rx_fifo_errors = 0; -+ stats->rx_missed_errors = 0; -+ -+ stats->tx_aborted_errors = 0; -+ stats->tx_carrier_errors = 0; -+ stats->tx_fifo_errors = 0; -+ stats->tx_heartbeat_errors = 0; -+ stats->tx_window_errors = 0; -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+static uint32_t -+netdev_bsd_parse_media(int media) -+{ -+ uint32_t supported = 0; -+ bool half_duplex = media & IFM_HDX ? true : false; -+ -+ switch (IFM_SUBTYPE(media)) { -+ case IFM_10_2: -+ case IFM_10_5: -+ case IFM_10_STP: -+ case IFM_10_T: -+ supported |= half_duplex ? OFPPF_10MB_HD : OFPPF_10MB_FD; -+ supported |= OFPPF_COPPER; -+ break; -+ -+ case IFM_10_FL: -+ supported |= half_duplex ? OFPPF_10MB_HD : OFPPF_10MB_FD; -+ supported |= OFPPF_FIBER; -+ break; -+ -+ case IFM_100_T2: -+ case IFM_100_T4: -+ case IFM_100_TX: -+ case IFM_100_VG: -+ supported |= half_duplex ? OFPPF_100MB_HD : OFPPF_100MB_FD; -+ supported |= OFPPF_COPPER; -+ break; -+ -+ case IFM_100_FX: -+ supported |= half_duplex ? OFPPF_100MB_HD : OFPPF_100MB_FD; -+ supported |= OFPPF_FIBER; -+ break; -+ -+ case IFM_1000_CX: -+ case IFM_1000_T: -+ supported |= half_duplex ? OFPPF_1GB_HD : OFPPF_1GB_FD; -+ supported |= OFPPF_COPPER; -+ break; -+ -+ case IFM_1000_LX: -+ case IFM_1000_SX: -+ supported |= half_duplex ? OFPPF_1GB_HD : OFPPF_1GB_FD; -+ supported |= OFPPF_FIBER; -+ break; -+ -+ case IFM_10G_CX4: -+ supported |= OFPPF_10GB_FD; -+ supported |= OFPPF_COPPER; -+ break; -+ -+ case IFM_10G_LR: -+ case IFM_10G_SR: -+ supported |= OFPPF_10GB_FD; -+ supported |= OFPPF_FIBER; -+ break; -+ -+ default: -+ return 0; -+ } -+ -+ if (IFM_SUBTYPE(media) == IFM_AUTO) { -+ supported |= OFPPF_AUTONEG; -+ } -+ /* -+ if (media & IFM_ETH_FMASK) { -+ supported |= OFPPF_PAUSE; -+ } -+ */ -+ -+ return supported; -+} -+ -+/* -+ * Stores the features supported by 'netdev' into each of '*current', -+ * '*advertised', '*supported', and '*peer' that are non-null. Each value is a -+ * bitmap of "enum ofp_port_features" bits, in host byte order. Returns 0 if -+ * successful, otherwise a positive errno value. On failure, all of the -+ * passed-in values are set to 0. -+ */ -+static int -+netdev_bsd_get_features(struct netdev *netdev, -+ uint32_t *current, uint32_t *advertised, -+ uint32_t *supported, uint32_t *peer) -+{ -+ struct ifmediareq ifmr; -+ int *media_list; -+ int i; -+ int error; -+ -+ -+ /* XXX Look into SIOCGIFCAP instead of SIOCGIFMEDIA */ -+ -+ memset(&ifmr, 0, sizeof(ifmr)); -+ strncpy(ifmr.ifm_name, netdev_get_name(netdev), sizeof ifmr.ifm_name); -+ -+ /* We make two SIOCGIFMEDIA ioctl calls. The first to determine the -+ * number of supported modes, and a second with a buffer to retrieve -+ * them. */ -+ if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { -+ VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", -+ netdev_get_name(netdev), strerror(errno)); -+ return errno; -+ } -+ -+ media_list = xcalloc(ifmr.ifm_count, sizeof(int)); -+ ifmr.ifm_ulist = media_list; -+ -+ if (!IFM_TYPE(ifmr.ifm_current) & IFM_ETHER) { -+ VLOG_DBG_RL(&rl, "%s: doesn't appear to be ethernet", -+ netdev_get_name(netdev)); -+ error = EINVAL; -+ goto cleanup; -+ } -+ -+ if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { -+ VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", -+ netdev_get_name(netdev), strerror(errno)); -+ error = errno; -+ goto cleanup; -+ } -+ -+ /* Current settings. */ -+ *current = netdev_bsd_parse_media(ifmr.ifm_active); -+ -+ /* Advertised features. */ -+ *advertised = netdev_bsd_parse_media(ifmr.ifm_current); -+ -+ /* Supported features. */ -+ *supported = 0; -+ for (i = 0; i < ifmr.ifm_count; i++) { -+ *supported |= netdev_bsd_parse_media(ifmr.ifm_ulist[i]); -+ } -+ -+ /* Peer advertisements. */ -+ *peer = 0; /* XXX */ -+ -+ error = 0; -+cleanup: -+ free(media_list); -+ return error; -+} -+ -+/* -+ * If 'netdev' has an assigned IPv4 address, sets '*in4' to that address (if -+ * 'in4' is non-null) and returns true. Otherwise, returns false. -+ */ -+static int -+netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4, -+ struct in_addr *netmask) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ -+ if (!(netdev_dev->cache_valid & VALID_IN4)) { -+ const struct sockaddr_in *sin; -+ struct ifreq ifr; -+ int error; -+ -+ ifr.ifr_addr.sa_family = AF_INET; -+ error = netdev_bsd_do_ioctl(netdev_, &ifr, -+ SIOCGIFADDR, "SIOCGIFADDR"); -+ if (error) { -+ return error; -+ } -+ -+ sin = (struct sockaddr_in *) &ifr.ifr_addr; -+ netdev_dev->in4 = sin->sin_addr; -+ netdev_dev->cache_valid |= VALID_IN4; -+ error = netdev_bsd_do_ioctl(netdev_, &ifr, -+ SIOCGIFNETMASK, "SIOCGIFNETMASK"); -+ if (error) { -+ return error; -+ } -+ *netmask = ((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr; -+ } -+ *in4 = netdev_dev->in4; -+ -+ return in4->s_addr == INADDR_ANY ? EADDRNOTAVAIL : 0; -+} -+ -+/* -+ * Assigns 'addr' as 'netdev''s IPv4 address and 'mask' as its netmask. If -+ * 'addr' is INADDR_ANY, 'netdev''s IPv4 address is cleared. Returns a -+ * positive errno value. -+ */ -+static int -+netdev_bsd_set_in4(struct netdev *netdev_, struct in_addr addr, -+ struct in_addr mask) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ int error; -+ -+ error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", addr); -+ if (!error) { -+ netdev_dev->cache_valid |= VALID_IN4; -+ netdev_dev->in4 = addr; -+ if (addr.s_addr != INADDR_ANY) { -+ error = do_set_addr(netdev_, SIOCSIFNETMASK, -+ "SIOCSIFNETMASK", mask); -+ } -+ } -+ return error; -+} -+ -+static int -+netdev_bsd_get_in6(const struct netdev *netdev_, struct in6_addr *in6) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ if (!(netdev_dev->cache_valid & VALID_IN6)) { -+ struct ifaddrs *ifa, *head; -+ struct sockaddr_in6 *sin6; -+ const char *netdev_name = netdev_get_name(netdev_); -+ -+ if (getifaddrs(&head) != 0) { -+ VLOG_ERR("getifaddrs on %s device failed: %s", netdev_name, -+ strerror(errno)); -+ return errno; -+ } -+ -+ for (ifa = head; ifa; ifa = ifa->ifa_next) { -+ if (ifa->ifa_addr->sa_family == AF_INET6 && -+ !strcmp(ifa->ifa_name, netdev_name)) { -+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; -+ if (sin6) { -+ memcpy(&netdev_dev->in6, &sin6->sin6_addr, sin6->sin6_len); -+ netdev_dev->cache_valid |= VALID_IN6; -+ *in6 = netdev_dev->in6; -+ freeifaddrs(head); -+ return 0; -+ } -+ } -+ } -+ return EADDRNOTAVAIL; -+ } -+ *in6 = netdev_dev->in6; -+ return 0; -+} -+ -+static void -+make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr) -+{ -+ struct sockaddr_in sin; -+ memset(&sin, 0, sizeof sin); -+ sin.sin_family = AF_INET; -+ sin.sin_addr = addr; -+ sin.sin_port = 0; -+ -+ memset(sa, 0, sizeof *sa); -+ memcpy(sa, &sin, sizeof sin); -+} -+ -+static int -+do_set_addr(struct netdev *netdev, -+ int ioctl_nr, const char *ioctl_name, struct in_addr addr) -+{ -+ struct ifreq ifr; -+ make_in4_sockaddr(&ifr.ifr_addr, addr); -+ return netdev_bsd_do_ioctl(netdev, &ifr, ioctl_nr, ioctl_name); -+} -+ -+static int -+nd_to_iff_flags(enum netdev_flags nd) -+{ -+ int iff = 0; -+ if (nd & NETDEV_UP) { -+ iff |= IFF_UP; -+ } -+ if (nd & NETDEV_PROMISC) { -+ iff |= IFF_PROMISC; -+ iff |= IFF_PPROMISC; -+ } -+ return iff; -+} -+ -+static int -+iff_to_nd_flags(int iff) -+{ -+ enum netdev_flags nd = 0; -+ if (iff & IFF_UP) { -+ nd |= NETDEV_UP; -+ } -+ if (iff & IFF_PROMISC) { -+ nd |= NETDEV_PROMISC; -+ } -+ return nd; -+} -+ -+static int -+netdev_bsd_update_flags(struct netdev *netdev, enum netdev_flags off, -+ enum netdev_flags on, enum netdev_flags *old_flagsp) -+{ -+ int old_flags, new_flags; -+ int error; -+ -+ error = get_flags(netdev, &old_flags); -+ if (!error) { -+ *old_flagsp = iff_to_nd_flags(old_flags); -+ new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on); -+ if (new_flags != old_flags) { -+ error = set_flags(netdev, new_flags); -+ } -+ } -+ return error; -+} -+ -+/* Call callbacks for all the list of notifiers */ -+static void -+poll_notify(struct list *dev_notifiers) -+{ -+ struct netdev_bsd_notifier *notifier; -+ LIST_FOR_EACH (notifier, struct netdev_bsd_notifier, node, dev_notifiers) { -+ struct netdev_notifier *n = ¬ifier->notifier; -+ n->cb(n); -+ } -+} -+ -+/* -+ * The callback registered for 'netdev_bsd_poll_notifier'. -+ * -+ * If 'change' is set it retrieves the element in the 'all_bsd_notifiers' -+ * relative to the network device which has been subject to the change, and -+ * then call the callbacks for all the notifiers registered for that network -+ * device. -+ */ -+static void -+netdev_bsd_poll_cb(const struct rtbsd_change *change, void *aux) -+{ -+ struct shash *arg = aux; -+ -+ if (change) { -+ struct list *dev_notifiers = shash_find_data(arg, change->if_name); -+ if (dev_notifiers) { -+ poll_notify(dev_notifiers); -+ } -+ } else { -+ struct shash_node *node; -+ SHASH_FOR_EACH (node, arg) { -+ poll_notify(node->data); -+ } -+ } -+} -+ -+/* -+ * Arranges for 'cb' to be called whenever one of the attributes of -+ * 'netdev' changes and sets '*notifierp' to a newly created -+ * netdev_notifier that represents this arrangement. -+ * -+ * If the 'all_bsd_notifiers' is empty, it registers the -+ * 'netdev_bsd_poll_notifier'. Than it creates a new notifier and inserts it -+ * into the list belonging to the node in the 'all_bsd_notifiers' relative to -+ * the network device. In case it is the first notifier registered for this -+ * network device, it first create the node into the 'all_bsd_notifiers' and -+ * then appends the notifier to its list. -+ */ -+static int -+netdev_bsd_poll_add(struct netdev *netdev, -+ void (*cb)(struct netdev_notifier *), void *aux, -+ struct netdev_notifier **notifierp) -+{ -+ const char *netdev_name = netdev_get_name(netdev); -+ struct netdev_bsd_notifier *notifier; -+ struct list *list; -+ -+ if (shash_is_empty(&all_bsd_notifiers)) { -+ /* This is the first time that this function is called so the main -+ * notifier needs to be registered */ -+ int error = rtbsd_notifier_register(&netdev_bsd_poll_notifier, -+ netdev_bsd_poll_cb, &all_bsd_notifiers); -+ if (error) { -+ return error; -+ } -+ } -+ list = shash_find_data(&all_bsd_notifiers, netdev_name); -+ if (!list) { -+ list = xmalloc(sizeof *list); -+ list_init(list); -+ shash_add(&all_bsd_notifiers, netdev_name, list); -+ } -+ -+ notifier = xmalloc(sizeof *notifier); -+ netdev_notifier_init(¬ifier->notifier, netdev, cb, aux); -+ list_push_back(list, ¬ifier->node); -+ *notifierp = ¬ifier->notifier; -+ return 0; -+} -+ -+static void -+netdev_bsd_poll_remove(struct netdev_notifier *notifier_) -+{ -+ struct netdev_bsd_notifier *notifier = -+ CONTAINER_OF(notifier_, struct netdev_bsd_notifier, notifier); -+ struct list *list; -+ -+ /* Remove 'notifier' from its list. */ -+ list = list_remove(¬ifier->node); -+ if (list_is_empty(list)) { -+ /* The list is now empty. Remove it from the hash and free it. */ -+ const char *netdev_name = netdev_get_name(notifier->notifier.netdev); -+ shash_delete(&all_bsd_notifiers, -+ shash_find(&all_bsd_notifiers, netdev_name)); -+ free(list); -+ } -+ free(notifier); -+ -+ /* If that was the last notifier, unregister. */ -+ if (shash_is_empty(&all_bsd_notifiers)) { -+ rtbsd_notifier_unregister(&netdev_bsd_poll_notifier); -+ } -+} -+ -+const struct netdev_class netdev_bsd_class = { -+ "system", -+ -+ netdev_bsd_init, -+ netdev_bsd_run, -+ netdev_bsd_wait, -+ netdev_bsd_create_system, -+ netdev_bsd_destroy, -+ NULL, /* reconfigure */ -+ netdev_bsd_open_system, -+ netdev_bsd_close, -+ -+ netdev_bsd_enumerate, -+ -+ netdev_bsd_recv, -+ netdev_bsd_recv_wait, -+ netdev_bsd_drain, -+ -+ netdev_bsd_send, -+ netdev_bsd_send_wait, -+ -+ netdev_bsd_set_etheraddr, -+ netdev_bsd_get_etheraddr, -+ netdev_bsd_get_mtu, -+ netdev_bsd_get_ifindex, -+ netdev_bsd_get_carrier, -+ netdev_bsd_get_stats, -+ NULL, /* set_stats */ -+ -+ netdev_bsd_get_features, -+ NULL, /* set_advertisement */ -+ NULL, /* get_vlan_vid */ //XXX SIOCGETVLAN -+ NULL, /* set_policing */ -+ NULL, /* get_qos_type */ -+ NULL, /* get_qos_capabilities */ -+ NULL, /* get_qos */ -+ NULL, /* set_qos */ -+ NULL, /* get_queue */ -+ NULL, /* set_queue */ -+ NULL, /* delete_queue */ -+ NULL, /* get_queue_stats */ -+ NULL, /* dump_queue */ -+ NULL, /* dump_queue_stats */ -+ -+ netdev_bsd_get_in4, -+ netdev_bsd_set_in4, -+ netdev_bsd_get_in6, -+ NULL, /* add_router */ -+ NULL, /* get_next_hop */ -+ NULL, /* arp_lookup */ -+ -+ netdev_bsd_update_flags, -+ -+ netdev_bsd_poll_add, -+ netdev_bsd_poll_remove, -+}; -+ -+const struct netdev_class netdev_tap_class = { -+ "tap", -+ -+ netdev_bsd_init, -+ netdev_bsd_run, -+ netdev_bsd_wait, -+ netdev_bsd_create_tap, -+ netdev_bsd_destroy, -+ NULL, /* reconfigure */ -+ netdev_bsd_open_system, -+ netdev_bsd_close, -+ -+ netdev_bsd_enumerate, -+ -+ netdev_bsd_recv, -+ netdev_bsd_recv_wait, -+ netdev_bsd_drain, -+ -+ netdev_bsd_send, -+ netdev_bsd_send_wait, -+ -+ netdev_bsd_set_etheraddr, -+ netdev_bsd_get_etheraddr, -+ netdev_bsd_get_mtu, -+ netdev_bsd_get_ifindex, -+ netdev_bsd_get_carrier, -+ netdev_bsd_get_stats, -+ NULL, /* set_stats */ -+ -+ netdev_bsd_get_features, -+ NULL, /* set_advertisement */ -+ NULL, /* get_vlan_vid */ -+ NULL, /* set_policing */ -+ NULL, /* get_qos_type */ -+ NULL, /* get_qos_capabilities */ -+ NULL, /* get_qos */ -+ NULL, /* set_qos */ -+ NULL, /* get_queue */ -+ NULL, /* set_queue */ -+ NULL, /* delete_queue */ -+ NULL, /* get_queue_stats */ -+ NULL, /* dump_queue */ -+ NULL, /* dump_queue_stats */ -+ -+ netdev_bsd_get_in4, -+ netdev_bsd_set_in4, -+ netdev_bsd_get_in6, -+ NULL, /* add_router */ -+ NULL, /* get_next_hop */ -+ NULL, /* arp_lookup */ -+ -+ netdev_bsd_update_flags, -+ -+ netdev_bsd_poll_add, -+ netdev_bsd_poll_remove, -+}; -+ -+ -+static void -+destroy_tap(int fd, const char *name) -+{ -+ struct ifreq ifr; -+ -+ close(fd); -+ strcpy(ifr.ifr_name, name); -+ /* XXX What to do if this call fails? */ -+ ioctl(af_inet_sock, SIOCIFDESTROY, &ifr); -+} -+ -+static int -+get_flags(const struct netdev *netdev, int *flags) -+{ -+ struct ifreq ifr; -+ int error; -+ -+ error = netdev_bsd_do_ioctl(netdev, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); -+ -+ *flags = 0xFFFF0000 & (ifr.ifr_flagshigh << 16); -+ *flags |= 0x0000FFFF & ifr.ifr_flags; -+ -+ return error; -+} -+ -+static int -+set_flags(struct netdev *netdev, int flags) -+{ -+ struct ifreq ifr; -+ -+ ifr.ifr_flags = 0x0000FFFF & flags; -+ ifr.ifr_flagshigh = (0xFFFF0000 & flags) >> 16; -+ -+ return netdev_bsd_do_ioctl(netdev, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); -+} -+ -+static int -+get_ifindex(const struct netdev *netdev_, int *ifindexp) -+{ -+ struct netdev_dev_bsd *netdev_dev = -+ netdev_dev_bsd_cast(netdev_get_dev(netdev_)); -+ *ifindexp = 0; -+ if (!(netdev_dev->cache_valid & VALID_IFINDEX)) { -+ int ifindex = if_nametoindex(netdev_get_name(netdev_)); -+ if (ifindex <= 0) { -+ return errno; -+ } -+ netdev_dev->cache_valid |= VALID_IFINDEX; -+ netdev_dev->ifindex = ifindex; -+ } -+ *ifindexp = netdev_dev->ifindex; -+ return 0; -+} -+ -+static int -+get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]) -+{ -+ struct ifaddrs *head; -+ struct ifaddrs *ifa; -+ struct sockaddr_dl *sdl; -+ -+ if (getifaddrs(&head) != 0) { -+ VLOG_ERR("getifaddrs on %s device failed: %s", netdev_name, -+ strerror(errno)); -+ return errno; -+ } -+ -+ for (ifa = head; ifa; ifa = ifa->ifa_next) { -+ if (ifa->ifa_addr->sa_family == AF_LINK) { -+ if (!strcmp(ifa->ifa_name, netdev_name)) { -+ sdl = (struct sockaddr_dl *)ifa->ifa_addr; -+ if (sdl) { -+ memcpy(ea, LLADDR(sdl), sdl->sdl_alen); -+ freeifaddrs(head); -+ return 0; -+ } -+ } -+ } -+ } -+ -+ VLOG_ERR("could not find ethernet address for %s device", netdev_name); -+ freeifaddrs(head); -+ return ENODEV; -+} -+ -+static int -+set_etheraddr(const char *netdev_name, int hwaddr_family, -+ int hwaddr_len, const uint8_t mac[ETH_ADDR_LEN]) -+{ -+ struct ifreq ifr; -+ -+ memset(&ifr, 0, sizeof ifr); -+ strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); -+ ifr.ifr_addr.sa_family = hwaddr_family; -+ ifr.ifr_addr.sa_len = hwaddr_len; -+ memcpy(ifr.ifr_addr.sa_data, mac, hwaddr_len); -+ COVERAGE_INC(netdev_set_hwaddr); -+ if (ioctl(af_inet_sock, SIOCSIFLLADDR, &ifr) < 0) { -+ VLOG_ERR("ioctl(SIOCSIFLLADDR) on %s device failed: %s", -+ netdev_name, strerror(errno)); -+ return errno; -+ } -+ return 0; -+} -+ -+static int -+netdev_bsd_do_ioctl(const struct netdev *netdev, struct ifreq *ifr, -+ unsigned long cmd, const char *cmd_name) -+{ -+ strncpy(ifr->ifr_name, netdev_get_name(netdev), sizeof ifr->ifr_name); -+ if (ioctl(af_inet_sock, cmd, ifr) == -1) { -+ VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", -+ netdev_get_name(netdev), cmd_name, strerror(errno)); -+ return errno; -+ } -+ return 0; -+} diff --git a/net/openvswitch/files/patch-porting.diff b/net/openvswitch/files/patch-porting.diff deleted file mode 100644 index 596b147eabe5..000000000000 --- a/net/openvswitch/files/patch-porting.diff +++ /dev/null @@ -1,346 +0,0 @@ -diff -NBubrw -x '*.svn*' lib/automake.mk lib/automake.mk ---- lib/automake.mk 2010-09-10 23:36:43.000000000 +0200 -+++ lib/automake.mk 2011-10-07 11:18:52.000000000 +0200 -@@ -187,6 +187,13 @@ - lib/rtnetlink.h - endif - -+if HAVE_IF_DL -+lib_libopenvswitch_a_SOURCES += \ -+ lib/netdev-bsd.c \ -+ lib/rtbsd.c \ -+ lib/rtbsd.h -+endif -+ - if HAVE_OPENSSL - lib_libopenvswitch_a_SOURCES += lib/stream-ssl.c - nodist_lib_libopenvswitch_a_SOURCES += lib/dhparams.c -diff -NBubrw -x '*.svn*' lib/netdev.c lib/netdev.c ---- lib/netdev.c 2010-09-10 23:36:43.000000000 +0200 -+++ lib/netdev.c 2011-10-25 16:11:14.416612232 +0200 -@@ -49,6 +49,10 @@ - &netdev_gre_class, - &netdev_capwap_class, - #endif -+#ifdef __FreeBSD__ -+ &netdev_bsd_class, -+ &netdev_tap_class, -+#endif - }; - - static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes); -diff -NBubrw -x '*.svn*' lib/netdev-provider.h lib/netdev-provider.h ---- lib/netdev-provider.h 2010-09-10 23:36:43.000000000 +0200 -+++ lib/netdev-provider.h 2011-10-25 16:03:39.446629209 +0200 -@@ -551,6 +551,9 @@ - extern const struct netdev_class netdev_patch_class; - extern const struct netdev_class netdev_gre_class; - extern const struct netdev_class netdev_capwap_class; -+#ifdef __FreeBSD__ -+extern const struct netdev_class netdev_bsd_class; -+#endif - - #ifdef __cplusplus - } -diff -NBubrw -x '*.svn*' lib/rtbsd.c lib/rtbsd.c ---- lib/rtbsd.c 1970-01-01 01:00:00.000000000 +0100 -+++ lib/rtbsd.c 2011-10-07 11:18:52.000000000 +0200 -@@ -0,0 +1,168 @@ -+/* -+ * Copyright (c) 2011 Gaetano Catalli. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND. -+ */ -+ -+#include <config.h> -+ -+#include <unistd.h> -+#include <errno.h> -+#include <sys/socket.h> -+#include <net/if.h> -+#include <net/route.h> -+#include <poll.h> -+ -+#include "coverage.h" -+#include "socket-util.h" -+#include "poll-loop.h" -+#include "vlog.h" -+#include "rtbsd.h" -+ -+VLOG_DEFINE_THIS_MODULE(rtbsd) -+ -+/* PF_ROUTE socket. */ -+static int notify_sock = -1; -+ -+/* All registered notifiers. */ -+static struct list all_notifiers = LIST_INITIALIZER(&all_notifiers); -+ -+static void rtbsd_report_change(const struct if_msghdr *); -+static void rtbsd_report_notify_error(void); -+ -+/* Registers 'cb' to be called with auxiliary data 'aux' with network device -+ * change notifications. The notifier is stored in 'notifier', which the -+ * caller must not modify or free. -+ * -+ * Returns 0 if successful, otherwise a positive errno value. */ -+int -+rtbsd_notifier_register(struct rtbsd_notifier *notifier, -+ rtbsd_notify_func *cb, void *aux) -+{ -+ if (notify_sock < 0) { -+ int error; -+ notify_sock = socket(PF_ROUTE, SOCK_RAW, 0); -+ if (notify_sock < 0) { -+ VLOG_WARN("could not create PF_ROUTE socket: %s", -+ strerror(errno)); -+ return errno; -+ } -+ error = set_nonblocking(notify_sock); -+ if (error) { -+ VLOG_WARN("error set_nonblocking PF_ROUTE socket: %s", -+ strerror(error)); -+ return error; -+ } -+ } else { -+ /* Catch up on notification work so that the new notifier won't -+ * receive any stale notifications. XXX*/ -+ rtbsd_notifier_run(); -+ } -+ -+ list_push_back(&all_notifiers, ¬ifier->node); -+ notifier->cb = cb; -+ notifier->aux = aux; -+ return 0; -+} -+ -+/* Cancels notification on 'notifier', which must have previously been -+ * registered with rtbsd_notifier_register(). */ -+void -+rtbsd_notifier_unregister(struct rtbsd_notifier *notifier) -+{ -+ list_remove(¬ifier->node); -+ if (list_is_empty(&all_notifiers)) { -+ close(notify_sock); -+ notify_sock = -1; -+ } -+} -+ -+/* Calls all of the registered notifiers, passing along any as-yet-unreported -+ * netdev change events. */ -+void -+rtbsd_notifier_run(void) -+{ -+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); -+ struct if_msghdr msg; -+ if (notify_sock < 0) { -+ return; -+ } -+ -+ for (;;) { -+ int retval; -+ -+ msg.ifm_type = RTM_IFINFO; -+ msg.ifm_version = RTM_VERSION; //XXX check if necessary -+ -+ /* read from PF_ROUTE socket */ -+ retval = read(notify_sock, (char *)&msg, sizeof(msg)); -+ if (retval >= 0) { -+ /* received packet from PF_ROUTE socket -+ * XXX check for bad packets */ -+ if (msg.ifm_type == RTM_IFINFO) { -+ rtbsd_report_change(&msg); -+ } -+ } else if (errno == EAGAIN) { -+ return; -+ } else { -+ if (errno == ENOBUFS) { -+ VLOG_WARN_RL(&rl, "PF_ROUTE receive buffer overflowed"); -+ } else { -+ VLOG_WARN_RL(&rl, "error reading PF_ROUTE socket: %s", -+ strerror(errno)); -+ } -+ rtbsd_report_notify_error(); -+ } -+ } -+} -+ -+/* Causes poll_block() to wake up when network device change notifications are -+ * ready. */ -+void -+rtbsd_notifier_wait(void) -+{ -+ if (notify_sock >= 0) { -+ poll_fd_wait(notify_sock, POLLIN); -+ } -+} -+ -+static void -+rtbsd_report_change(const struct if_msghdr *msg) -+{ -+ struct rtbsd_notifier *notifier; -+ struct rtbsd_change change; -+ -+ /*COVERAGE_INC(rtbsd_changed);*/ /* XXX update coverage-counters.c */ -+ -+ change.msg_type = msg->ifm_type; //XXX -+ change.if_index = msg->ifm_index; -+ if_indextoname(msg->ifm_index, change.if_name); -+ change.master_ifindex = 0; //XXX -+ -+ LIST_FOR_EACH (notifier, struct rtbsd_notifier, node, -+ &all_notifiers) { -+ notifier->cb(&change, notifier->aux); -+ } -+} -+ -+/* If an error occurs the notifiers' callbacks are called with NULL changes */ -+static void -+rtbsd_report_notify_error(void) -+{ -+ struct rtbsd_notifier *notifier; -+ -+ LIST_FOR_EACH (notifier, struct rtbsd_notifier, node, -+ &all_notifiers) { -+ notifier->cb(NULL, notifier->aux); -+ } -+} -diff -NBubrw -x '*.svn*' lib/rtbsd.h lib/rtbsd.h ---- lib/rtbsd.h 1970-01-01 01:00:00.000000000 +0100 -+++ lib/rtbsd.h 2011-10-07 11:18:52.000000000 +0200 -@@ -0,0 +1,58 @@ -+/* -+ * Copyright (c) 2011 Gaetano Catalli. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright notice, -+ * this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND. -+ */ -+ -+#ifndef RTBSD_H -+#define RTBSD_H 1 -+ -+#include "list.h" -+ -+/* -+ * A digested version of a message received from a PF_ROUTE socket which -+ * indicates that a network device has been created or destroyed or changed. -+ */ -+struct rtbsd_change { -+ /* Copied from struct if_msghdr. */ -+ int msg_type; /* e.g. XXX. */ -+ -+ /* Copied from struct if_msghdr. */ -+ int if_index; /* Index of network device. */ -+ -+ char if_name[IF_NAMESIZE]; /* Name of network device. */ -+ int master_ifindex; /* Ifindex of datapath master (0 if none). */ -+}; -+ -+/* -+ * Function called to report that a netdev has changed. 'change' describes the -+ * specific change. It may be null if the buffer of change information -+ * overflowed, in which case the function must assume that every device may -+ * have changed. 'aux' is as specified in the call to -+ * rtbsd_notifier_register(). -+ */ -+typedef void rtbsd_notify_func(const struct rtbsd_change *, void *aux); -+ -+struct rtbsd_notifier { -+ struct list node; -+ rtbsd_notify_func *cb; -+ void *aux; -+}; -+ -+int rtbsd_notifier_register(struct rtbsd_notifier *, -+ rtbsd_notify_func *, void *aux); -+void rtbsd_notifier_unregister(struct rtbsd_notifier *); -+void rtbsd_notifier_run(void); -+void rtbsd_notifier_wait(void); -+ -+#endif /* rtbsd.h */ -diff -NBubrw -x '*.svn*' lib/socket-util.c lib/socket-util.c ---- lib/socket-util.c 2010-09-10 23:36:43.000000000 +0200 -+++ lib/socket-util.c 2011-10-07 11:18:52.000000000 +0200 -@@ -259,7 +259,10 @@ - } - fatal_signal_add_file_to_unlink(bind_path); - if (bind(fd, (struct sockaddr*) &un, un_len) -- || fchmod(fd, S_IRWXU)) { -+#ifndef __FreeBSD__ -+ || fchmod(fd, S_IRWXU) -+#endif -+ ) { - goto error; - } - } -diff -NBubrw -x '*.svn*' lib/stream-ssl.c lib/stream-ssl.c ---- lib/stream-ssl.c 2010-09-10 23:36:43.000000000 +0200 -+++ lib/stream-ssl.c 2011-10-07 11:18:52.000000000 +0200 -@@ -22,6 +22,8 @@ - #include <errno.h> - #include <inttypes.h> - #include <string.h> -+#include <sys/types.h> -+#include <sys/socket.h> - #include <netinet/tcp.h> - #include <openssl/err.h> - #include <openssl/ssl.h> -diff -NBubrw -x '*.svn*' utilities/ovs-ofctl.c utilities/ovs-ofctl.c ---- utilities/ovs-ofctl.c 2010-09-10 23:36:43.000000000 +0200 -+++ utilities/ovs-ofctl.c 2011-10-07 11:18:59.000000000 +0200 -@@ -18,6 +18,7 @@ - #include <errno.h> - #include <getopt.h> - #include <inttypes.h> -+#include <sys/socket.h> //XXX - #include <net/if.h> - #include <signal.h> - #include <stdlib.h> -diff -NBubrw -x '*.svn*' lib/dpif-netdev.c lib/dpif-netdev.c ---- lib/dpif-netdev.c 2010-09-10 23:36:43.000000000 +0200 -+++ lib/dpif-netdev.c 2011-10-25 15:57:13.646643609 +0200 -@@ -1043,7 +1043,7 @@ - struct ofpbuf packet; - struct dp_netdev *dp; - -- ofpbuf_init(&packet, DP_NETDEV_HEADROOM + max_mtu); -+ ofpbuf_init(&packet, DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + max_mtu); - LIST_FOR_EACH (dp, struct dp_netdev, node, &dp_netdev_list) { - struct dp_netdev_port *port; - ---- configure.ac.orig 2010-09-14 06:49:48.000000000 +0200 -+++ configure.ac 2011-11-01 11:22:52.000000000 +0100 -@@ -41,6 +41,7 @@ - - AC_SEARCH_LIBS([pow], [m]) - AC_SEARCH_LIBS([clock_gettime], [rt]) -+AC_SEARCH_LIBS([timer_create], [rt]) - - OVS_CHECK_COVERAGE - OVS_CHECK_NDEBUG -@@ -52,6 +53,7 @@ - OVS_CHECK_OVSDBMONITOR - OVS_CHECK_ER_DIAGRAMS - OVS_CHECK_IF_PACKET -+OVS_CHECK_IF_DL - OVS_CHECK_STRTOK_R - AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec], - [], [], [[#include <sys/stat.h>]]) diff --git a/net/openvswitch/pkg-plist b/net/openvswitch/pkg-plist index 4a2ad83c5bb6..8ba06eedffd3 100644 --- a/net/openvswitch/pkg-plist +++ b/net/openvswitch/pkg-plist @@ -1,17 +1,33 @@ bin/ovs-appctl bin/ovs-controller -bin/ovs-discover bin/ovs-dpctl -bin/ovs-kill bin/ovs-ofctl -bin/ovs-openflowd bin/ovs-vsctl +bin/ovs-benchmark bin/ovsdb-tool bin/ovsdb-client bin/ovs-pki +bin/ovs-parse-leaks +bin/ovs-pcap +bin/ovs-tcpundump +bin/ovs-test +bin/ovs-vlan-test sbin/ovs-vswitchd sbin/ovsdb-server +sbin/ovs-bugtool +share/openvswitch/bugtool-plugins/kernel-info/openvswitch.xml +share/openvswitch/bugtool-plugins/network-status/openvswitch.xml +share/openvswitch/bugtool-plugins/system-configuration.xml +share/openvswitch/bugtool-plugins/system-logs/openvswitch.xml +share/openvswitch/bugtool-plugins/system-configuration/openvswitch.xml share/openvswitch/python/ovs/dirs.py +share/openvswitch/python/ovs/db/__init__.py +share/openvswitch/python/ovs/db/data.py +share/openvswitch/python/ovs/db/error.py +share/openvswitch/python/ovs/db/idl.py +share/openvswitch/python/ovs/db/parser.py +share/openvswitch/python/ovs/db/schema.py +share/openvswitch/python/ovs/db/types.py share/openvswitch/python/ovs/__init__.py share/openvswitch/python/ovs/daemon.py share/openvswitch/python/ovs/fatal_signal.py @@ -24,23 +40,41 @@ share/openvswitch/python/ovs/reconnect.py share/openvswitch/python/ovs/socket_util.py share/openvswitch/python/ovs/stream.py share/openvswitch/python/ovs/timeval.py +share/openvswitch/python/ovs/unixctl.py share/openvswitch/python/ovs/util.py -share/openvswitch/python/ovs/db/__init__.py -share/openvswitch/python/ovs/db/data.py -share/openvswitch/python/ovs/db/error.py -share/openvswitch/python/ovs/db/idl.py -share/openvswitch/python/ovs/db/parser.py -share/openvswitch/python/ovs/db/schema.py -share/openvswitch/python/ovs/db/types.py +share/openvswitch/python/ovs/version.py +share/openvswitch/python/ovs/vlog.py +share/openvswitch/python/ovstest/__init__.py +share/openvswitch/python/ovstest/args.py +share/openvswitch/python/ovstest/rpcserver.py +share/openvswitch/python/ovstest/tcp.py +share/openvswitch/python/ovstest/udp.py +share/openvswitch/python/ovstest/util.py +share/openvswitch/python/ovstest/vswitch.py share/openvswitch/vswitch.ovsschema -@dirrmtry var/run/openvswitch -@dirrmtry var/run +share/openvswitch/scripts/ovs-lib +share/openvswitch/scripts/ovs-ctl +share/openvswitch/scripts/ovs-save +share/openvswitch/scripts/ovs-bugtool-cfm-show +share/openvswitch/scripts/ovs-bugtool-lacp-show +share/openvswitch/scripts/ovs-bugtool-tc-class-show +share/openvswitch/scripts/ovs-bugtool-ovsdb-dump +share/openvswitch/scripts/ovs-check-dead-ifs +share/openvswitch/scripts/ovs-bugtool-coverage-show +share/openvswitch/scripts/ovs-bugtool-vsctl-show +share/openvswitch/scripts/ovs-bugtool-daemons-ver +share/openvswitch/scripts/ovs-bugtool-bond-show @dirrmtry var/log/openvswitch -@dirrmtry var/log -@dirrmtry etc/openvswitch -@dirrm share/openvswitch/python/ovs/db -@dirrm share/openvswitch/python/ovs -@dirrm share/openvswitch/python -@dirrm share/openvswitch/pki -@dirrm share/openvswitch/ovsdbmonitor -@dirrm share/openvswitch +@dirrmtry var/lib/openvswitch/pki +@dirrmtry var/lib/openvswitch +@dirrmtry share/openvswitch/scripts +@dirrmtry share/openvswitch/python/ovstest +@dirrmtry share/openvswitch/python/ovs/db +@dirrmtry share/openvswitch/python/ovs +@dirrmtry share/openvswitch/python +@dirrmtry share/openvswitch/bugtool-plugins/system-logs +@dirrmtry share/openvswitch/bugtool-plugins/system-configuration +@dirrmtry share/openvswitch/bugtool-plugins/network-status +@dirrmtry share/openvswitch/bugtool-plugins/kernel-info +@dirrmtry share/openvswitch/bugtool-plugins +@dirrmtry share/openvswitch |