/* * Determine initial path cost based on speed. * using recommendations from 802.1d standard * * Since driver might sleep need to not be holding any locks.
*/ staticint port_cost(struct net_device *dev)
{ struct ethtool_link_ksettings ecmd;
if (!__ethtool_get_link_ksettings(dev, &ecmd)) { switch (ecmd.base.speed) { case SPEED_10000: return 2; case SPEED_5000: return 3; case SPEED_2500: return 4; case SPEED_1000: return 5; case SPEED_100: return 19; case SPEED_10: return 100; case SPEED_UNKNOWN: return 100; default: if (ecmd.base.speed > SPEED_10000) return 1;
}
}
/* Old silly heuristics based on name */ if (!strncmp(dev->name, "lec", 3)) return 7;
staticvoid br_port_clear_promisc(struct net_bridge_port *p)
{ int err;
/* Check if the port is already non-promisc or if it doesn't * support UNICAST filtering. Without unicast filtering support * we'll end up re-enabling promisc mode anyway, so just check for * it here.
*/ if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT)) return;
/* Since we'll be clearing the promisc mode, program the port * first so that we don't have interruption in traffic.
*/
err = br_fdb_sync_static(p->br, p); if (err) return;
/* When a port is added or removed or when certain port flags * change, this function is called to automatically manage * promiscuity setting of all the bridge ports. We are always called * under RTNL so can skip using rcu primitives.
*/ void br_manage_promisc(struct net_bridge *br)
{ struct net_bridge_port *p; bool set_all = false;
/* If vlan filtering is disabled or bridge interface is placed * into promiscuous mode, place all ports in promiscuous mode.
*/ if ((br->dev->flags & IFF_PROMISC) || !br_vlan_enabled(br->dev))
set_all = true;
list_for_each_entry(p, &br->port_list, list) { if (set_all) {
br_port_set_promisc(p);
} else { /* If the number of auto-ports is <= 1, then all other * ports will have their output configuration * statically specified through fdbs. Since ingress * on the auto-port becomes forwarding/egress to other * ports and egress configuration is statically known, * we can say that ingress configuration of the * auto-port is also statically known. * This lets us disable promiscuous mode and write * this config to hw.
*/ if ((p->dev->priv_flags & IFF_UNICAST_FLT) &&
(br->auto_cnt == 0 ||
(br->auto_cnt == 1 && br_auto_port(p))))
br_port_clear_promisc(p); else
br_port_set_promisc(p);
}
}
}
list_for_each_entry(p, &br->port_list, list) { if (br_auto_port(p))
cnt++;
} if (br->auto_cnt != cnt) {
br->auto_cnt = cnt;
br_manage_promisc(br);
}
}
staticvoid nbp_delete_promisc(struct net_bridge_port *p)
{ /* If port is currently promiscuous, unset promiscuity. * Otherwise, it is a static port so remove all addresses * from it.
*/
dev_set_allmulti(p->dev, -1); if (br_promisc_port(p))
dev_set_promiscuity(p->dev, -1); else
br_fdb_unsync_static(p->br, p);
}
/* Delete port(interface) from bridge is done in two steps. * via RCU. First step, marks device as down. That deletes * all the timers and stops new packets from flowing through. * * Final cleanup doesn't occur until after all CPU's finished * processing packets. * * Protected from multiple admin operations by RTNL mutex
*/ staticvoid del_nbp(struct net_bridge_port *p)
{ struct net_bridge *br = p->br; struct net_device *dev = p->dev;
/* called with RTNL but without bridge lock */ staticstruct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device *dev)
{ struct net_bridge_port *p; int index, err;
index = find_portno(br); if (index < 0) return ERR_PTR(index);
p = kzalloc(sizeof(*p), GFP_KERNEL); if (p == NULL) return ERR_PTR(-ENOMEM);
res = register_netdevice(dev); if (res)
free_netdev(dev); return res;
}
int br_del_bridge(struct net *net, constchar *name)
{ struct net_device *dev; int ret = 0;
dev = __dev_get_by_name(net, name); if (dev == NULL)
ret = -ENXIO; /* Could not find device */
elseif (!netif_is_bridge_master(dev)) { /* Attempt to delete non bridge device! */
ret = -EPERM;
}
elseif (dev->flags & IFF_UP) { /* Not shutdown yet. */
ret = -EBUSY;
}
else
br_dev_delete(dev, NULL);
return ret;
}
/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ staticint br_mtu_min(conststruct net_bridge *br)
{ conststruct net_bridge_port *p; int ret_mtu = 0;
/* if the bridge MTU was manually configured don't mess with it */ if (br_opt_get(br, BROPT_MTU_SET_BY_USER)) return;
/* change to the minimum MTU and clear the flag which was set by * the bridge ndo_change_mtu callback
*/
dev_set_mtu(br->dev, br_mtu_min(br));
br_opt_toggle(br, BROPT_MTU_SET_BY_USER, false);
}
/* No bridging of bridges */ if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) {
NL_SET_ERR_MSG(extack, "Can not enslave a bridge to a bridge"); return -ELOOP;
}
/* Device has master upper dev */ if (netdev_master_upper_dev_get(dev)) return -EBUSY;
/* No bridging devices that dislike that (e.g. wireless) */ if (dev->priv_flags & IFF_DONT_BRIDGE) {
NL_SET_ERR_MSG(extack, "Device does not allow enslaving to a bridge"); return -EOPNOTSUPP;
}
p = new_nbp(br, dev); if (IS_ERR(p)) return PTR_ERR(p);
nbp_update_port_count(br); if (!br_promisc_port(p) && (p->dev->priv_flags & IFF_UNICAST_FLT)) { /* When updating the port count we also update all ports' * promiscuous mode. * A port leaving promiscuous mode normally gets the bridge's * fdb synced to the unicast filter (if supported), however, * `br_port_clear_promisc` does not distinguish between * non-promiscuous ports and *new* ports, so we need to * sync explicitly here.
*/
fdb_synced = br_fdb_sync_static(br, p) == 0; if (!fdb_synced)
netdev_err(dev, "failed to sync bridge static fdb addresses to this port\n");
}
if (br_fdb_add_local(br, p, dev->dev_addr, 0))
netdev_err(dev, "failed insert local address bridge forwarding table\n");
if (br->dev->addr_assign_type != NET_ADDR_SET) { /* Ask for permission to use this MAC address now, even if we * don't end up choosing it below.
*/
err = netif_pre_changeaddr_notify(br->dev, dev->dev_addr,
extack); if (err) goto err6;
}
err = nbp_vlan_init(p, extack); if (err) {
netdev_err(dev, "failed to initialize vlan filtering on this port\n"); goto err6;
}
/* called with RTNL */ int br_del_if(struct net_bridge *br, struct net_device *dev)
{ struct net_bridge_port *p; bool changed_addr;
p = br_port_get_rtnl(dev); if (!p || p->br != br) return -EINVAL;
/* Since more than one interface can be attached to a bridge, * there still maybe an alternate path for netconsole to use; * therefore there is no reason for a NETDEV_RELEASE event.
*/
del_nbp(p);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.