// SPDX-License-Identifier: GPL-2.0-or-later /* * Handling of a conduit device, switching frames via its switch fabric CPU port * * Copyright (c) 2017 Savoir-faire Linux Inc. * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*/
if (ds->ops->get_strings) {
ndata = data + mcount * len; /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle * the output after to prepend our CPU port prefix we * constructed earlier
*/
ds->ops->get_strings(ds, port, stringset, ndata);
count = ds->ops->get_sset_count(ds, port, stringset); if (count < 0) return; for (i = 0; i < count; i++) {
memmove(ndata + (i * len + sizeof(pfx)),
ndata + i * len, len - sizeof(pfx));
memcpy(ndata + i * len, pfx, sizeof(pfx));
}
}
}
/* Deny PTP operations on conduit if there is at least one switch in the tree * that is PTP capable.
*/ int __dsa_conduit_hwtstamp_validate(struct net_device *dev, conststruct kernel_hwtstamp_config *config, struct netlink_ext_ack *extack)
{ struct dsa_port *cpu_dp = dev->dsa_ptr; struct dsa_switch *ds = cpu_dp->ds; struct dsa_switch_tree *dst; struct dsa_port *dp;
dst = ds->dst;
list_for_each_entry(dp, &dst->ports, list) { if (dsa_port_supports_hwtstamp(dp)) {
NL_SET_ERR_MSG(extack, "HW timestamping not allowed on DSA conduit when switch supports the operation"); return -EBUSY;
}
}
/* Keep the conduit always promiscuous if the tagging protocol requires that * (garbles MAC DA) or if it doesn't support unicast filtering, case in which * it would revert to promiscuous mode as soon as we call dev_uc_add() on it * anyway.
*/ staticvoid dsa_conduit_set_promiscuity(struct net_device *dev, int inc)
{ conststruct dsa_device_ops *ops = dev->dsa_ptr->tag_ops;
if ((dev->priv_flags & IFF_UNICAST_FLT) && !ops->promisc_on_conduit) return;
/* Empty string passed */ if (!len) return -ENOPROTOOPT;
name = kstrndup(buf, len, GFP_KERNEL); if (!name) return -ENOMEM;
old_tag_ops = cpu_dp->tag_ops;
new_tag_ops = dsa_tag_driver_get_by_name(name);
kfree(name); /* Bad tagger name? */ if (IS_ERR(new_tag_ops)) return PTR_ERR(new_tag_ops);
if (new_tag_ops == old_tag_ops) /* Drop the temporarily held duplicate reference, since * the DSA switch tree uses this tagger.
*/ goto out;
err = dsa_tree_change_tag_proto(cpu_dp->ds->dst, new_tag_ops,
old_tag_ops); if (err) { /* On failure the old tagger is restored, so we don't need the * driver for the new one.
*/
dsa_tag_driver_put(new_tag_ops); return err;
}
/* On success we no longer need the module for the old tagging protocol
*/
out:
dsa_tag_driver_put(old_tag_ops); return count;
} static DEVICE_ATTR_RW(tagging);
mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops);
/* The DSA conduit must use SET_NETDEV_DEV for this to work. */ if (!netif_is_lag_master(dev)) {
consumer_link = device_link_add(ds->dev, dev->dev.parent,
DL_FLAG_AUTOREMOVE_CONSUMER); if (!consumer_link)
netdev_err(dev, "Failed to create a device link to DSA switch %s\n",
dev_name(ds->dev));
}
/* The switch driver may not implement ->port_change_mtu(), case in * which dsa_user_change_mtu() will not update the conduit MTU either, * so we need to do that here.
*/
ret = dev_set_mtu(dev, mtu); if (ret)
netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n",
ret, mtu);
/* If we use a tagging format that doesn't have an ethertype * field, make sure that all packets from this point on get * sent to the tag format's receive function.
*/
wmb();
dev->dsa_ptr = cpu_dp;
dsa_conduit_set_promiscuity(dev, 1);
ret = dsa_conduit_ethtool_setup(dev); if (ret) goto out_err_reset_promisc;
ret = sysfs_create_group(&dev->dev.kobj, &dsa_group); if (ret) goto out_err_ethtool_teardown;
/* If we used a tagging format that doesn't have an ethertype * field, make sure that all packets from this point get sent * without the tag and go through the regular receive path.
*/
wmb();
}
int dsa_conduit_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp, struct netdev_lag_upper_info *uinfo, struct netlink_ext_ack *extack)
{ bool conduit_setup = false; int err;
if (!netdev_uses_dsa(lag_dev)) {
err = dsa_conduit_setup(lag_dev, cpu_dp); if (err) return err;
conduit_setup = true;
}
err = dsa_port_lag_join(cpu_dp, lag_dev, uinfo, extack); if (err) {
NL_SET_ERR_MSG_WEAK_MOD(extack, "CPU port failed to join LAG"); goto out_conduit_teardown;
}
return 0;
out_conduit_teardown: if (conduit_setup)
dsa_conduit_teardown(lag_dev); return err;
}
/* Tear down a conduit if there isn't any other user port on it, * optionally also destroying LAG information.
*/ void dsa_conduit_lag_teardown(struct net_device *lag_dev, struct dsa_port *cpu_dp)
{ struct net_device *upper; struct list_head *iter;
dsa_port_lag_leave(cpu_dp, lag_dev);
netdev_for_each_upper_dev_rcu(lag_dev, upper, iter) if (dsa_user_dev_check(upper)) return;
dsa_conduit_teardown(lag_dev);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
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.