From: Ben Pfaff Date: Sat, 10 Aug 2013 04:14:23 +0000 (-0700) Subject: netdev-linux, netdev-bsd: Make access to AF_INET socket thread-safe. X-Git-Tag: sliver-openvswitch-2.0.90-1~32^2 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=259e0b1ad1bfea762a76f0098deb8f8d8db1dfa3;p=sliver-openvswitch.git netdev-linux, netdev-bsd: Make access to AF_INET socket thread-safe. The only uses of 'af_inet_sock', in both drivers, were ioctls, so it seemed like a good abstraction to write a function that just does such an ioctl, and to factor out shared code into socket-util. Signed-off-by: Ben Pfaff CC: Ed Maste --- diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index 5c23d3810..b799cb589 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -107,9 +107,6 @@ enum { VALID_CARRIER = 1 << 5 }; -/* An AF_INET socket (used for ioctl operations). */ -static int af_inet_sock = -1; - #if defined(__NetBSD__) /* AF_LINK socket used for netdev_bsd_get_stats and set_etheraddr */ static int af_link_sock = -1; @@ -133,8 +130,6 @@ static int cache_notifier_refcount; static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); -static int netdev_bsd_do_ioctl(const char *, struct ifreq *, unsigned long cmd, - const char *cmd_name); static void destroy_tap(int fd, const char *name); static int get_flags(const struct netdev *, int *flagsp); static int set_flags(const char *, int flags); @@ -181,30 +176,23 @@ netdev_get_kernel_name(const struct netdev *netdev) static int netdev_bsd_init(void) { +#if defined(__NetBSD__) static int status = -1; if (status >= 0) { /* already initialized */ return status; } - af_inet_sock = socket(AF_INET, SOCK_DGRAM, 0); - status = af_inet_sock >= 0 ? 0 : errno; - if (status) { - VLOG_ERR("failed to create inet socket: %s", ovs_strerror(status)); - return status; - } - -#if defined(__NetBSD__) 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)); - close(af_inet_sock); - af_inet_sock = -1; } -#endif /* defined(__NetBSD__) */ return status; +#else + return 0; +#endif /* defined(__NetBSD__) */ } /* @@ -381,8 +369,8 @@ netdev_bsd_create_tap(const struct netdev_class *class, const char *name, /* Change the name of the tap device */ #if defined(SIOCSIFNAME) ifr.ifr_data = (void *)name; - if (ioctl(af_inet_sock, SIOCSIFNAME, &ifr) == -1) { - error = errno; + error = af_inet_ioctl(SIOCSIFNAME, &ifr); + if (error) { destroy_tap(netdev->tap_fd, ifr.ifr_name); goto error_unref_notifier; } @@ -405,8 +393,8 @@ netdev_bsd_create_tap(const struct netdev_class *class, const char *name, /* Turn device UP */ ifr_set_flags(&ifr, IFF_UP); strncpy(ifr.ifr_name, kernel_name, sizeof ifr.ifr_name); - if (ioctl(af_inet_sock, SIOCSIFFLAGS, &ifr) == -1) { - error = errno; + error = af_inet_ioctl(SIOCSIFFLAGS, &ifr); + if (error) { destroy_tap(netdev->tap_fd, kernel_name); goto error_unref_notifier; } @@ -815,7 +803,7 @@ netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup) struct ifreq ifr; int error; - error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev_), &ifr, + error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr, SIOCGIFMTU, "SIOCGIFMTU"); if (error) { return error; @@ -844,15 +832,17 @@ netdev_bsd_get_carrier(const struct netdev *netdev_, bool *carrier) 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); - if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { + error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr); + if (error) { VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", - netdev_get_name(netdev_), ovs_strerror(errno)); - return errno; + netdev_get_name(netdev_), ovs_strerror(error)); + return error; } netdev->carrier = (ifmr.ifm_status & IFM_ACTIVE) == IFM_ACTIVE; @@ -1057,10 +1047,11 @@ netdev_bsd_get_features(const struct netdev *netdev, /* We make two SIOCGIFMEDIA ioctl calls. The first to determine the * number of supported modes, and a second with a buffer to retrieve * them. */ - if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { + error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr); + if (error) { VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", - netdev_get_name(netdev), ovs_strerror(errno)); - return errno; + netdev_get_name(netdev), ovs_strerror(error)); + return error; } media_list = xcalloc(ifmr.ifm_count, sizeof(int)); @@ -1073,10 +1064,10 @@ netdev_bsd_get_features(const struct netdev *netdev, goto cleanup; } - if (ioctl(af_inet_sock, SIOCGIFMEDIA, &ifmr) == -1) { + error = af_inet_ioctl(SIOCGIFMEDIA, &ifmr); + if (error) { VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFMEDIA) failed: %s", - netdev_get_name(netdev), ovs_strerror(errno)); - error = errno; + netdev_get_name(netdev), ovs_strerror(error)); goto cleanup; } @@ -1117,7 +1108,7 @@ netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4, int error; ifr.ifr_addr.sa_family = AF_INET; - error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev_), &ifr, + error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr, SIOCGIFADDR, "SIOCGIFADDR"); if (error) { return error; @@ -1125,7 +1116,7 @@ netdev_bsd_get_in4(const struct netdev *netdev_, struct in_addr *in4, sin = (struct sockaddr_in *) &ifr.ifr_addr; netdev->in4 = sin->sin_addr; - error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev_), &ifr, + error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev_), &ifr, SIOCGIFNETMASK, "SIOCGIFNETMASK"); if (error) { return error; @@ -1348,7 +1339,7 @@ do_set_addr(struct netdev *netdev, { struct ifreq ifr; make_in4_sockaddr(&ifr.ifr_addr, addr); - return netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev), &ifr, ioctl_nr, + return af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev), &ifr, ioctl_nr, ioctl_name); } @@ -1534,7 +1525,7 @@ destroy_tap(int fd, const char *name) close(fd); strcpy(ifr.ifr_name, name); /* XXX What to do if this call fails? */ - ioctl(af_inet_sock, SIOCIFDESTROY, &ifr); + af_inet_ioctl(SIOCIFDESTROY, &ifr); } static int @@ -1543,7 +1534,7 @@ get_flags(const struct netdev *netdev, int *flags) struct ifreq ifr; int error; - error = netdev_bsd_do_ioctl(netdev_get_kernel_name(netdev), &ifr, + error = af_inet_ifreq_ioctl(netdev_get_kernel_name(netdev), &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); *flags = ifr_get_flags(&ifr); @@ -1558,7 +1549,7 @@ set_flags(const char *name, int flags) ifr_set_flags(&ifr, flags); - return netdev_bsd_do_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); + return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); } static int @@ -1616,16 +1607,18 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, { #if defined(__FreeBSD__) struct ifreq ifr; + int error; memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); ifr.ifr_addr.sa_family = hwaddr_family; ifr.ifr_addr.sa_len = hwaddr_len; memcpy(ifr.ifr_addr.sa_data, mac, hwaddr_len); - if (ioctl(af_inet_sock, SIOCSIFLLADDR, &ifr) < 0) { + error = af_inet_ioctl(SIOCSIFLLADDR, &ifr); + if (error) { VLOG_ERR("ioctl(SIOCSIFLLADDR) on %s device failed: %s", - netdev_name, ovs_strerror(errno)); - return errno; + netdev_name, ovs_strerror(error)); + return error; } return 0; #elif defined(__NetBSD__) @@ -1683,19 +1676,6 @@ set_etheraddr(const char *netdev_name OVS_UNUSED, int hwaddr_family OVS_UNUSED, #endif } -static int -netdev_bsd_do_ioctl(const char *name, struct ifreq *ifr, unsigned long cmd, - const char *cmd_name) -{ - strncpy(ifr->ifr_name, name, sizeof ifr->ifr_name); - if (ioctl(af_inet_sock, cmd, ifr) == -1) { - VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name, - ovs_strerror(errno)); - return errno; - } - return 0; -} - static int ifr_get_flags(const struct ifreq *ifr) { diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index c59f59090..930610067 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -400,19 +400,14 @@ struct netdev_rx_linux { static const struct netdev_rx_class netdev_rx_linux_class; -/* Sockets used for ioctl operations. */ -static int af_inet_sock = -1; /* AF_INET, SOCK_DGRAM. */ - /* This is set pretty low because we probably won't learn anything from the * additional log messages. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); -static int netdev_linux_init(void); +static void netdev_linux_run(void); static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *, int cmd, const char *cmd_name); -static int netdev_linux_do_ioctl(const char *name, struct ifreq *, int cmd, - const char *cmd_name); static int netdev_linux_get_ipv4(const struct netdev *, struct in_addr *, int cmd, const char *cmd_name); static int get_flags(const struct netdev *, unsigned int *flags); @@ -433,7 +428,7 @@ static void netdev_linux_miimon_wait(void); static bool is_netdev_linux_class(const struct netdev_class *netdev_class) { - return netdev_class->init == netdev_linux_init; + return netdev_class->run == netdev_linux_run; } static bool @@ -457,21 +452,6 @@ netdev_rx_linux_cast(const struct netdev_rx *rx) return CONTAINER_OF(rx, struct netdev_rx_linux, up); } -static int -netdev_linux_init(void) -{ - static int status = -1; - if (status < 0) { - /* Create AF_INET socket. */ - af_inet_sock = socket(AF_INET, SOCK_DGRAM, 0); - status = af_inet_sock >= 0 ? 0 : errno; - if (status) { - VLOG_ERR("failed to create inet socket: %s", ovs_strerror(status)); - } - } - return status; -} - static void netdev_linux_run(void) { @@ -721,13 +701,15 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) struct sockaddr_ll sll; int ifindex; /* Result of tcpdump -dd inbound */ - static struct sock_filter filt[] = { + static const struct sock_filter filt[] = { { 0x28, 0, 0, 0xfffff004 }, /* ldh [0] */ { 0x15, 0, 1, 0x00000004 }, /* jeq #4 jt 2 jf 3 */ { 0x6, 0, 0, 0x00000000 }, /* ret #0 */ { 0x6, 0, 0, 0x0000ffff } /* ret #65535 */ }; - static struct sock_fprog fprog = { ARRAY_SIZE(filt), filt }; + static const struct sock_fprog fprog = { + ARRAY_SIZE(filt), (struct sock_filter *) filt + }; /* Create file descriptor. */ fd = socket(PF_PACKET, SOCK_RAW, 0); @@ -766,7 +748,7 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp) sizeof fprog); if (error) { error = errno; - VLOG_ERR("%s: failed attach filter (%s)", + VLOG_ERR("%s: failed to attach filter (%s)", netdev_get_name(netdev_), ovs_strerror(error)); goto error; } @@ -834,8 +816,8 @@ netdev_rx_linux_drain(struct netdev_rx *rx_) struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); if (rx->is_tap) { struct ifreq ifr; - int error = netdev_linux_do_ioctl(netdev_rx_get_name(rx_), &ifr, - SIOCGIFTXQLEN, "SIOCGIFTXQLEN"); + int error = af_inet_ifreq_ioctl(netdev_rx_get_name(rx_), &ifr, + SIOCGIFTXQLEN, "SIOCGIFTXQLEN"); if (error) { return error; } @@ -1019,8 +1001,8 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup) struct ifreq ifr; int error; - error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr, - SIOCGIFMTU, "SIOCGIFMTU"); + error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr, + SIOCGIFMTU, "SIOCGIFMTU"); netdev->netdev_mtu_error = error; netdev->mtu = ifr.ifr_mtu; @@ -1053,8 +1035,8 @@ netdev_linux_set_mtu(const struct netdev *netdev_, int mtu) netdev->cache_valid &= ~VALID_MTU; } ifr.ifr_mtu = mtu; - error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr, - SIOCSIFMTU, "SIOCSIFMTU"); + error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr, + SIOCSIFMTU, "SIOCSIFMTU"); if (!error || error == ENODEV) { netdev->netdev_mtu_error = error; netdev->mtu = ifr.ifr_mtu; @@ -1103,7 +1085,7 @@ netdev_linux_do_miimon(const char *name, int cmd, const char *cmd_name, memset(&ifr, 0, sizeof ifr); memcpy(&ifr.ifr_data, data, sizeof *data); - error = netdev_linux_do_ioctl(name, &ifr, cmd, cmd_name); + error = af_inet_ifreq_ioctl(name, &ifr, cmd, cmd_name); memcpy(data, &ifr.ifr_data, sizeof *data); return error; @@ -2191,11 +2173,10 @@ do_set_addr(struct netdev *netdev, int ioctl_nr, const char *ioctl_name, struct in_addr addr) { struct ifreq ifr; - ovs_strzcpy(ifr.ifr_name, netdev_get_name(netdev), sizeof ifr.ifr_name); - make_in4_sockaddr(&ifr.ifr_addr, addr); - return netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr, - ioctl_name); + make_in4_sockaddr(&ifr.ifr_addr, addr); + return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr, + ioctl_name); } /* Adds 'router' as a default IP gateway. */ @@ -2211,7 +2192,7 @@ netdev_linux_add_router(struct netdev *netdev OVS_UNUSED, struct in_addr router) make_in4_sockaddr(&rt.rt_gateway, router); make_in4_sockaddr(&rt.rt_genmask, any); rt.rt_flags = RTF_UP | RTF_GATEWAY; - error = ioctl(af_inet_sock, SIOCADDRT, &rt) < 0 ? errno : 0; + error = af_inet_ioctl(SIOCADDRT, &rt); if (error) { VLOG_WARN("ioctl(SIOCADDRT): %s", ovs_strerror(error)); } @@ -2337,7 +2318,7 @@ netdev_linux_arp_lookup(const struct netdev *netdev, r.arp_flags = 0; ovs_strzcpy(r.arp_dev, netdev_get_name(netdev), sizeof r.arp_dev); COVERAGE_INC(netdev_arp_lookup); - retval = ioctl(af_inet_sock, SIOCGARP, &r) < 0 ? errno : 0; + retval = af_inet_ioctl(SIOCGARP, &r); if (!retval) { memcpy(mac, r.arp_ha.sa_data, ETH_ADDR_LEN); } else if (retval != ENXIO) { @@ -2403,7 +2384,7 @@ netdev_linux_change_seq(const struct netdev *netdev) { \ NAME, \ \ - netdev_linux_init, \ + NULL, \ netdev_linux_run, \ netdev_linux_wait, \ \ @@ -4193,14 +4174,6 @@ tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes) /* Linux-only functions declared in netdev-linux.h */ -/* Returns a fd for an AF_INET socket or a negative errno value. */ -int -netdev_linux_get_af_inet_sock(void) -{ - int error = netdev_linux_init(); - return error ? -error : af_inet_sock; -} - /* Modifies the 'flag' bit in ethtool's flags field for 'netdev'. If * 'enable' is true, the bit is set. Otherwise, it is cleared. */ int @@ -4393,8 +4366,7 @@ get_flags(const struct netdev *dev, unsigned int *flags) int error; *flags = 0; - error = netdev_linux_do_ioctl(dev->name, &ifr, SIOCGIFFLAGS, - "SIOCGIFFLAGS"); + error = af_inet_ifreq_ioctl(dev->name, &ifr, SIOCGIFFLAGS, "SIOCGIFFLAGS"); if (!error) { *flags = ifr.ifr_flags; } @@ -4407,20 +4379,23 @@ set_flags(const char *name, unsigned int flags) struct ifreq ifr; ifr.ifr_flags = flags; - return netdev_linux_do_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); + return af_inet_ifreq_ioctl(name, &ifr, SIOCSIFFLAGS, "SIOCSIFFLAGS"); } static int do_get_ifindex(const char *netdev_name) { struct ifreq ifr; + int error; ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); COVERAGE_INC(netdev_get_ifindex); - if (ioctl(af_inet_sock, SIOCGIFINDEX, &ifr) < 0) { + + error = af_inet_ioctl(SIOCGIFINDEX, &ifr); + if (error) { VLOG_WARN_RL(&rl, "ioctl(SIOCGIFINDEX) on %s device failed: %s", - netdev_name, ovs_strerror(errno)); - return -errno; + netdev_name, ovs_strerror(error)); + return -error; } return ifr.ifr_ifindex; } @@ -4452,18 +4427,20 @@ get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]) { struct ifreq ifr; int hwaddr_family; + int error; memset(&ifr, 0, sizeof ifr); ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); COVERAGE_INC(netdev_get_hwaddr); - if (ioctl(af_inet_sock, SIOCGIFHWADDR, &ifr) < 0) { + error = af_inet_ioctl(SIOCGIFHWADDR, &ifr); + if (error) { /* ENODEV probably means that a vif disappeared asynchronously and * hasn't been removed from the database yet, so reduce the log level * to INFO for that case. */ - VLOG(errno == ENODEV ? VLL_INFO : VLL_ERR, + VLOG(error == ENODEV ? VLL_INFO : VLL_ERR, "ioctl(SIOCGIFHWADDR) on %s device failed: %s", - netdev_name, ovs_strerror(errno)); - return errno; + netdev_name, ovs_strerror(error)); + return error; } hwaddr_family = ifr.ifr_hwaddr.sa_family; if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) { @@ -4479,18 +4456,19 @@ set_etheraddr(const char *netdev_name, const uint8_t mac[ETH_ADDR_LEN]) { struct ifreq ifr; + int error; memset(&ifr, 0, sizeof ifr); ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ADDR_LEN); COVERAGE_INC(netdev_set_hwaddr); - if (ioctl(af_inet_sock, SIOCSIFHWADDR, &ifr) < 0) { + error = af_inet_ioctl(SIOCSIFHWADDR, &ifr); + if (error) { VLOG_ERR("ioctl(SIOCSIFHWADDR) on %s device failed: %s", - netdev_name, ovs_strerror(errno)); - return errno; + netdev_name, ovs_strerror(error)); } - return 0; + return error; } static int @@ -4498,37 +4476,24 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd, int cmd, const char *cmd_name) { struct ifreq ifr; + int error; memset(&ifr, 0, sizeof ifr); ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); ifr.ifr_data = (caddr_t) ecmd; ecmd->cmd = cmd; - if (ioctl(af_inet_sock, SIOCETHTOOL, &ifr) == 0) { - return 0; - } else { - if (errno != EOPNOTSUPP) { + error = af_inet_ioctl(SIOCETHTOOL, &ifr); + if (error) { + if (error != EOPNOTSUPP) { VLOG_WARN_RL(&rl, "ethtool command %s on network device %s " - "failed: %s", cmd_name, name, ovs_strerror(errno)); + "failed: %s", cmd_name, name, ovs_strerror(error)); } else { /* The device doesn't support this operation. That's pretty * common, so there's no point in logging anything. */ } - return errno; - } -} - -static int -netdev_linux_do_ioctl(const char *name, struct ifreq *ifr, int cmd, - const char *cmd_name) -{ - ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name); - if (ioctl(af_inet_sock, cmd, ifr) == -1) { - VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name, - ovs_strerror(errno)); - return errno; } - return 0; + return error; } static int @@ -4539,7 +4504,7 @@ netdev_linux_get_ipv4(const struct netdev *netdev, struct in_addr *ip, int error; ifr.ifr_addr.sa_family = AF_INET; - error = netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, cmd, cmd_name); + error = af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, cmd, cmd_name); if (!error) { const struct sockaddr_in *sin = ALIGNED_CAST(struct sockaddr_in *, &ifr.ifr_addr); diff --git a/lib/netdev-linux.h b/lib/netdev-linux.h index 7874dd6c3..0c61bc907 100644 --- a/lib/netdev-linux.h +++ b/lib/netdev-linux.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Nicira, Inc. + * Copyright (c) 2011, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,5 @@ struct netdev; int netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag, const char *flag_name, bool enable); -int netdev_linux_get_af_inet_sock(void); #endif /* netdev-linux.h */ diff --git a/lib/socket-util.c b/lib/socket-util.c index 1d0cede88..7f34ea2e9 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1353,3 +1354,42 @@ error: *n_fdsp = 0; return EPROTO; } + +/* Calls ioctl() on an AF_INET sock, passing the specified 'command' and + * 'arg'. Returns 0 if successful, otherwise a positive errno value. */ +int +af_inet_ioctl(unsigned long int command, const void *arg) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + static int sock; + + if (ovsthread_once_start(&once)) { + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + sock = -errno; + VLOG_ERR("failed to create inet socket: %s", ovs_strerror(errno)); + } + ovsthread_once_done(&once); + } + + return (sock < 0 ? -sock + : ioctl(sock, command, arg) == -1 ? errno + : 0); +} + +int +af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd, + const char *cmd_name) +{ + int error; + + ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name); + error = af_inet_ioctl(cmd, ifr); + if (error) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name, + ovs_strerror(error)); + } + return error; +} + diff --git a/lib/socket-util.h b/lib/socket-util.h index 96aad5d16..670eeb343 100644 --- a/lib/socket-util.h +++ b/lib/socket-util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,4 +97,10 @@ int recv_data_and_fds(int sock, void *data, size_t size, int fds[SOUTIL_MAX_FDS], size_t *n_fdsp); +/* Helpers for calling ioctl() on an AF_INET socket. */ +struct ifreq; +int af_inet_ioctl(unsigned long int command, const void *arg); +int af_inet_ifreq_ioctl(const char *name, struct ifreq *, + unsigned long int cmd, const char *cmd_name); + #endif /* socket-util.h */ diff --git a/lib/vlandev.c b/lib/vlandev.c index 5f58f1055..282d28ca3 100644 --- a/lib/vlandev.c +++ b/lib/vlandev.c @@ -26,6 +26,7 @@ #include "dummy.h" #include "hash.h" #include "shash.h" +#include "socket-util.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(vlandev); @@ -237,17 +238,11 @@ do_vlan_ioctl(const char *netdev_name, struct vlan_ioctl_args *via, { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); int error; - int sock; via->cmd = cmd; ovs_strlcpy(via->device1, netdev_name, sizeof via->device1); - sock = netdev_linux_get_af_inet_sock(); - if (sock < 0) { - return -sock; - } - - error = ioctl(sock, SIOCSIFVLAN, via) < 0 ? errno : 0; + error = af_inet_ioctl(SIOCSIFVLAN, via); if (error) { VLOG_WARN_RL(&rl, "%s: VLAN ioctl %s failed (%s)", netdev_name, cmd_name, ovs_strerror(error));