if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL;
if (ds->ops->port_set_mac_address) {
err = ds->ops->port_set_mac_address(ds, dp->index,
addr->sa_data); if (err) return err;
}
/* If the port is down, the address isn't synced yet to hardware or * to the DSA conduit, so there is nothing to change.
*/ if (!(dev->flags & IFF_UP)) goto out_change_dev_addr;
err = dsa_user_host_uc_install(dev, addr->sa_data); if (err) return err;
switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_set_state(dp, attr->u.stp_state, true); break; case SWITCHDEV_ATTR_ID_PORT_MST_STATE: if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_set_mst_state(dp, &attr->u.mst_state, extack); break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering,
extack); break; case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_ageing_time(dp, attr->u.ageing_time); break; case SWITCHDEV_ATTR_ID_BRIDGE_MST: if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_mst_enable(dp, attr->u.mst, extack); break; case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags,
extack); break; case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, extack); break; case SWITCHDEV_ATTR_ID_VLAN_MSTI: if (!dsa_port_offloads_bridge_dev(dp, attr->orig_dev)) return -EOPNOTSUPP;
ret = dsa_port_vlan_msti(dp, &attr->u.vlan_msti); break; default:
ret = -EOPNOTSUPP; break;
}
return ret;
}
/* Must be called under rcu_read_lock() */ staticint
dsa_user_vlan_check_for_8021q_uppers(struct net_device *user, conststruct switchdev_obj_port_vlan *vlan)
{ struct net_device *upper_dev; struct list_head *iter;
if (dsa_port_skip_vlan_configuration(dp)) {
NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); return 0;
}
vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
/* Deny adding a bridge VLAN when there is already an 802.1Q upper with * the same VID.
*/ if (br_vlan_enabled(dsa_port_bridge_dev_get(dp))) {
rcu_read_lock();
err = dsa_user_vlan_check_for_8021q_uppers(dev, vlan);
rcu_read_unlock(); if (err) {
NL_SET_ERR_MSG_MOD(extack, "Port already has a VLAN upper with this VID"); return err;
}
}
return dsa_port_vlan_add(dp, vlan, extack);
}
/* Offload a VLAN installed on the bridge or on a foreign interface by * installing it as a VLAN towards the CPU port.
*/ staticint dsa_user_host_vlan_add(struct net_device *dev, conststruct switchdev_obj *obj, struct netlink_ext_ack *extack)
{ struct dsa_port *dp = dsa_user_to_port(dev); struct switchdev_obj_port_vlan vlan;
/* Do nothing if this is a software bridge */ if (!dp->bridge) return -EOPNOTSUPP;
if (dsa_port_skip_vlan_configuration(dp)) {
NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN"); return 0;
}
vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj);
/* Even though drivers often handle CPU membership in special ways, * it doesn't make sense to program a PVID, so clear this flag.
*/
vlan.flags &= ~BRIDGE_VLAN_INFO_PVID;
if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NOBPF)) return;
if (!ds->ops->port_txtstamp) return;
ds->ops->port_txtstamp(ds, p->dp->index, skb);
}
netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev)
{ /* SKB for netpoll still need to be mangled with the protocol-specific * tag to be successfully transmitted
*/ if (unlikely(netpoll_tx_running(dev))) return dsa_user_netpoll_send_skb(dev, skb);
/* Queue the SKB for transmission on the parent interface, but * do not modify its EtherType
*/
skb->dev = dsa_user_to_conduit(dev);
dev_queue_xmit(skb);
/* Handle tx timestamp if any */
dsa_skb_tx_timestamp(p, skb);
if (skb_ensure_writable_head_tail(skb, dev)) {
dev_kfree_skb_any(skb); return NETDEV_TX_OK;
}
/* needed_tailroom should still be 'warm' in the cache line from * skb_ensure_writable_head_tail(), which has also ensured that * padding is safe.
*/ if (dev->needed_tailroom)
eth_skb_pad(skb);
/* Transmit function may have to reallocate the original SKB, * in which case it must have freed it. Only free it here on error.
*/
nskb = p->xmit(skb, dev); if (!nskb) {
kfree_skb(skb); return NETDEV_TX_OK;
}
/* Check whether the switch supports EEE */ if (!ds->ops->support_eee || !ds->ops->support_eee(ds, dp->index)) return -EOPNOTSUPP;
/* If the port is using phylink managed EEE, then an unimplemented * set_mac_eee() is permissible.
*/ if (!phylink_mac_implements_lpi(ds->phylink_mac_ops)) { /* Port's PHY and MAC both need to be EEE capable */ if (!dev->phydev) return -ENODEV;
if (!ds->ops->set_mac_eee) return -EOPNOTSUPP;
ret = ds->ops->set_mac_eee(ds, dp->index, e); if (ret) return ret;
} elseif (ds->ops->set_mac_eee) {
ret = ds->ops->set_mac_eee(ds, dp->index, e); if (ret) return ret;
}
if (cls->common.protocol != htons(ETH_P_ALL)) {
NL_SET_ERR_MSG_MOD(extack, "Can only offload \"protocol all\" matchall filter"); return -EOPNOTSUPP;
}
if (!ds->ops->port_mirror_add) {
NL_SET_ERR_MSG_MOD(extack, "Switch does not support mirroring operation"); return -EOPNOTSUPP;
}
if (!flow_action_basic_hw_stats_check(&cls->rule->action, extack)) return -EOPNOTSUPP;
act = &cls->rule->action.entries[0];
if (!act->dev) return -EINVAL;
if (dsa_user_dev_check(act->dev)) { if (ingress_target) { /* We can only fulfill this using software assist */ if (cls->common.skip_sw) {
NL_SET_ERR_MSG_MOD(extack, "Can only mirred to ingress of DSA user port if filter also runs in software"); return -EOPNOTSUPP;
}
to_dp = dp->cpu_dp;
} else {
to_dp = dsa_user_to_port(act->dev);
}
} else { /* Handle mirroring to foreign target ports as a mirror towards * the CPU. The software tc rule will take the packets from * there.
*/ if (cls->common.skip_sw) {
NL_SET_ERR_MSG_MOD(extack, "Can only mirred to CPU if filter also runs in software"); return -EOPNOTSUPP;
}
to_dp = dp->cpu_dp;
}
if (dp->ds != to_dp->ds) {
NL_SET_ERR_MSG_MOD(extack, "Cross-chip mirroring not implemented"); return -EOPNOTSUPP;
}
mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL); if (!mall_tc_entry) return -ENOMEM;
if (!flow_offload_has_one_action(action)) {
NL_SET_ERR_MSG_MOD(extack, "Cannot offload matchall filter with more than one action"); return -EOPNOTSUPP;
}
switch (action->entries[0].id) { case FLOW_ACTION_MIRRED: return dsa_user_add_cls_matchall_mirred(dev, cls, ingress, false); case FLOW_ACTION_MIRRED_INGRESS: return dsa_user_add_cls_matchall_mirred(dev, cls, ingress, true); case FLOW_ACTION_POLICE: return dsa_user_add_cls_matchall_police(dev, cls, ingress); default:
NL_SET_ERR_MSG_MOD(extack, "Unknown action"); break;
}
/* User port... */
ret = dsa_port_vlan_add(dp, &vlan, &extack); if (ret) { if (extack._msg)
netdev_err(dev, "%s\n", extack._msg); return ret;
}
/* And CPU port... */
ret = dsa_port_host_vlan_add(dp, &vlan, &extack); if (ret) { if (extack._msg)
netdev_err(dev, "CPU port %d: %s\n", dp->cpu_dp->index,
extack._msg); return ret;
}
if (!dsa_switch_supports_uc_filtering(ds) &&
!dsa_switch_supports_mc_filtering(ds)) return 0;
v = kzalloc(sizeof(*v), GFP_KERNEL); if (!v) {
ret = -ENOMEM; goto rollback;
}
staticint dsa_user_restore_vlan(struct net_device *vdev, int vid, void *arg)
{
__be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q);
return dsa_user_vlan_rx_add_vid(arg, proto, vid);
}
staticint dsa_user_clear_vlan(struct net_device *vdev, int vid, void *arg)
{
__be16 proto = vdev ? vlan_dev_vlan_proto(vdev) : htons(ETH_P_8021Q);
return dsa_user_vlan_rx_kill_vid(arg, proto, vid);
}
/* Keep the VLAN RX filtering list in sync with the hardware only if VLAN * filtering is enabled. The baseline is that only ports that offload a * VLAN-aware bridge are VLAN-aware, and standalone ports are VLAN-unaware, * but there are exceptions for quirky hardware. * * If ds->vlan_filtering_is_global = true, then standalone ports which share * the same switch with other ports that offload a VLAN-aware bridge are also * inevitably VLAN-aware. * * To summarize, a DSA switch port offloads: * * - If standalone (this includes software bridge, software LAG): * - if ds->needs_standalone_vlan_filtering = true, OR if * (ds->vlan_filtering_is_global = true AND there are bridges spanning * this switch chip which have vlan_filtering=1) * - the 8021q upper VLANs * - else (standalone VLAN filtering is not needed, VLAN filtering is not * global, or it is, but no port is under a VLAN-aware bridge): * - no VLAN (any 8021q upper is a software VLAN) * * - If under a vlan_filtering=0 bridge which it offload: * - if ds->configure_vlan_while_not_filtering = true (default): * - the bridge VLANs. These VLANs are committed to hardware but inactive. * - else (deprecated): * - no VLAN. The bridge VLANs are not restored when VLAN awareness is * enabled, so this behavior is broken and discouraged. * * - If under a vlan_filtering=1 bridge which it offload: * - the bridge VLANs * - the 8021q upper VLANs
*/ int dsa_user_manage_vlan_filtering(struct net_device *user, bool vlan_filtering)
{ int err;
if (vlan_filtering) {
user->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
list_for_each_entry_safe(p, n, hw_port_list, list)
kfree(p);
}
/* Make the hardware datapath to/from @dev limited to a common MTU */ staticvoid dsa_bridge_mtu_normalization(struct dsa_port *dp)
{ struct list_head hw_port_list; struct dsa_switch_tree *dst; int min_mtu = ETH_MAX_MTU; struct dsa_port *other_dp; int err;
if (!dp->ds->mtu_enforcement_ingress) return;
if (!dp->bridge) return;
INIT_LIST_HEAD(&hw_port_list);
/* Populate the list of ports that are part of the same bridge * as the newly added/modified port
*/
list_for_each_entry(dst, &dsa_tree_list, list) {
list_for_each_entry(other_dp, &dst->ports, list) { struct dsa_hw_port *hw_port; struct net_device *user;
if (other_dp->type != DSA_PORT_TYPE_USER) continue;
if (!dsa_port_bridge_same(dp, other_dp)) continue;
if (!other_dp->ds->mtu_enforcement_ingress) continue;
user = other_dp->user;
if (min_mtu > user->mtu)
min_mtu = user->mtu;
hw_port = kzalloc(sizeof(*hw_port), GFP_KERNEL); if (!hw_port) goto out;
/* Attempt to configure the entire hardware bridge to the newly added * interface's MTU first, regardless of whether the intention of the * user was to raise or lower it.
*/
err = dsa_hw_port_list_set_mtu(&hw_port_list, dp->user->mtu); if (!err) goto out;
/* Clearly that didn't work out so well, so just set the minimum MTU on * all hardware bridge ports now. If this fails too, then all ports will * still have their old MTU rolled back anyway.
*/
dsa_hw_port_list_set_mtu(&hw_port_list, min_mtu);
out:
dsa_hw_port_list_free(&hw_port_list);
}
int dsa_user_change_mtu(struct net_device *dev, int new_mtu)
{ struct net_device *conduit = dsa_user_to_conduit(dev); struct dsa_port *dp = dsa_user_to_port(dev); struct dsa_port *cpu_dp = dp->cpu_dp; struct dsa_switch *ds = dp->ds; struct dsa_port *other_dp; int largest_mtu = 0; int new_conduit_mtu; int old_conduit_mtu; int mtu_limit; int overhead; int cpu_mtu; int err;
if (!ds->ops->port_change_mtu) return -EOPNOTSUPP;
dsa_tree_for_each_user_port(other_dp, ds->dst) { int user_mtu;
/* During probe, this function will be called for each user * device, while not all of them have been allocated. That's * ok, it doesn't change what the maximum is, so ignore it.
*/ if (!other_dp->user) continue;
/* Pretend that we already applied the setting, which we * actually haven't (still haven't done all integrity checks)
*/ if (dp == other_dp)
user_mtu = new_mtu; else
user_mtu = other_dp->user->mtu;
if (largest_mtu < user_mtu)
largest_mtu = user_mtu;
}
/* If the conduit MTU isn't over limit, there's no need to check the CPU * MTU, since that surely isn't either.
*/
cpu_mtu = largest_mtu;
/* Start applying stuff */ if (new_conduit_mtu != old_conduit_mtu) {
err = dev_set_mtu(conduit, new_conduit_mtu); if (err < 0) goto out_conduit_failed;
/* We only need to propagate the MTU of the CPU port to * upstream switches, so emit a notifier which updates them.
*/
err = dsa_port_mtu_change(cpu_dp, cpu_mtu); if (err) goto out_cpu_failed;
}
err = ds->ops->port_change_mtu(ds, dp->index, new_mtu); if (err) goto out_port_failed;
WRITE_ONCE(dev->mtu, new_mtu);
dsa_bridge_mtu_normalization(dp);
return 0;
out_port_failed: if (new_conduit_mtu != old_conduit_mtu)
dsa_port_mtu_change(cpu_dp, old_conduit_mtu - overhead);
out_cpu_failed: if (new_conduit_mtu != old_conduit_mtu)
dev_set_mtu(conduit, old_conduit_mtu);
out_conduit_failed: return err;
}
staticint __maybe_unused
dsa_user_dcbnl_set_apptrust(struct net_device *dev, u8 *sel, int nsel)
{ struct dsa_port *dp = dsa_user_to_port(dev); struct dsa_switch *ds = dp->ds; int port = dp->index;
if (!ds->ops->port_set_apptrust) return -EOPNOTSUPP;
/* Update the DSCP prio entries on all user ports of the switch in case * the switch supports global DSCP prio instead of per port DSCP prios.
*/ staticint dsa_user_dcbnl_ieee_global_dscp_setdel(struct net_device *dev, struct dcb_app *app, bool del)
{ int (*setdel)(struct net_device *dev, struct dcb_app *app); struct dsa_port *dp = dsa_user_to_port(dev); struct dsa_switch *ds = dp->ds; struct dsa_port *other_dp; int err, restore_err;
if (del)
setdel = dcb_ieee_delapp; else
setdel = dcb_ieee_setapp;
/* Pre-populate the DCB application priority table with the priorities * configured during switch setup, which we read from hardware here.
*/ staticint dsa_user_dcbnl_init(struct net_device *dev)
{ struct dsa_port *dp = dsa_user_to_port(dev); struct dsa_switch *ds = dp->ds; int port = dp->index; int err;
/* No need to check that this operation is valid, the callback would * not be called if it was not.
*/
ds->ops->phylink_fixed_state(ds, dp->index, state);
}
/* The get_fixed_state callback takes precedence over polling the * link GPIO in PHYLINK (see phylink_get_fixed_state). Only set * this if the switch provides such a callback.
*/ if (ds->ops->phylink_fixed_state) {
dp->pl_config.get_fixed_state = dsa_user_phylink_fixed_state;
dp->pl_config.poll_fixed_state = true;
}
ret = dsa_port_phylink_create(dp); if (ret) return ret;
if (ds->ops->get_phy_flags)
phy_flags = ds->ops->get_phy_flags(ds, dp->index);
ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); if (ret == -ENODEV && ds->user_mii_bus) { /* We could not connect to a designated PHY or SFP, so try to * use the switch internal MDIO bus instead
*/
ret = dsa_user_phy_connect(user_dev, dp->index, phy_flags);
} if (ret) {
netdev_err(user_dev, "failed to connect to PHY: %pe\n",
ERR_PTR(ret));
dsa_port_phylink_destroy(dp);
}
user->needed_headroom = cpu_dp->tag_ops->needed_headroom;
user->needed_tailroom = cpu_dp->tag_ops->needed_tailroom; /* Try to save one extra realloc later in the TX path (in the conduit) * by also inheriting the conduit's needed headroom and tailroom. * The 8021q driver also does this.
*/
user->needed_headroom += conduit->needed_headroom;
user->needed_tailroom += conduit->needed_tailroom;
p->xmit = cpu_dp->tag_ops->xmit;
user->features = conduit->vlan_features | NETIF_F_HW_TC;
user->hw_features |= NETIF_F_HW_TC; if (user->needed_tailroom)
user->features &= ~(NETIF_F_SG | NETIF_F_FRAGLIST); if (ds->needs_standalone_vlan_filtering)
user->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
user->lltx = true;
}
int dsa_user_suspend(struct net_device *user_dev)
{ struct dsa_port *dp = dsa_user_to_port(user_dev);
if (!netif_running(user_dev)) return 0;
netif_device_detach(user_dev);
rtnl_lock();
phylink_stop(dp->pl);
rtnl_unlock();
return 0;
}
int dsa_user_resume(struct net_device *user_dev)
{ struct dsa_port *dp = dsa_user_to_port(user_dev);
ret = dsa_user_phy_setup(user_dev); if (ret) {
netdev_err(user_dev, "error %d setting up PHY for tree %d, switch %d, port %d\n",
ret, ds->dst->index, ds->index, port->index); goto out_gcells;
}
rtnl_lock();
ret = dsa_user_change_mtu(user_dev, ETH_DATA_LEN); if (ret && ret != -EOPNOTSUPP)
dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n",
ret, ETH_DATA_LEN, port->index);
ret = register_netdevice(user_dev); if (ret) {
netdev_err(conduit, "error %d registering interface %s\n",
ret, user_dev->name);
rtnl_unlock(); goto out_phy;
}
if (IS_ENABLED(CONFIG_DCB)) {
ret = dsa_user_dcbnl_init(user_dev); if (ret) {
netdev_err(user_dev, "failed to initialize DCB: %pe\n",
ERR_PTR(ret));
rtnl_unlock(); goto out_unregister;
}
}
ret = netdev_upper_dev_link(conduit, user_dev, NULL);
if (!ds->ops->port_change_conduit) {
NL_SET_ERR_MSG_MOD(extack, "Driver does not support changing DSA conduit"); return -EOPNOTSUPP;
}
if (!netdev_uses_dsa(conduit)) {
NL_SET_ERR_MSG_MOD(extack, "Interface not eligible as DSA conduit"); return -EOPNOTSUPP;
}
netdev_for_each_upper_dev_rcu(conduit, upper, iter) { if (dsa_user_dev_check(upper)) continue; if (netif_is_bridge_master(upper)) continue;
NL_SET_ERR_MSG_MOD(extack, "Cannot join conduit with unknown uppers"); return -EOPNOTSUPP;
}
/* Since we allow live-changing the DSA conduit, plus we auto-open the * DSA conduit when the user port opens => we need to ensure that the * new DSA conduit is open too.
*/ if (dev->flags & IFF_UP) {
err = dev_open(conduit, extack); if (err) return err;
}
netdev_upper_dev_unlink(old_conduit, dev);
err = netdev_upper_dev_link(conduit, dev, extack); if (err) goto out_revert_old_conduit_unlink;
err = dsa_port_change_conduit(dp, conduit, extack); if (err) goto out_revert_conduit_link;
/* Update the MTU of the new CPU port through cross-chip notifiers */
err = dsa_user_change_mtu(dev, dev->mtu); if (err && err != -EOPNOTSUPP) {
netdev_warn(dev, "nonfatal error updating MTU with new conduit: %pe\n",
ERR_PTR(err));
}
if (netif_is_bridge_master(info->upper_dev) && !info->linking)
dsa_port_pre_bridge_leave(dp, info->upper_dev); elseif (netif_is_lag_master(info->upper_dev) && !info->linking)
dsa_port_pre_lag_leave(dp, info->upper_dev); /* dsa_port_pre_hsr_leave is not yet necessary since hsr devices cannot * meaningfully placed under a bridge yet
*/
if (!br || !br_vlan_enabled(br)) return NOTIFY_DONE;
extack = netdev_notifier_info_to_extack(&info->info);
vid = vlan_dev_vlan_id(info->upper_dev);
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the * device, respectively the VID is not found, returning * 0 means success, which is a failure for us here.
*/
err = br_vlan_get_info(br, vid, &br_info); if (err == 0) {
NL_SET_ERR_MSG_MOD(extack, "This VLAN is already configured by the bridge"); return notifier_from_errno(-EBUSY);
}
if (!dsa_user_dev_check(dev)) return dsa_prevent_bridging_8021q_upper(dev, info);
dp = dsa_user_to_port(dev);
ds = dp->ds;
if (ds->ops->port_prechangeupper) {
err = ds->ops->port_prechangeupper(ds, dp->index, info); if (err) return notifier_from_errno(err);
}
if (is_vlan_dev(info->upper_dev)) return dsa_user_check_8021q_upper(dev, info);
return NOTIFY_DONE;
}
/* To be eligible as a DSA conduit, a LAG must have all lower interfaces be * eligible DSA conduits. Additionally, all LAG slaves must be DSA conduits of * switches in the same switch tree.
*/ staticint dsa_lag_conduit_validate(struct net_device *lag_dev, struct netlink_ext_ack *extack)
{ struct net_device *lower1, *lower2; struct list_head *iter1, *iter2;
netdev_for_each_lower_dev(lag_dev, lower1, iter1) {
netdev_for_each_lower_dev(lag_dev, lower2, iter2) { if (!netdev_uses_dsa(lower1) ||
!netdev_uses_dsa(lower2)) {
NL_SET_ERR_MSG_MOD(extack, "All LAG ports must be eligible as DSA conduits"); return notifier_from_errno(-EINVAL);
}
if (lower1 == lower2) continue;
if (!dsa_port_tree_same(lower1->dsa_ptr,
lower2->dsa_ptr)) {
NL_SET_ERR_MSG_MOD(extack, "LAG contains DSA conduits of disjoint switch trees"); return notifier_from_errno(-EINVAL);
}
}
}
if (!netdev_uses_dsa(conduit)) return NOTIFY_DONE;
if (!info->linking) return NOTIFY_DONE;
/* Allow DSA switch uppers */ if (dsa_user_dev_check(info->upper_dev)) return NOTIFY_DONE;
/* Allow bridge uppers of DSA conduits, subject to further * restrictions in dsa_bridge_prechangelower_sanity_check()
*/ if (netif_is_bridge_master(info->upper_dev)) return NOTIFY_DONE;
/* Allow LAG uppers, subject to further restrictions in * dsa_lag_conduit_prechangelower_sanity_check()
*/ if (netif_is_lag_master(info->upper_dev)) return dsa_lag_conduit_validate(info->upper_dev, extack);
if (!netdev_uses_dsa(lag_dev) || !netif_is_lag_master(lag_dev)) return NOTIFY_DONE;
if (!info->linking) return NOTIFY_DONE;
if (!netdev_uses_dsa(dev)) {
NL_SET_ERR_MSG(extack, "Only DSA conduits can join a LAG DSA conduit"); return notifier_from_errno(-EINVAL);
}
netdev_for_each_lower_dev(lag_dev, lower, iter) { if (!dsa_port_tree_same(dev->dsa_ptr, lower->dsa_ptr)) {
NL_SET_ERR_MSG(extack, "Interface is DSA conduit for a different switch tree than this LAG"); return notifier_from_errno(-EINVAL);
}
break;
}
return NOTIFY_DONE;
}
/* Don't allow bridging of DSA conduits, since the bridge layer rx_handler * prevents the DSA fake ethertype handler to be invoked, so we don't get the * chance to strip off and parse the DSA switch tag protocol header (the bridge * layer just returns RX_HANDLER_CONSUMED, stopping RX processing for these * frames). * The only case where that would not be an issue is when bridging can already * be offloaded, such as when the DSA conduit is itself a DSA or plain switchdev * port, and is bridged only with other ports from the same hardware device.
*/ staticint
dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower, struct netdev_notifier_changeupper_info *info)
{ struct net_device *br = info->upper_dev; struct netlink_ext_ack *extack; struct net_device *lower; struct list_head *iter;
if (!netif_is_bridge_master(br)) return NOTIFY_DONE;
netdev_for_each_lower_dev(br, lower, iter) { if (!netdev_uses_dsa(new_lower) && !netdev_uses_dsa(lower)) continue;
if (!netdev_port_same_parent_id(lower, new_lower)) {
NL_SET_ERR_MSG(extack, "Cannot do software bridging with a DSA conduit"); return notifier_from_errno(-EINVAL);
}
}
if (new_cpu_dp) { /* Update the CPU port of the user ports still under the LAG * so that dsa_port_to_conduit() continues to work properly
*/
dsa_tree_for_each_user_port(dp, dst) if (dsa_port_to_conduit(dp) == lag_dev)
dp->cpu_dp = new_cpu_dp;
/* Update the index of the virtual CPU port to match the lowest * physical CPU port
*/
lag_dev->dsa_ptr = new_cpu_dp;
wmb();
} else { /* If the LAG DSA conduit has no ports left, migrate back all * user ports to the first physical CPU port
*/
dsa_tree_migrate_ports_from_lag_conduit(dst, lag_dev);
}
/* This DSA conduit has left its LAG in any case, so let * the CPU port leave the hardware LAG as well
*/
dsa_conduit_lag_teardown(lag_dev, conduit->dsa_ptr);
}
/* Mirror LAG port events on DSA conduits that are in * a LAG towards their respective switch CPU ports
*/ if (netdev_uses_dsa(dev)) {
dp = dev->dsa_ptr;
return notifier_from_errno(err);
} case NETDEV_CHANGE: case NETDEV_UP: { /* Track state of conduit port. * DSA driver may require the conduit port (and indirectly * the tagger) to be available for some special operation.
*/ if (netdev_uses_dsa(dev)) { struct dsa_port *cpu_dp = dev->dsa_ptr; struct dsa_switch_tree *dst = cpu_dp->ds->dst;
/* Track when the conduit port is UP */
dsa_tree_conduit_oper_state_change(dst, dev,
netif_oper_up(dev));
/* Track when the conduit port is ready and can accept * packet. * NETDEV_UP event is not enough to flag a port as ready. * We also have to wait for linkwatch_do_dev to dev_activate * and emit a NETDEV_CHANGE event. * We check if a conduit port is ready by checking if the dev * have a qdisc assigned and is not noop.
*/
dsa_tree_conduit_admin_state_change(dst, dev,
!qdisc_tx_is_noop(dev));
if (switchdev_fdb_is_dynamically_learned(fdb_info)) { if (dsa_port_offloads_bridge_port(dp, orig_dev)) return 0;
/* FDB entries learned by the software bridge or by foreign * bridge ports should be installed as host addresses only if * the driver requests assisted learning.
*/ if (!ds->assisted_learning_on_cpu_port) return 0;
}
/* Also treat FDB entries on foreign interfaces bridged with us as host * addresses.
*/ if (dsa_foreign_dev_check(dev, orig_dev))
host_addr = true;
/* Check early that we're not doing work in vain. * Host addresses on LAG ports still require regular FDB ops, * since the CPU port isn't in a LAG.
*/ if (dp->lag && !host_addr) { if (!ds->ops->lag_fdb_add || !ds->ops->lag_fdb_del) return -EOPNOTSUPP;
} else { if (!ds->ops->port_fdb_add || !ds->ops->port_fdb_del) return -EOPNOTSUPP;
}
switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); if (!switchdev_work) return -ENOMEM;
netdev_dbg(dev, "%s FDB entry towards %s, addr %pM vid %d%s\n",
event == SWITCHDEV_FDB_ADD_TO_DEVICE ? "Adding" : "Deleting",
orig_dev->name, fdb_info->addr, fdb_info->vid,
host_addr ? " as host address" : "");
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.