+ *in6 = netdev->in6;
+ return 0;
+}
+
+#if defined(__NetBSD__)
+static char *
+netdev_bsd_kernel_name_to_ovs_name(const char *kernel_name)
+{
+ char *ovs_name = NULL;
+ struct shash device_shash;
+ struct shash_node *node;
+
+ shash_init(&device_shash);
+ netdev_get_devices(&netdev_tap_class, &device_shash);
+ SHASH_FOR_EACH(node, &device_shash) {
+ struct netdev *netdev = node->data;
+ struct netdev_bsd * const dev = netdev_bsd_cast(netdev);
+
+ if (!strcmp(dev->kernel_name, kernel_name)) {
+ free(ovs_name);
+ ovs_name = xstrdup(netdev_get_name(&dev->up));
+ }
+ netdev_close(netdev);
+ }
+ shash_destroy(&device_shash);
+
+ return ovs_name ? ovs_name : xstrdup(kernel_name);
+}
+#endif
+
+static int
+netdev_bsd_get_next_hop(const struct in_addr *host OVS_UNUSED,
+ struct in_addr *next_hop OVS_UNUSED,
+ char **netdev_name OVS_UNUSED)
+{
+#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;
+ char *kernel_name;
+
+ kernel_name = xmemdup0(sdl->sdl_data, sdl->sdl_nlen);
+ ifname = netdev_bsd_kernel_name_to_ovs_name(kernel_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);