mirror of
https://github.com/openvswitch/ovs
synced 2025-10-27 15:18:06 +00:00
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 <blp@nicira.com> CC: Ed Maste <emaste@freebsd.org>
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,7 +816,7 @@ 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,
|
||||
int error = af_inet_ifreq_ioctl(netdev_rx_get_name(rx_), &ifr,
|
||||
SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
|
||||
if (error) {
|
||||
return error;
|
||||
@@ -1019,7 +1001,7 @@ 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,
|
||||
error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr,
|
||||
SIOCGIFMTU, "SIOCGIFMTU");
|
||||
|
||||
netdev->netdev_mtu_error = error;
|
||||
@@ -1053,7 +1035,7 @@ 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,
|
||||
error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr,
|
||||
SIOCSIFMTU, "SIOCSIFMTU");
|
||||
if (!error || error == ENODEV) {
|
||||
netdev->netdev_mtu_error = error;
|
||||
@@ -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,10 +2173,9 @@ 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,
|
||||
make_in4_sockaddr(&ifr.ifr_addr, addr);
|
||||
return af_inet_ifreq_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr,
|
||||
ioctl_name);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user