net/dsa/port.c

Source file repositories/reference/linux-study-clean/net/dsa/port.c

File Facts

System
Linux kernel
Corpus path
net/dsa/port.c
Extension
.c
Size
47751 bytes
Lines
1956
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

br_vlan_enabled(bridge.dev)) {
		change_vlan_filtering = true;
		vlan_filtering = false;
	}

	/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
	 * event for changing vlan_filtering setting upon user ports leaving
	 * it. That is a good thing, because that lets us handle it and also
	 * handle the case where the switch's vlan_filtering setting is global
	 * (not per port). When that happens, the correct moment to trigger the
	 * vlan_filtering callback is only when the last port leaves the last
	 * VLAN-aware bridge.
	 */
	if (change_vlan_filtering && ds->vlan_filtering_is_global) {
		dsa_switch_for_each_port(other_dp, ds) {
			struct net_device *br = dsa_port_bridge_dev_get(other_dp);

			if (br && br_vlan_enabled(br)) {
				change_vlan_filtering = false;
				break;
			}
		}
	}

	if (!change_vlan_filtering)
		return;

	err = dsa_port_vlan_filtering(dp, vlan_filtering, &extack);
	if (extack._msg) {
		dev_err(ds->dev, "port %d: %s\n", dp->index,
			extack._msg);
	}
	if (err && err != -EOPNOTSUPP) {
		dev_err(ds->dev,
			"port %d failed to reset VLAN filtering to %d: %pe\n",
		       dp->index, vlan_filtering, ERR_PTR(err));
	}
}

static int dsa_port_inherit_brport_flags(struct dsa_port *dp,
					 struct netlink_ext_ack *extack)
{
	const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
				   BR_BCAST_FLOOD | BR_PORT_LOCKED;
	struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
	int flag, err;

	for_each_set_bit(flag, &mask, 32) {
		struct switchdev_brport_flags flags = {0};

		flags.mask = BIT(flag);

		if (br_port_flag_is_set(brport_dev, BIT(flag)))
			flags.val = BIT(flag);

		err = dsa_port_bridge_flags(dp, flags, extack);
		if (err && err != -EOPNOTSUPP)
			return err;
	}

	return 0;
}

static void dsa_port_clear_brport_flags(struct dsa_port *dp)
{
	const unsigned long val = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
	const unsigned long mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
				   BR_BCAST_FLOOD | BR_PORT_LOCKED;
	int flag, err;

	for_each_set_bit(flag, &mask, 32) {
		struct switchdev_brport_flags flags = {0};

		flags.mask = BIT(flag);
		flags.val = val & BIT(flag);

		err = dsa_port_bridge_flags(dp, flags, NULL);
		if (err && err != -EOPNOTSUPP)
			dev_err(dp->ds->dev,
				"failed to clear bridge port flag %lu: %pe\n",
				flags.val, ERR_PTR(err));
	}
}

static int dsa_port_switchdev_sync_attrs(struct dsa_port *dp,
					 struct netlink_ext_ack *extack)
{
	struct net_device *brport_dev = dsa_port_to_bridge_port(dp);
	struct net_device *br = dsa_port_bridge_dev_get(dp);
	int err;

Annotation

Implementation Notes