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;
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);
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);
}
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',
}
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) {
[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)];
? 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;