/* Setup device to be added to the HSR bridge. */ static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port) { int res; dev_hold(dev); res = dev_set_promiscuity(dev, 1); if (res) goto fail_promiscuity; /* FIXME: * What does net device "adjacency" mean? Should we do * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ? */ res = netdev_rx_handler_register(dev, hsr_handle_frame, port); if (res) goto fail_rx_handler; dev_disable_lro(dev); return 0; fail_rx_handler: dev_set_promiscuity(dev, -1); fail_promiscuity: dev_put(dev); return res; }
static int dsa_slave_open(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = p->parent->dst->master_netdev; struct dsa_switch *ds = p->parent; u8 stp_state = dsa_port_is_bridged(p) ? BR_STATE_BLOCKING : BR_STATE_FORWARDING; int err; if (!(master->flags & IFF_UP)) return -ENETDOWN; if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { err = dev_uc_add(master, dev->dev_addr); if (err < 0) goto out; } if (dev->flags & IFF_ALLMULTI) { err = dev_set_allmulti(master, 1); if (err < 0) goto del_unicast; } if (dev->flags & IFF_PROMISC) { err = dev_set_promiscuity(master, 1); if (err < 0) goto clear_allmulti; } if (ds->drv->port_enable) { err = ds->drv->port_enable(ds, p->port, p->phy); if (err) goto clear_promisc; } if (ds->drv->port_stp_update) ds->drv->port_stp_update(ds, p->port, stp_state); if (p->phy) phy_start(p->phy); return 0; clear_promisc: if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); del_unicast: if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) dev_uc_del(master, dev->dev_addr); out: return err; }
int br_add_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; if (dev->br_port != NULL) return -EBUSY; if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) return -EINVAL; dev_hold(dev); write_lock_bh(&br->lock); if ((p = new_nbp(br, dev)) == NULL) { write_unlock_bh(&br->lock); dev_put(dev); return -EXFULL; } dev_set_promiscuity(dev, 1); br_stp_recalculate_bridge_id(br); br_fdb_insert(br, p, dev->dev_addr, 1); if ((br->dev.flags & IFF_UP) && (dev->flags & IFF_UP)) br_stp_enable_port(p); write_unlock_bh(&br->lock); return 0; }
/* called under bridge lock */ static int __br_del_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; struct net_bridge_port **pptr; if ((p = dev->br_port) == NULL) return -EINVAL; br_stp_disable_port(p); dev_set_promiscuity(dev, -1); dev->br_port = NULL; pptr = &br->port_list; while (*pptr != NULL) { if (*pptr == p) { *pptr = p->next; break; } pptr = &((*pptr)->next); } br_fdb_delete_by_port(br, p); kfree(p); dev_put(dev); return 0; }
static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); #ifdef HAVE_RHEL_OVS_HOOK rcu_assign_pointer(netdev_vport->dev->ax25_ptr, vport); atomic_inc(&nr_bridges); rcu_assign_pointer(openvswitch_handle_frame_hook, netdev_frame_hook); #else err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_unlock; #endif dev_set_promiscuity(netdev_vport->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) dev_disable_lro(netdev_vport->dev); #endif netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); return vport; #ifndef HAVE_RHEL_OVS_HOOK error_unlock: #endif rtnl_unlock(); error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
void hsr_del_port(struct hsr_port *port) { struct hsr_priv *hsr; struct hsr_port *master; hsr = port->hsr; master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); list_del_rcu(&port->port_list); if (port != master) { if (master != NULL) { netdev_update_features(master->dev); dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); } netdev_rx_handler_unregister(port->dev); dev_set_promiscuity(port->dev, -1); } /* FIXME? * netdev_upper_dev_unlink(port->dev, port->hsr->dev); */ synchronize_rcu(); if (port != master) dev_put(port->dev); }
static int dsa_slave_close(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = p->parent->dst->master_netdev; struct dsa_switch *ds = p->parent; if (p->phy) phy_stop(p->phy); dev_mc_unsync(master, dev); dev_uc_unsync(master, dev); if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) dev_uc_del(master, dev->dev_addr); if (ds->drv->port_disable) ds->drv->port_disable(ds, p->port, p->phy); if (ds->drv->port_stp_update) ds->drv->port_stp_update(ds, p->port, BR_STATE_DISABLED); return 0; }
static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); err = netdev_master_upper_dev_link(netdev_vport->dev, get_dpdev(vport->dp)); if (err) goto error_unlock; err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_master_upper_dev_unlink; dev_set_promiscuity(netdev_vport->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) dev_disable_lro(netdev_vport->dev); #endif netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); netdev_init(); return vport; error_master_upper_dev_unlink: netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp)); error_unlock: rtnl_unlock(); error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
void ovs_netdev_detach_dev(struct vport *vport) { ASSERT_RTNL(); vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(vport->dev); netdev_upper_dev_unlink(vport->dev, netdev_master_upper_dev_get(vport->dev)); dev_set_promiscuity(vport->dev, -1); }
static void vlan_dev_change_rx_flags(struct net_device *dev, int change) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; if (change & IFF_ALLMULTI) dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); if (change & IFF_PROMISC) dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); }
static struct vport *internal_dev_create(const struct vport_parms *parms) { struct vport *vport; struct internal_dev *internal_dev; int err; vport = ovs_vport_alloc(0, &ovs_internal_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } vport->dev = alloc_netdev(sizeof(struct internal_dev), parms->name, NET_NAME_USER, do_setup); if (!vport->dev) { err = -ENOMEM; goto error_free_vport; } vport->dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!vport->dev->tstats) { err = -ENOMEM; goto error_free_netdev; } #ifdef HAVE_IFF_PHONY_HEADROOM vport->dev->needed_headroom = vport->dp->max_headroom; #endif dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); internal_dev = internal_dev_priv(vport->dev); internal_dev->vport = vport; /* Restrict bridge port to current netns. */ if (vport->port_no == OVSP_LOCAL) vport->dev->features |= NETIF_F_NETNS_LOCAL; rtnl_lock(); err = register_netdevice(vport->dev); if (err) goto error_unlock; dev_set_promiscuity(vport->dev, 1); rtnl_unlock(); netif_start_queue(vport->dev); return vport; error_unlock: rtnl_unlock(); free_percpu(vport->dev->tstats); error_free_netdev: free_netdev(vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static int netdev_detach(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(netdev_vport->dev); dev_set_promiscuity(netdev_vport->dev, -1); return 0; }
static void netdev_destroy(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(netdev_vport->dev); dev_set_promiscuity(netdev_vport->dev, -1); call_rcu(&netdev_vport->rcu, free_port_rcu); }
static void internal_dev_destroy(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); netif_stop_queue(netdev_vport->dev); dev_set_promiscuity(netdev_vport->dev, -1); /* unregister_netdevice() waits for an RCU grace period. */ unregister_netdevice(netdev_vport->dev); }
static void internal_dev_destroy(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); netif_stop_queue(netdev_vport->dev); dev_set_promiscuity(netdev_vport->dev, -1); unregister_netdevice(netdev_vport->dev); }
static void dsa_slave_change_rx_flags(struct net_device *dev, int change) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = p->parent->dst->master_netdev; if (change & IFF_ALLMULTI) dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); if (change & IFF_PROMISC) dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1); }
static void internal_dev_destroy(struct vport *vport) { netif_stop_queue(vport->dev); rtnl_lock(); dev_set_promiscuity(vport->dev, -1); /* unregister_netdevice() waits for an RCU grace period. */ unregister_netdevice(vport->dev); free_percpu(vport->dev->tstats); rtnl_unlock(); }
static void netdev_destroy(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(netdev_vport->dev); dev_set_promiscuity(netdev_vport->dev, -1); synchronize_rcu(); dev_put(netdev_vport->dev); ovs_vport_free(vport); }
static int vlan_dev_open(struct net_device *dev) { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); struct net_device *real_dev = vlan->real_dev; int err; if (!(real_dev->flags & IFF_UP) && !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) return -ENETDOWN; if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) && !vlan_dev_inherit_address(dev, real_dev)) { err = dev_uc_add(real_dev, dev->dev_addr); if (err < 0) goto out; } if (dev->flags & IFF_ALLMULTI) { err = dev_set_allmulti(real_dev, 1); if (err < 0) goto del_unicast; } if (dev->flags & IFF_PROMISC) { err = dev_set_promiscuity(real_dev, 1); if (err < 0) goto clear_allmulti; } ether_addr_copy(vlan->real_dev_addr, real_dev->dev_addr); if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); if (vlan->flags & VLAN_FLAG_MVRP) vlan_mvrp_request_join(dev); if (netif_carrier_ok(real_dev) && !(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) netif_carrier_on(dev); return 0; clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); del_unicast: if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr)) dev_uc_del(real_dev, dev->dev_addr); out: netif_carrier_off(dev); return err; }
/* * 重要!通过相应的参数进行网络设备的注册 * 何时调用? */ static struct vport *netdev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; // 看vport_netdev.h中的定义 int err; //根据具体的ovs_netdev_vport_ops和参数构造一个vport // 第一个参数代表私有数据的大小,这里正是要放struct netdev_vport vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_netdev_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); if (!netdev_vport->dev) { err = -ENODEV; goto error_free_vport; } if (netdev_vport->dev->flags & IFF_LOOPBACK || netdev_vport->dev->type != ARPHRD_ETHER || ovs_is_internal_dev(netdev_vport->dev)) { err = -EINVAL; goto error_put; } /* 重要!就是设置net_device两个字段 netdev_rx_handler_register - register receive handler * @dev: device to register a handler for * @rx_handler: receive handler to register * @rx_handler_data: data pointer that is used by rx handler */ err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) goto error_put; dev_set_promiscuity(netdev_vport->dev, 1); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) dev_disable_lro(netdev_vport->dev); #endif netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; return vport; error_put: dev_put(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
static struct vport *internal_dev_create(const struct vport_parms *parms) { struct vport *vport; struct netdev_vport *netdev_vport; struct internal_dev *internal_dev; int err; vport = ovs_vport_alloc(sizeof(struct netdev_vport), &ovs_internal_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } netdev_vport = netdev_vport_priv(vport); netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), parms->name, NET_NAME_UNKNOWN, do_setup); if (!netdev_vport->dev) { err = -ENOMEM; goto error_free_vport; } dev_net_set(netdev_vport->dev, ovs_dp_get_net(vport->dp)); internal_dev = internal_dev_priv(netdev_vport->dev); internal_dev->vport = vport; /* Restrict bridge port to current netns. */ if (vport->port_no == OVSP_LOCAL) netdev_vport->dev->features |= NETIF_F_NETNS_LOCAL; rtnl_lock(); err = register_netdevice(netdev_vport->dev); if (err) goto error_free_netdev; dev_set_promiscuity(netdev_vport->dev, 1); rtnl_unlock(); netif_start_queue(netdev_vport->dev); return vport; error_free_netdev: rtnl_unlock(); free_netdev(netdev_vport->dev); error_free_vport: ovs_vport_free(vport); error: return ERR_PTR(err); }
/* teach the switch the mac of a disabled slave * on the primary for fault tolerance * * Caller must hold bond->ptrlock for write or bond lock for write */ static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) { if (!bond->current_slave) { return; } if (!bond->alb_info.primary_is_promisc) { bond->alb_info.primary_is_promisc = 1; dev_set_promiscuity(bond->current_slave->dev, 1); } bond->alb_info.rlb_promisc_timeout_counter = 0; alb_send_learning_packets(bond->current_slave, addr); }
static void netdev_destroy(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); netdev_exit(); rtnl_lock(); netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; netdev_rx_handler_unregister(netdev_vport->dev); netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp)); dev_set_promiscuity(netdev_vport->dev, -1); rtnl_unlock(); call_rcu(&netdev_vport->rcu, free_port_rcu); }
int vlan_dev_stop(struct net_device *dev) { struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; dev_mc_unsync(real_dev, dev); if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); if (dev->flags & IFF_PROMISC) dev_set_promiscuity(real_dev, -1); if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len); return 0; }
/** * bond_alb_assign_current_slave - assign new current_slave * @bond: our bonding struct * @new_slave: new slave to assign * * Set the bond->current_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * * Caller must hold bond ptrlock for write (or bond lock for write) */ void bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) { struct slave *swap_slave = bond->current_slave; if (bond->current_slave == new_slave) { return; } if (bond->current_slave && bond->alb_info.primary_is_promisc) { dev_set_promiscuity(bond->current_slave->dev, -1); bond->alb_info.primary_is_promisc = 0; bond->alb_info.rlb_promisc_timeout_counter = 0; } bond->current_slave = new_slave; if (!new_slave || (bond->slave_cnt == 0)) { return; } /* set the new current_slave to the bonds mac address * i.e. swap mac addresses of old current_slave and new current_slave */ if (!swap_slave) { /* find slave that is holding the bond's mac address */ swap_slave = bond_get_first_slave(bond); while (swap_slave) { if (!memcmp(swap_slave->dev->dev_addr, bond->device->dev_addr, ETH_ALEN)) { break; } swap_slave = bond_get_next_slave(bond, swap_slave); } } /* current_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ alb_set_mac_addr(new_slave, bond->device->dev_addr, bond->alb_info.rlb_enabled); /* fasten bond mac on new current slave */ alb_send_learning_packets(new_slave, bond->device->dev_addr); } }
static int netdev_attach(struct vport *vport) { struct netdev_vport *netdev_vport = netdev_vport_priv(vport); int err; err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) return err; dev_set_promiscuity(netdev_vport->dev, 1); dev_disable_lro(netdev_vport->dev); netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; return 0; }
struct vport *ovs_netdev_link(struct vport *vport, const char *name) { int err; vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), name); if (!vport->dev) { err = -ENODEV; goto error_free_vport; } if (vport->dev->flags & IFF_LOOPBACK || (vport->dev->type != ARPHRD_ETHER && vport->dev->type != ARPHRD_NONE) || ovs_is_internal_dev(vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); err = netdev_master_upper_dev_link(vport->dev, get_dpdev(vport->dp), NULL, NULL, NULL); if (err) goto error_unlock; err = netdev_rx_handler_register(vport->dev, netdev_frame_hook, vport); if (err) goto error_master_upper_dev_unlink; dev_disable_lro(vport->dev); dev_set_promiscuity(vport->dev, 1); vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); return vport; error_master_upper_dev_unlink: netdev_upper_dev_unlink(vport->dev, get_dpdev(vport->dp)); error_unlock: rtnl_unlock(); error_put: dev_put(vport->dev); error_free_vport: ovs_vport_free(vport); return ERR_PTR(err); }
static int dsa_slave_close(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = p->parent->dst->master_netdev; dev_mc_unsync(master, dev); dev_uc_unsync(master, dev); if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); if (compare_ether_addr(dev->dev_addr, master->dev_addr)) dev_uc_del(master, dev->dev_addr); return 0; }
int nta_register_zc(struct net_device *netdev, int (*hard_start_xmit) (struct m_buf *mbuf, struct net_device *dev)) { int i; struct zc_control *zc = &zc_sniffer[0]; for(i=0; i< ZC_MAX_NETDEVS; i++) { //printk("zc->netdev[%d] %p\n", i, zc->netdev[i]); if(!zc->netdev[i] && netdev) { zc->netdev[i] = netdev; zc->hard_start_xmit = hard_start_xmit; dev_set_promiscuity(zc->netdev[i], 1); return i; } } return -1; }
static int vlan_dev_open(struct net_device *dev) { struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; int err; if (!(real_dev->flags & IFF_UP) && !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) return -ENETDOWN; if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { err = dev_uc_add(real_dev, dev->dev_addr); if (err < 0) goto out; } if (dev->flags & IFF_ALLMULTI) { err = dev_set_allmulti(real_dev, 1); if (err < 0) goto del_unicast; } if (dev->flags & IFF_PROMISC) { err = dev_set_promiscuity(real_dev, 1); if (err < 0) goto clear_allmulti; } memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN); if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); netif_carrier_on(dev); return 0; clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); del_unicast: if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) dev_uc_del(real_dev, dev->dev_addr); out: netif_carrier_off(dev); return err; }