net/dsa/tag_8021q.c

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

File Facts

System
Linux kernel
Corpus path
net/dsa/tag_8021q.c
Extension
.c
Size
15812 bytes
Lines
589
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

struct dsa_tag_8021q_vlan {
	struct list_head list;
	int port;
	u16 vid;
	refcount_t refcount;
};

struct dsa_8021q_context {
	struct dsa_switch *ds;
	struct list_head vlans;
	/* EtherType of RX VID, used for filtering on conduit interface */
	__be16 proto;
};

u16 dsa_tag_8021q_bridge_vid(unsigned int bridge_num)
{
	/* The VBID value of 0 is reserved for precise TX, but it is also
	 * reserved/invalid for the bridge_num, so all is well.
	 */
	return DSA_8021Q_RSV | DSA_8021Q_VBID(bridge_num);
}
EXPORT_SYMBOL_GPL(dsa_tag_8021q_bridge_vid);

/* Returns the VID that will be installed as pvid for this switch port, sent as
 * tagged egress towards the CPU port and decoded by the rcv function.
 */
u16 dsa_tag_8021q_standalone_vid(const struct dsa_port *dp)
{
	return DSA_8021Q_RSV | DSA_8021Q_SWITCH_ID(dp->ds->index) |
	       DSA_8021Q_PORT(dp->index);
}
EXPORT_SYMBOL_GPL(dsa_tag_8021q_standalone_vid);

/* Returns the decoded switch ID from the RX VID. */
int dsa_8021q_rx_switch_id(u16 vid)
{
	return (vid & DSA_8021Q_SWITCH_ID_MASK) >> DSA_8021Q_SWITCH_ID_SHIFT;
}
EXPORT_SYMBOL_GPL(dsa_8021q_rx_switch_id);

/* Returns the decoded port ID from the RX VID. */
int dsa_8021q_rx_source_port(u16 vid)
{
	return (vid & DSA_8021Q_PORT_MASK) >> DSA_8021Q_PORT_SHIFT;
}
EXPORT_SYMBOL_GPL(dsa_8021q_rx_source_port);

/* Returns the decoded VBID from the RX VID. */
static int dsa_tag_8021q_rx_vbid(u16 vid)
{
	u16 vbid_hi = (vid & DSA_8021Q_VBID_HI_MASK) >> DSA_8021Q_VBID_HI_SHIFT;
	u16 vbid_lo = (vid & DSA_8021Q_VBID_LO_MASK) >> DSA_8021Q_VBID_LO_SHIFT;

	return (vbid_hi << 2) | vbid_lo;
}

bool vid_is_dsa_8021q(u16 vid)
{
	u16 rsv = (vid & DSA_8021Q_RSV_MASK) >> DSA_8021Q_RSV_SHIFT;

	return rsv == DSA_8021Q_RSV_VAL;
}
EXPORT_SYMBOL_GPL(vid_is_dsa_8021q);

static struct dsa_tag_8021q_vlan *
dsa_tag_8021q_vlan_find(struct dsa_8021q_context *ctx, int port, u16 vid)
{
	struct dsa_tag_8021q_vlan *v;

	list_for_each_entry(v, &ctx->vlans, list)
		if (v->vid == vid && v->port == port)
			return v;

	return NULL;
}

static int dsa_port_do_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid,
					  u16 flags)
{
	struct dsa_8021q_context *ctx = dp->ds->tag_8021q_ctx;
	struct dsa_switch *ds = dp->ds;
	struct dsa_tag_8021q_vlan *v;
	int port = dp->index;
	int err;

	/* No need to bother with refcounting for user ports */
	if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
		return ds->ops->tag_8021q_vlan_add(ds, port, vid, flags);

	v = dsa_tag_8021q_vlan_find(ctx, port, vid);

Annotation

Implementation Notes