+#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);
+ return 0;
+#else
+ return EOPNOTSUPP;
+#endif
+}
+
+static int
+netdev_bsd_arp_lookup(const struct netdev *netdev OVS_UNUSED,
+ ovs_be32 ip OVS_UNUSED,
+ uint8_t mac[ETH_ADDR_LEN] OVS_UNUSED)
+{
+#if defined(__NetBSD__)
+ const struct rt_msghdr *rtm;
+ size_t needed;
+ char *buf;
+ const char *cp;
+ const char *ep;
+ int mib[6];
+ int error;
+
+ buf = NULL;
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) {
+ error = errno;
+ goto error;
+ }
+ buf = xmalloc(needed);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) {
+ error = errno;
+ goto error;
+ }
+ ep = buf + needed;
+ for (cp = buf; cp < ep; cp += rtm->rtm_msglen) {
+ const struct sockaddr_inarp *sina;
+ const struct sockaddr_dl *sdl;
+
+ rtm = (const void *)cp;
+ sina = (const void *)(rtm + 1);
+ if (ip != sina->sin_addr.s_addr) {
+ continue;
+ }
+ sdl = (const void *)
+ ((const char *)(const void *)sina + RT_ROUNDUP(sina->sin_len));
+ if (sdl->sdl_alen == ETH_ADDR_LEN) {
+ memcpy(mac, &sdl->sdl_data[sdl->sdl_nlen], ETH_ADDR_LEN);
+ error = 0;
+ goto error;
+ }
+ }
+ error = ENXIO;
+error:
+ free(buf);
+ return error;
+#else
+ return EOPNOTSUPP;
+#endif
+}
+