#include <sys/sysctl.h>
#if defined(__NetBSD__)
#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_inarp.h>
#endif
#include "rtbsd.h"
int fd;
};
-static const struct netdev_rx_class netdev_rx_bsd_class;
-
struct netdev_bsd {
struct netdev up;
+
+ /* Never changes after initialization. */
+ char *kernel_name;
+
+ /* Protects all members below. */
+ struct ovs_mutex mutex;
+
unsigned int cache_valid;
unsigned int change_seq;
/* Used for sending packets on non-tap devices. */
pcap_t *pcap;
int fd;
-
- char *kernel_name;
};
static int get_flags(const struct netdev *, int *flagsp);
static int set_flags(const char *, int flags);
static int do_set_addr(struct netdev *netdev,
- int ioctl_nr, const char *ioctl_name,
+ unsigned long 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,
static void ifr_set_flags(struct ifreq *, int flags);
#ifdef __NetBSD__
-static int af_link_ioctl(int command, const void *arg);
+static int af_link_ioctl(unsigned long command, const void *arg);
#endif
static void netdev_bsd_run(void);
static struct netdev_rx_bsd *
netdev_rx_bsd_cast(const struct netdev_rx *rx)
{
- netdev_rx_assert_class(rx, &netdev_rx_bsd_class);
+ ovs_assert(is_netdev_bsd_class(netdev_get_class(rx->netdev)));
return CONTAINER_OF(rx, struct netdev_rx_bsd, up);
}
return 0;
}
-/* Allocate a netdev_bsd structure */
+static struct netdev *
+netdev_bsd_alloc(void)
+{
+ struct netdev_bsd *netdev = xzalloc(sizeof *netdev);
+ return &netdev->up;
+}
+
static int
-netdev_bsd_create_system(const struct netdev_class *class, const char *name,
- struct netdev **netdevp)
+netdev_bsd_construct_system(struct netdev *netdev_)
{
- struct netdev_bsd *netdev;
+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
enum netdev_flags flags;
int error;
return error;
}
- netdev = xzalloc(sizeof *netdev);
+ ovs_mutex_init(&netdev->mutex, PTHREAD_MUTEX_NORMAL);
netdev->change_seq = 1;
- netdev_init(&netdev->up, name, class);
netdev->tap_fd = -1;
- netdev->kernel_name = xstrdup(name);
+ netdev->kernel_name = xstrdup(netdev_->name);
/* Verify that the netdev really exists by attempting to read its flags */
- error = netdev_get_flags(&netdev->up, &flags);
+ error = netdev_get_flags(netdev_, &flags);
if (error == ENXIO) {
free(netdev->kernel_name);
- netdev_uninit(&netdev->up, false);
- free(netdev);
cache_notifier_unref();
return error;
}
- *netdevp = &netdev->up;
return 0;
}
-/*
- * Allocate a netdev_bsd structure with 'tap' class.
- */
static int
-netdev_bsd_create_tap(const struct netdev_class *class, const char *name,
- struct netdev **netdevp)
+netdev_bsd_construct_tap(struct netdev *netdev_)
{
- struct netdev_bsd *netdev = NULL;
+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
+ const char *name = netdev_->name;
int error = 0;
struct ifreq ifr;
char *kernel_name = NULL;
goto error;
}
- /* allocate the device structure and set the internal flag */
- netdev = xzalloc(sizeof *netdev);
-
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. */
+ ovs_mutex_init(&netdev->mutex, PTHREAD_MUTEX_NORMAL);
netdev->tap_fd = open("/dev/tap", O_RDWR);
netdev->change_seq = 1;
if (netdev->tap_fd < 0) {
goto error_unref_notifier;
}
- /* initialize the device structure and
- * link the structure to its netdev */
- netdev_init(&netdev->up, name, class);
netdev->kernel_name = kernel_name;
- *netdevp = &netdev->up;
return 0;
error_unref_notifier:
+ ovs_mutex_destroy(&netdev->mutex);
cache_notifier_unref();
error:
- free(netdev);
free(kernel_name);
return error;
}
static void
-netdev_bsd_destroy(struct netdev *netdev_)
+netdev_bsd_destruct(struct netdev *netdev_)
{
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
pcap_close(netdev->pcap);
}
free(netdev->kernel_name);
+ ovs_mutex_destroy(&netdev->mutex);
+}
+
+static void
+netdev_bsd_dealloc(struct netdev *netdev_)
+{
+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
+
free(netdev);
}
return error;
}
+static struct netdev_rx *
+netdev_bsd_rx_alloc(void)
+{
+ struct netdev_rx_bsd *rx = xzalloc(sizeof *rx);
+ return &rx->up;
+}
+
static int
-netdev_bsd_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
+netdev_bsd_rx_construct(struct netdev_rx *rx_)
{
+ struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
+ struct netdev *netdev_ = rx->up.netdev;
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
-
- struct netdev_rx_bsd *rx;
- pcap_t *pcap;
- int fd;
+ int error;
if (!strcmp(netdev_get_type(netdev_), "tap")) {
- pcap = NULL;
- fd = netdev->tap_fd;
+ rx->pcap_handle = NULL;
+ rx->fd = netdev->tap_fd;
+ error = 0;
} else {
- int error = netdev_bsd_open_pcap(netdev_get_kernel_name(netdev_),
- &pcap, &fd);
- if (error) {
- return error;
+ ovs_mutex_lock(&netdev->mutex);
+ error = netdev_bsd_open_pcap(netdev_get_kernel_name(netdev_),
+ &rx->pcap_handle, &rx->fd);
+ if (!error) {
+ netdev_bsd_changed(netdev);
}
-
- netdev_bsd_changed(netdev);
+ ovs_mutex_unlock(&netdev->mutex);
}
- rx = xmalloc(sizeof *rx);
- netdev_rx_init(&rx->up, netdev_, &netdev_rx_bsd_class);
- rx->pcap_handle = pcap;
- rx->fd = fd;
-
- *rxp = &rx->up;
- return 0;
+ return error;
}
static void
-netdev_rx_bsd_destroy(struct netdev_rx *rx_)
+netdev_bsd_rx_destruct(struct netdev_rx *rx_)
{
struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
if (rx->pcap_handle) {
pcap_close(rx->pcap_handle);
}
+}
+
+static void
+netdev_bsd_rx_dealloc(struct netdev_rx *rx_)
+{
+ struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
+
free(rx);
}
}
}
-
static int
-netdev_rx_bsd_recv(struct netdev_rx *rx_, void *data, size_t size)
+netdev_bsd_rx_recv(struct netdev_rx *rx_, void *data, size_t size)
{
struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
* when a packet is ready to be received with netdev_rx_recv() on 'rx'.
*/
static void
-netdev_rx_bsd_wait(struct netdev_rx *rx_)
+netdev_bsd_rx_wait(struct netdev_rx *rx_)
{
struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
/* Discards all packets waiting to be received from 'rx'. */
static int
-netdev_rx_bsd_drain(struct netdev_rx *rx_)
+netdev_bsd_rx_drain(struct netdev_rx *rx_)
{
struct ifreq ifr;
struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
{
struct netdev_bsd *dev = netdev_bsd_cast(netdev_);
const char *name = netdev_get_name(netdev_);
+ int error;
+ ovs_mutex_lock(&dev->mutex);
if (dev->tap_fd < 0 && !dev->pcap) {
- int error = netdev_bsd_open_pcap(name, &dev->pcap, &dev->fd);
- if (error) {
- return error;
- }
+ error = netdev_bsd_open_pcap(name, &dev->pcap, &dev->fd);
+ } else {
+ error = 0;
}
- for (;;) {
+ while (!error) {
ssize_t retval;
if (dev->tap_fd >= 0) {
retval = write(dev->tap_fd, data, size);
if (retval < 0) {
if (errno == EINTR) {
continue;
- } else if (errno != EAGAIN) {
- VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
- name, ovs_strerror(errno));
+ } else {
+ error = errno;
+ if (error != EAGAIN) {
+ VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: "
+ "%s", name, ovs_strerror(error));
+ }
}
- return errno;
} else if (retval != size) {
VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%zd bytes of "
"%zu) on %s", retval, size, name);
- return EMSGSIZE;
+ error = EMSGSIZE;
} else {
- return 0;
+ break;
}
}
+
+ ovs_mutex_unlock(&dev->mutex);
+ return error;
}
/*
{
struct netdev_bsd *dev = netdev_bsd_cast(netdev_);
+ ovs_mutex_lock(&dev->mutex);
if (dev->tap_fd >= 0) {
/* TAP device always accepts packets. */
poll_immediate_wake();
/* We haven't even tried to send a packet yet. */
poll_immediate_wake();
}
+ ovs_mutex_unlock(&dev->mutex);
}
/*
const uint8_t mac[ETH_ADDR_LEN])
{
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
- int error;
+ int error = 0;
+ ovs_mutex_lock(&netdev->mutex);
if (!(netdev->cache_valid & VALID_ETHERADDR)
|| !eth_addr_equals(netdev->etheraddr, mac)) {
error = set_etheraddr(netdev_get_kernel_name(netdev_), AF_LINK,
memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
netdev_bsd_changed(netdev);
}
- } else {
- error = 0;
}
+ ovs_mutex_unlock(&netdev->mutex);
+
return error;
}
uint8_t mac[ETH_ADDR_LEN])
{
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
+ int error = 0;
+ ovs_mutex_lock(&netdev->mutex);
if (!(netdev->cache_valid & VALID_ETHERADDR)) {
- int error = get_etheraddr(netdev_get_kernel_name(netdev_),
- netdev->etheraddr);
- if (error) {
- return error;
+ error = get_etheraddr(netdev_get_kernel_name(netdev_),
+ netdev->etheraddr);
+ if (!error) {
+ netdev->cache_valid |= VALID_ETHERADDR;
}
- netdev->cache_valid |= VALID_ETHERADDR;
}
- memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
+ if (!error) {
+ memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN);
+ }
+ ovs_mutex_unlock(&netdev->mutex);
- return 0;
+ return error;
}
/*
netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup)
{
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
+ int error = 0;
+ ovs_mutex_lock(&netdev->mutex);
if (!(netdev->cache_valid & VALID_MTU)) {
struct ifreq ifr;
- int error;
error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr,
SIOCGIFMTU, "SIOCGIFMTU");
- if (error) {
- return error;
+ if (!error) {
+ netdev->mtu = ifr.ifr_mtu;
+ netdev->cache_valid |= VALID_MTU;
}
- netdev->mtu = ifr.ifr_mtu;
- netdev->cache_valid |= VALID_MTU;
}
+ if (!error) {
+ *mtup = netdev->mtu;
+ }
+ ovs_mutex_unlock(&netdev->mutex);
- *mtup = netdev->mtu;
return 0;
}
static int
-netdev_bsd_get_ifindex(const struct netdev *netdev)
+netdev_bsd_get_ifindex(const struct netdev *netdev_)
{
+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
int ifindex, error;
- error = get_ifindex(netdev, &ifindex);
+ ovs_mutex_lock(&netdev->mutex);
+ error = get_ifindex(netdev_, &ifindex);
+ ovs_mutex_unlock(&netdev->mutex);
+
return error ? -error : ifindex;
}
netdev_bsd_get_carrier(const struct netdev *netdev_, bool *carrier)
{
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
+ int error = 0;
+ ovs_mutex_lock(&netdev->mutex);
if (!(netdev->cache_valid & VALID_CARRIER)) {
struct ifmediareq ifmr;
- int error;
memset(&ifmr, 0, sizeof(ifmr));
strncpy(ifmr.ifm_name, netdev_get_kernel_name(netdev_),
sizeof ifmr.ifm_name);
error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr);
- if (error) {
+ if (!error) {
+ netdev->carrier = (ifmr.ifm_status & IFM_ACTIVE) == IFM_ACTIVE;
+ netdev->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->carrier = true;
+ }
+ } else {
VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s",
netdev_get_name(netdev_), ovs_strerror(error));
- return error;
- }
-
- netdev->carrier = (ifmr.ifm_status & IFM_ACTIVE) == IFM_ACTIVE;
- netdev->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->carrier = true;
}
}
- *carrier = netdev->carrier;
+ if (!error) {
+ *carrier = netdev->carrier;
+ }
+ ovs_mutex_unlock(&netdev->mutex);
- return 0;
+ return error;
}
static void
struct in_addr *netmask)
{
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
+ int error = 0;
+ ovs_mutex_lock(&netdev->mutex);
if (!(netdev->cache_valid & VALID_IN4)) {
- const struct sockaddr_in *sin;
struct ifreq ifr;
- int error;
ifr.ifr_addr.sa_family = AF_INET;
error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr,
SIOCGIFADDR, "SIOCGIFADDR");
- if (error) {
- return error;
- }
+ if (!error) {
+ const struct sockaddr_in *sin;
- sin = (struct sockaddr_in *) &ifr.ifr_addr;
- netdev->in4 = sin->sin_addr;
- error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr,
- SIOCGIFNETMASK, "SIOCGIFNETMASK");
- if (error) {
- return error;
+ sin = (struct sockaddr_in *) &ifr.ifr_addr;
+ netdev->in4 = sin->sin_addr;
+ netdev->cache_valid |= VALID_IN4;
+ error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr,
+ SIOCGIFNETMASK, "SIOCGIFNETMASK");
+ if (!error) {
+ *netmask = sin->sin_addr;
+ }
}
- netdev->netmask = sin->sin_addr;
- netdev->cache_valid |= VALID_IN4;
}
- *in4 = netdev->in4;
- *netmask = netdev->netmask;
+ if (!error) {
+ *in4 = netdev->in4;
+ *netmask = netdev->netmask;
+ }
+ ovs_mutex_unlock(&netdev->mutex);
- return in4->s_addr == INADDR_ANY ? EADDRNOTAVAIL : 0;
+ return error ? error : in4->s_addr == INADDR_ANY ? EADDRNOTAVAIL : 0;
}
/*
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
int error;
+ ovs_mutex_lock(&netdev->mutex);
error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", addr);
if (!error) {
if (addr.s_addr != INADDR_ANY) {
}
netdev_bsd_changed(netdev);
}
+ ovs_mutex_unlock(&netdev->mutex);
+
return error;
}
#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
+}
+
static void
make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr)
{
static int
do_set_addr(struct netdev *netdev,
- int ioctl_nr, const char *ioctl_name, struct in_addr addr)
+ unsigned long ioctl_nr, const char *ioctl_name,
+ struct in_addr addr)
{
struct ifreq ifr;
make_in4_sockaddr(&ifr.ifr_addr, addr);
NULL, /* init */
netdev_bsd_run,
netdev_bsd_wait,
- netdev_bsd_create_system,
- netdev_bsd_destroy,
+ netdev_bsd_alloc,
+ netdev_bsd_construct_system,
+ netdev_bsd_destruct,
+ netdev_bsd_dealloc,
NULL, /* get_config */
NULL, /* set_config */
NULL, /* get_tunnel_config */
- netdev_bsd_rx_open,
-
netdev_bsd_send,
netdev_bsd_send_wait,
NULL, /* add_router */
netdev_bsd_get_next_hop,
NULL, /* get_status */
- NULL, /* arp_lookup */
+ netdev_bsd_arp_lookup, /* arp_lookup */
netdev_bsd_update_flags,
- netdev_bsd_change_seq
+ netdev_bsd_change_seq,
+
+ netdev_bsd_rx_alloc,
+ netdev_bsd_rx_construct,
+ netdev_bsd_rx_destruct,
+ netdev_bsd_rx_dealloc,
+ netdev_bsd_rx_recv,
+ netdev_bsd_rx_wait,
+ netdev_bsd_rx_drain,
};
const struct netdev_class netdev_tap_class = {
NULL, /* init */
netdev_bsd_run,
netdev_bsd_wait,
- netdev_bsd_create_tap,
- netdev_bsd_destroy,
+ netdev_bsd_alloc,
+ netdev_bsd_construct_tap,
+ netdev_bsd_destruct,
+ netdev_bsd_dealloc,
NULL, /* get_config */
NULL, /* set_config */
NULL, /* get_tunnel_config */
- netdev_bsd_rx_open,
-
netdev_bsd_send,
netdev_bsd_send_wait,
NULL, /* add_router */
netdev_bsd_get_next_hop,
NULL, /* get_status */
- NULL, /* arp_lookup */
+ netdev_bsd_arp_lookup, /* arp_lookup */
netdev_bsd_update_flags,
- netdev_bsd_change_seq
-};
+ netdev_bsd_change_seq,
-static const struct netdev_rx_class netdev_rx_bsd_class = {
- netdev_rx_bsd_destroy,
- netdev_rx_bsd_recv,
- netdev_rx_bsd_wait,
- netdev_rx_bsd_drain,
+ netdev_bsd_rx_alloc,
+ netdev_bsd_rx_construct,
+ netdev_bsd_rx_destruct,
+ netdev_bsd_rx_dealloc,
+ netdev_bsd_rx_recv,
+ netdev_bsd_rx_wait,
+ netdev_bsd_rx_drain,
};
\f
/* Calls ioctl() on an AF_LINK sock, passing the specified 'command' and
* 'arg'. Returns 0 if successful, otherwise a positive errno value. */
int
-af_link_ioctl(int command, const void *arg)
+af_link_ioctl(unsigned long command, const void *arg)
{
static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
static int sock;