From 44445cac40bec2b2f12e8baf7bbb7fcf32fcbb42 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Fri, 9 Mar 2012 12:58:10 -0800 Subject: [PATCH] netdev-linux: Cache error code from ether-addr ioctl. Signed-off-by: Pravin B Shelar --- lib/netdev-linux.c | 52 +++++++++++++++++++++++++++++--------------- lib/rtnetlink-link.c | 7 ++++++ lib/rtnetlink-link.h | 3 +++ 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 7c510acf4..5be51c8dc 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -377,6 +377,7 @@ struct netdev_dev_linux { int vport_stats_error; /* Cached error code from vport_get_stats(). 0 or an errno value. */ int netdev_mtu_error; /* Cached error code from SIOCGIFMTU or SIOCSIFMTU. */ + int ether_addr_error; /* Cached error code from set/get etheraddr. */ struct ethtool_drvinfo drvinfo; /* Cached from ETHTOOL_GDRVINFO. */ struct tc *tc; @@ -417,8 +418,7 @@ static int do_set_addr(struct netdev *netdev, int 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, - const uint8_t[ETH_ADDR_LEN]); +static int set_etheraddr(const char *netdev_name, const uint8_t[ETH_ADDR_LEN]); static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats); static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats); static int af_packet_sock(void); @@ -541,6 +541,12 @@ netdev_dev_linux_update(struct netdev_dev_linux *dev, dev->netdev_mtu_error = 0; } + if (!eth_addr_is_zero(change->addr)) { + memcpy(dev->etheraddr, change->addr, ETH_ADDR_LEN); + dev->cache_valid |= VALID_ETHERADDR; + dev->ether_addr_error = 0; + } + } else { netdev_dev_linux_changed(dev, change->ifi_flags, 0); } @@ -1008,37 +1014,49 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, netdev_dev_linux_cast(netdev_get_dev(netdev_)); int error; - if (!(netdev_dev->cache_valid & VALID_ETHERADDR) - || !eth_addr_equals(netdev_dev->etheraddr, mac)) { - error = set_etheraddr(netdev_get_name(netdev_), ARPHRD_ETHER, mac); + if (netdev_dev->cache_valid & VALID_ETHERADDR) { + if (netdev_dev->ether_addr_error) { + return netdev_dev->ether_addr_error; + } + if (eth_addr_equals(netdev_dev->etheraddr, mac)) { + return 0; + } + netdev_dev->cache_valid &= ~VALID_ETHERADDR; + } + + error = set_etheraddr(netdev_get_name(netdev_), mac); + if (!error || error == ENODEV) { + netdev_dev->ether_addr_error = error; + netdev_dev->cache_valid |= VALID_ETHERADDR; if (!error) { - netdev_dev->cache_valid |= VALID_ETHERADDR; memcpy(netdev_dev->etheraddr, mac, ETH_ADDR_LEN); } - } else { - error = 0; } + return error; } -/* Returns a pointer to 'netdev''s MAC address. The caller must not modify or - * free the returned buffer. */ +/* Copies 'netdev''s MAC address to 'mac' which is passed as param. */ static int netdev_linux_get_etheraddr(const struct netdev *netdev_, uint8_t mac[ETH_ADDR_LEN]) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev_)); + if (!(netdev_dev->cache_valid & VALID_ETHERADDR)) { int error = get_etheraddr(netdev_get_name(netdev_), netdev_dev->etheraddr); - if (error) { - return error; - } + + netdev_dev->ether_addr_error = error; netdev_dev->cache_valid |= VALID_ETHERADDR; } - memcpy(mac, netdev_dev->etheraddr, ETH_ADDR_LEN); - return 0; + + if (!netdev_dev->ether_addr_error) { + memcpy(mac, netdev_dev->etheraddr, ETH_ADDR_LEN); + } + + return netdev_dev->ether_addr_error; } /* Returns the maximum size of transmitted (and received) packets on 'netdev', @@ -4385,14 +4403,14 @@ get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]) } static int -set_etheraddr(const char *netdev_name, int hwaddr_family, +set_etheraddr(const char *netdev_name, const uint8_t mac[ETH_ADDR_LEN]) { struct ifreq ifr; memset(&ifr, 0, sizeof ifr); ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); - ifr.ifr_hwaddr.sa_family = hwaddr_family; + 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) { diff --git a/lib/rtnetlink-link.c b/lib/rtnetlink-link.c index d14f0e3c4..07350a6c5 100644 --- a/lib/rtnetlink-link.c +++ b/lib/rtnetlink-link.c @@ -46,6 +46,7 @@ rtnetlink_link_parse(struct ofpbuf *buf, [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false }, [IFLA_MASTER] = { .type = NL_A_U32, .optional = true }, [IFLA_MTU] = { .type = NL_A_U32, .optional = true }, + [IFLA_ADDRESS] = { .type = NL_A_UNSPEC, .optional = true }, }; static struct nlattr *attrs[ARRAY_SIZE(policy)]; @@ -72,6 +73,12 @@ rtnetlink_link_parse(struct ofpbuf *buf, ? nl_attr_get_u32(attrs[IFLA_MTU]) : 0); + if (attrs[IFLA_ADDRESS] && + nl_attr_get_size(attrs[IFLA_ADDRESS]) == ETH_ALEN) { + memcpy(change->addr, nl_attr_get(attrs[IFLA_ADDRESS]), ETH_ALEN); + } else { + memset(change->addr, 0, ETH_ALEN); + } } return parsed; diff --git a/lib/rtnetlink-link.h b/lib/rtnetlink-link.h index cfdb24ba9..7c64c94da 100644 --- a/lib/rtnetlink-link.h +++ b/lib/rtnetlink-link.h @@ -18,6 +18,8 @@ #define RTNETLINK_LINK_H 1 #include +#include +#include struct ofpbuf; struct nln_notifier; @@ -38,6 +40,7 @@ struct rtnetlink_link_change { const char *ifname; /* Name of network device. */ int master_ifindex; /* Ifindex of datapath master (0 if none). */ int mtu; /* Current MTU. */ + uint8_t addr[ETH_ALEN]; unsigned int ifi_flags; /* Flags of network device. */ }; -- 2.20.1