From: Ben Pfaff Date: Thu, 8 Aug 2013 06:48:59 +0000 (-0700) Subject: netdev-bsd: Make use of AF_LINK socket thread-safe in NetBSD. X-Git-Tag: sliver-openvswitch-2.0.90-1~29^2~1 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=996e5ae9e915103607c7045daffaf6fab143ef34;p=sliver-openvswitch.git netdev-bsd: Make use of AF_LINK socket thread-safe in NetBSD. Signed-off-by: Ben Pfaff CC: Ed Maste CC: YAMAMOTO Takashi --- diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index b799cb589..67c0c182b 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -50,6 +50,7 @@ #include "fatal-signal.h" #include "ofpbuf.h" #include "openflow/openflow.h" +#include "ovs-thread.h" #include "packets.h" #include "poll-loop.h" #include "socket-util.h" @@ -107,11 +108,6 @@ enum { VALID_CARRIER = 1 << 5 }; -#if defined(__NetBSD__) -/* AF_LINK socket used for netdev_bsd_get_stats and set_etheraddr */ -static int af_link_sock = -1; -#endif /* defined(__NetBSD__) */ - #define PCAP_SNAPLEN 2048 @@ -144,12 +140,16 @@ static int get_ifindex(const struct netdev *, int *ifindexp); static int ifr_get_flags(const struct ifreq *); static void ifr_set_flags(struct ifreq *, int flags); -static int netdev_bsd_init(void); +#ifdef __NetBSD__ +static int af_link_ioctl(int command, const void *arg); +#endif + +static void netdev_bsd_run(void); static bool is_netdev_bsd_class(const struct netdev_class *netdev_class) { - return netdev_class->init == netdev_bsd_init; + return netdev_class->run == netdev_bsd_run; } static struct netdev_bsd * @@ -172,29 +172,6 @@ netdev_get_kernel_name(const struct netdev *netdev) return netdev_bsd_cast(netdev)->kernel_name; } -/* Initialize the AF_INET socket used for ioctl operations */ -static int -netdev_bsd_init(void) -{ -#if defined(__NetBSD__) - static int status = -1; - - if (status >= 0) { /* already initialized */ - return status; - } - - af_link_sock = socket(AF_LINK, SOCK_DGRAM, 0); - status = af_link_sock >= 0 ? 0 : errno; - if (status) { - VLOG_ERR("failed to create link socket: %s", ovs_strerror(status)); - } - - return status; -#else - return 0; -#endif /* defined(__NetBSD__) */ -} - /* * Perform periodic work needed by netdev. In BSD netdevs it checks for any * interface status changes, and eventually calls all the user callbacks. @@ -931,19 +908,16 @@ netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) return 0; #elif defined(__NetBSD__) struct ifdatareq ifdr; - int saved_errno; - int ret; + int error; memset(&ifdr, 0, sizeof(ifdr)); strncpy(ifdr.ifdr_name, netdev_get_kernel_name(netdev_), sizeof(ifdr.ifdr_name)); - ret = ioctl(af_link_sock, SIOCGIFDATA, &ifdr); - saved_errno = errno; - if (ret == -1) { - return saved_errno; + error = af_link_ioctl(SIOCGIFDATA, &ifdr); + if (!error) { + convert_stats(stats, &ifdr.ifdr_data); } - convert_stats(stats, &ifdr.ifdr_data); - return 0; + return error; #else #error not implemented #endif @@ -1402,7 +1376,7 @@ netdev_bsd_change_seq(const struct netdev *netdev) const struct netdev_class netdev_bsd_class = { "system", - netdev_bsd_init, + NULL, /* init */ netdev_bsd_run, netdev_bsd_wait, netdev_bsd_create_system, @@ -1457,7 +1431,7 @@ const struct netdev_class netdev_bsd_class = { const struct netdev_class netdev_tap_class = { "tap", - netdev_bsd_init, + NULL, /* init */ netdev_bsd_run, netdev_bsd_wait, netdev_bsd_create_tap, @@ -1625,7 +1599,7 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, struct if_laddrreq req; struct sockaddr_dl *sdl; struct sockaddr_storage oldaddr; - int ret; + int error; /* * get the old address, add new one, and then remove old one. @@ -1641,9 +1615,10 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, req.addr.ss_family = hwaddr_family; sdl = (struct sockaddr_dl *)&req.addr; sdl->sdl_alen = hwaddr_len; - ret = ioctl(af_link_sock, SIOCGLIFADDR, &req); - if (ret == -1) { - return errno; + + error = af_link_ioctl(SIOCGLIFADDR, &req); + if (error) { + return error; } if (!memcmp(&sdl->sdl_data[sdl->sdl_nlen], mac, hwaddr_len)) { return 0; @@ -1658,19 +1633,15 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, sdl->sdl_alen = hwaddr_len; sdl->sdl_family = hwaddr_family; memcpy(sdl->sdl_data, mac, hwaddr_len); - ret = ioctl(af_link_sock, SIOCALIFADDR, &req); - if (ret == -1) { - return errno; + error = af_link_ioctl(SIOCALIFADDR, &req); + if (error) { + return error; } memset(&req, 0, sizeof(req)); strncpy(req.iflr_name, netdev_name, sizeof(req.iflr_name)); req.addr = oldaddr; - ret = ioctl(af_link_sock, SIOCDLIFADDR, &req); - if (ret == -1) { - return errno; - } - return 0; + return af_link_ioctl(SIOCDLIFADDR, &req); #else #error not implemented #endif @@ -1694,3 +1665,25 @@ ifr_set_flags(struct ifreq *ifr, int flags) ifr->ifr_flagshigh = flags >> 16; #endif } + +/* 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) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + static int sock; + + if (ovsthread_once_start(&once)) { + sock = socket(AF_LINK, SOCK_DGRAM, 0); + if (sock < 0) { + sock = -errno; + VLOG_ERR("failed to create link socket: %s", ovs_strerror(errno)); + } + ovsthread_once_done(&once); + } + + return (sock < 0 ? -sock + : ioctl(sock, command, arg) == -1 ? errno + : 0); +}