[ovs-dev] [PATCH 21/22] implement get_next_hop for NetBSD

YAMAMOTO Takashi yamt at mwd.biglobe.ne.jp
Mon Apr 22 13:20:19 UTC 2013


Signed-off-by: YAMAMOTO Takashi <yamt at mwd.biglobe.ne.jp>
---
 INSTALL.userspace |   6 +--
 lib/netdev-bsd.c  | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 152 insertions(+), 5 deletions(-)

diff --git a/INSTALL.userspace b/INSTALL.userspace
index d1f0b69..f54b93e 100644
--- a/INSTALL.userspace
+++ b/INSTALL.userspace
@@ -51,9 +51,9 @@ ovs-vswitchd will create a TAP device as the bridge's local interface,
 named the same as the bridge, as well as for each configured internal
 interface.
 
-Currently, on FreeBSD and NetBSD, the functionality required for in-band
-control support is not implemented.  To avoid related errors, you can
-disable the in-band support with the following command.
+Currently, on FreeBSD, the functionality required for in-band control
+support is not implemented.  To avoid related errors, you can disable
+the in-band support with the following command.
 
     ovs-vsctl set bridge br0 other_config:disable-in-band=true
 
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index 7a29898..43edc9e 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2011 Gaetano Catalli.
+ * Copyright (c) 2013 YAMAMOTO Takashi.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,6 +39,9 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/sysctl.h>
+#if defined(__NetBSD__)
+#include <net/route.h>
+#endif
 
 #include "rtbsd.h"
 #include "coverage.h"
@@ -1251,6 +1255,149 @@ netdev_bsd_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
     return 0;
 }
 
+#if defined(__NetBSD__)
+static struct netdev_dev *
+find_netdev_by_kernel_name(const char *kernel_name)
+{
+    struct shash device_shash;
+    struct shash_node *node;
+
+    shash_init(&device_shash);
+    netdev_dev_get_devices(&netdev_tap_class, &device_shash);
+    SHASH_FOR_EACH(node, &device_shash) {
+        struct netdev_dev_bsd * const dev = node->data;
+
+        if (!strcmp(dev->kernel_name, kernel_name)) {
+            shash_destroy(&device_shash);
+            return &dev->netdev_dev;
+        }
+    }
+    shash_destroy(&device_shash);
+    return NULL;
+}
+
+static const char *
+netdev_bsd_convert_kernel_name_to_ovs_name(const char *kernel_name)
+{
+    const struct netdev_dev * const netdev_dev =
+      find_netdev_by_kernel_name(kernel_name);
+
+    if (netdev_dev == NULL) {
+        return NULL;
+    }
+    return netdev_dev_get_name(netdev_dev);
+}
+#endif
+
+static int
+netdev_bsd_get_next_hop(const struct in_addr *host, struct in_addr *next_hop,
+                        char **netdev_name)
+{
+#if defined(__NetBSD__)
+    static int seq = 0;
+    struct sockaddr_in sin;
+    struct sockaddr_dl sdl;
+    int s;
+    int i;
+    struct {
+        struct rt_msghdr h;
+        char space[512];
+    } buf;
+    struct rt_msghdr *rtm = &buf.h;
+    const pid_t pid = getpid();
+    char *cp;
+    ssize_t ssz;
+    bool gateway = false;
+    char *ifname = NULL;
+    int saved_errno;
+
+    memset(next_hop, 0, sizeof(*next_hop));
+    *netdev_name = NULL;
+
+    memset(&sin, 0, sizeof(sin));
+    sin.sin_len = sizeof(sin);
+    sin.sin_family = AF_INET;
+    sin.sin_port = 0;
+    sin.sin_addr = *host;
+
+    memset(&sdl, 0, sizeof(sdl));
+    sdl.sdl_len = sizeof(sdl);
+    sdl.sdl_family = AF_LINK;
+
+    s = socket(PF_ROUTE, SOCK_RAW, 0);
+    memset(&buf, 0, sizeof(buf));
+    rtm->rtm_flags = RTF_HOST|RTF_UP;
+    rtm->rtm_version = RTM_VERSION;
+    rtm->rtm_addrs = RTA_DST|RTA_IFP;
+    cp = (void *)&buf.space;
+    memcpy(cp, &sin, sizeof(sin));
+    RT_ADVANCE(cp, (struct sockaddr *)(void *)&sin);
+    memcpy(cp, &sdl, sizeof(sdl));
+    RT_ADVANCE(cp, (struct sockaddr *)(void *)&sdl);
+    rtm->rtm_msglen = cp - (char *)(void *)rtm;
+    rtm->rtm_seq = ++seq;
+    rtm->rtm_type = RTM_GET;
+    rtm->rtm_pid = pid;
+    write(s, rtm, rtm->rtm_msglen);
+    memset(&buf, 0, sizeof(buf));
+    do {
+        ssz = read(s, &buf, sizeof(buf));
+    } while (ssz > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+    saved_errno = errno;
+    close(s);
+    if (ssz <= 0) {
+        if (ssz < 0) {
+            return saved_errno;
+        }
+        return EPIPE; /* XXX */
+    }
+    cp = (void *)&buf.space;
+    for (i = 1; i; i <<= 1) {
+        if ((rtm->rtm_addrs & i) != 0) {
+            const struct sockaddr *sa = (const void *)cp;
+
+            if ((i == RTA_GATEWAY) && sa->sa_family == AF_INET) {
+                const struct sockaddr_in * const sin =
+                  (const struct sockaddr_in *)sa;
+
+                *next_hop = sin->sin_addr;
+                gateway = true;
+            }
+            if ((i == RTA_IFP) && sa->sa_family == AF_LINK) {
+                const struct sockaddr_dl * const sdl =
+                  (const struct sockaddr_dl *)sa;
+                const size_t nlen = sdl->sdl_nlen;
+                char * const kernel_name = xmalloc(nlen + 1);
+                const char *name;
+
+                memcpy(kernel_name, sdl->sdl_data, nlen);
+                kernel_name[nlen] = 0;
+                name = netdev_bsd_convert_kernel_name_to_ovs_name(kernel_name);
+                if (name == NULL) {
+                    ifname = xstrdup(kernel_name);
+                } else {
+                    ifname = xstrdup(name);
+                }
+                free(kernel_name);
+            }
+            RT_ADVANCE(cp, sa);
+        }
+    }
+    if (ifname == NULL) {
+        return ENXIO;
+    }
+    if (!gateway) {
+        *next_hop = *host;
+    }
+    *netdev_name = ifname;
+    VLOG_DBG("host " IP_FMT " next-hop " IP_FMT " if %s",
+      IP_ARGS(host->s_addr), IP_ARGS(next_hop->s_addr), *netdev_name);
+    return 0;
+#else
+    return EOPNOTSUPP;
+#endif
+}
+
 static void
 make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr)
 {
@@ -1380,7 +1527,7 @@ const struct netdev_class netdev_bsd_class = {
     netdev_bsd_set_in4,
     netdev_bsd_get_in6,
     NULL, /* add_router */
-    NULL, /* get_next_hop */
+    netdev_bsd_get_next_hop,
     NULL, /* get_status */
     NULL, /* arp_lookup */
 
@@ -1441,7 +1588,7 @@ const struct netdev_class netdev_tap_class = {
     netdev_bsd_set_in4,
     netdev_bsd_get_in6,
     NULL, /* add_router */
-    NULL, /* get_next_hop */
+    netdev_bsd_get_next_hop,
     NULL, /* get_status */
     NULL, /* arp_lookup */
 
-- 
1.8.0.1




More information about the dev mailing list