* network device. */
/* Cached network device information. */
- int ifindex;
+ int ifindex; /* -1 if not known. */
uint8_t etheraddr[ETH_ADDR_LEN];
struct in6_addr in6;
int speed;
static int restore_flags(struct netdev *netdev);
static int get_flags(const char *netdev_name, int *flagsp);
static int set_flags(const char *netdev_name, int flags);
+static int do_get_ifindex(const char *netdev_name);
+static int get_ifindex(const struct netdev *, int *ifindexp);
+static int get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN],
+ int *hwaddr_familyp);
/* Obtains the IPv6 address for 'name' into 'in6'. */
static void
int netdev_fd;
struct sockaddr_ll sll;
struct ifreq ifr;
- unsigned int ifindex;
+ int ifindex = -1;
uint8_t etheraddr[ETH_ADDR_LEN];
struct in6_addr in6;
int mtu;
return errno;
}
- /* Set non-blocking mode. */
- error = set_nonblocking(netdev_fd);
- if (error) {
- goto error_already_set;
- }
+ if (ethertype != NETDEV_ETH_TYPE_NONE) {
+ /* Set non-blocking mode. */
+ error = set_nonblocking(netdev_fd);
+ if (error) {
+ goto error_already_set;
+ }
- /* Get ethernet device index. */
- strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
- if (ioctl(netdev_fd, SIOCGIFINDEX, &ifr) < 0) {
- VLOG_ERR("ioctl(SIOCGIFINDEX) on %s device failed: %s",
- name, strerror(errno));
- goto error;
- }
- ifindex = ifr.ifr_ifindex;
-
- /* Bind to specific ethernet device. */
- memset(&sll, 0, sizeof sll);
- sll.sll_family = AF_PACKET;
- sll.sll_ifindex = ifindex;
- if (bind(netdev_fd, (struct sockaddr *) &sll, sizeof sll) < 0) {
- VLOG_ERR("bind to %s failed: %s", name, strerror(errno));
- goto error;
- }
+ /* Get ethernet device index. */
+ ifindex = do_get_ifindex(name);
+ if (ifindex < 0) {
+ return -ifindex;
+ }
+
+ /* Bind to specific ethernet device. */
+ memset(&sll, 0, sizeof sll);
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = ifindex;
+ if (bind(netdev_fd, (struct sockaddr *) &sll, sizeof sll) < 0) {
+ VLOG_ERR("bind to %s failed: %s", name, strerror(errno));
+ goto error;
+ }
- if (ethertype != NETDEV_ETH_TYPE_NONE) {
/* Between the socket() and bind() calls above, the socket receives all
* packets of the requested type on all system interfaces. We do not
* want to receive that data, but there is no way to avoid it. So we
* must now drain out the receive queue. */
error = drain_rcvbuf(netdev_fd);
if (error) {
- goto error;
+ goto error_already_set;
}
}
/* Get MAC address. */
- if (ioctl(netdev_fd, SIOCGIFHWADDR, &ifr) < 0) {
- VLOG_ERR("ioctl(SIOCGIFHWADDR) on %s device failed: %s",
- name, strerror(errno));
- goto error;
- }
- hwaddr_family = ifr.ifr_hwaddr.sa_family;
- if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
- VLOG_WARN("%s device has unknown hardware address family %d",
- name, hwaddr_family);
+ error = get_etheraddr(name, etheraddr, &hwaddr_family);
+ if (error) {
+ goto error_already_set;
}
- memcpy(etheraddr, ifr.ifr_hwaddr.sa_data, sizeof etheraddr);
/* Get MTU. */
+ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
if (ioctl(netdev_fd, SIOCGIFMTU, &ifr) < 0) {
VLOG_ERR("ioctl(SIOCGIFMTU) on %s device failed: %s",
name, strerror(errno));
struct ifinfomsg *ifi;
const struct rtnl_link_stats *rtnl_stats;
struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)];
+ int ifindex;
int error;
+ error = get_ifindex(netdev, &ifindex);
+ if (error) {
+ goto error;
+ }
+
ofpbuf_init(&request, 0);
nl_msg_put_nlmsghdr(&request, rtnl_sock, sizeof *ifi,
RTM_GETLINK, NLM_F_REQUEST);
ifi = ofpbuf_put_zeros(&request, sizeof *ifi);
ifi->ifi_family = PF_UNSPEC;
- ifi->ifi_index = netdev->ifindex;
+ ifi->ifi_index = ifindex;
error = nl_sock_transact(rtnl_sock, &request, &reply);
ofpbuf_uninit(&request);
if (error) {
}
return 0;
}
+
+static int
+do_get_ifindex(const char *netdev_name)
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
+ if (ioctl(af_inet_sock, SIOCGIFINDEX, &ifr) < 0) {
+ VLOG_WARN_RL(&rl, "ioctl(SIOCGIFINDEX) on %s device failed: %s",
+ netdev_name, strerror(errno));
+ return -errno;
+ }
+ return ifr.ifr_ifindex;
+}
+
+static int
+get_ifindex(const struct netdev *netdev, int *ifindexp)
+{
+ *ifindexp = 0;
+ if (netdev->ifindex < 0) {
+ int ifindex = do_get_ifindex(netdev->name);
+ if (ifindex < 0) {
+ return -ifindex;
+ }
+ ((struct netdev *) netdev)->ifindex = ifindex;
+ }
+ *ifindexp = netdev->ifindex;
+ return 0;
+}
+
+static int
+get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN],
+ int *hwaddr_familyp)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof ifr);
+ strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
+ if (ioctl(af_inet_sock, SIOCGIFHWADDR, &ifr) < 0) {
+ VLOG_ERR("ioctl(SIOCGIFHWADDR) on %s device failed: %s",
+ netdev_name, strerror(errno));
+ return errno;
+ }
+ if (hwaddr_familyp) {
+ int hwaddr_family = ifr.ifr_hwaddr.sa_family;
+ *hwaddr_familyp = hwaddr_family;
+ if (hwaddr_family != AF_UNSPEC && hwaddr_family != ARPHRD_ETHER) {
+ VLOG_WARN("%s device has unknown hardware address family %d",
+ netdev_name, hwaddr_family);
+ }
+ }
+ memcpy(ea, ifr.ifr_hwaddr.sa_data, ETH_ADDR_LEN);
+
+ return 0;
+}