net/bridge/br_multicast.c

Source file repositories/reference/linux-study-clean/net/bridge/br_multicast.c

File Facts

System
Linux kernel
Corpus path
net/bridge/br_multicast.c
Extension
.c
Size
142196 bytes
Lines
5250
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

if (brmctx->multicast_igmp_version == 3) {
			struct net_bridge_mdb_entry *mdb;

			ip.src.ip4 = ip_hdr(skb)->saddr;
			mdb = br_mdb_ip_get_rcu(br, &ip);
			if (mdb)
				return mdb;
			ip.src.ip4 = 0;
		}
		break;
#if IS_ENABLED(CONFIG_IPV6)
	case htons(ETH_P_IPV6):
		ip.dst.ip6 = ipv6_hdr(skb)->daddr;
		if (brmctx->multicast_mld_version == 2) {
			struct net_bridge_mdb_entry *mdb;

			ip.src.ip6 = ipv6_hdr(skb)->saddr;
			mdb = br_mdb_ip_get_rcu(br, &ip);
			if (mdb)
				return mdb;
			memset(&ip.src.ip6, 0, sizeof(ip.src.ip6));
		}
		break;
#endif
	default:
		ip.proto = 0;
		ether_addr_copy(ip.dst.mac_addr, eth_hdr(skb)->h_dest);
	}

	return br_mdb_ip_get_rcu(br, &ip);
}

/* IMPORTANT: this function must be used only when the contexts cannot be
 * passed down (e.g. timer) and must be used for read-only purposes because
 * the vlan snooping option can change, so it can return any context
 * (non-vlan or vlan). Its initial intended purpose is to read timer values
 * from the *current* context based on the option. At worst that could lead
 * to inconsistent timers when the contexts are changed, i.e. src timer
 * which needs to re-arm with a specific delay taken from the old context
 */
static struct net_bridge_mcast_port *
br_multicast_pg_to_port_ctx(const struct net_bridge_port_group *pg)
{
	struct net_bridge_mcast_port *pmctx = &pg->key.port->multicast_ctx;
	struct net_bridge_vlan *vlan;

	lockdep_assert_held_once(&pg->key.port->br->multicast_lock);

	/* if vlan snooping is disabled use the port's multicast context */
	if (!pg->key.addr.vid ||
	    !br_opt_get(pg->key.port->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED))
		goto out;

	/* locking is tricky here, due to different rules for multicast and
	 * vlans we need to take rcu to find the vlan and make sure it has
	 * the BR_VLFLAG_MCAST_ENABLED flag set, it can only change under
	 * multicast_lock which must be already held here, so the vlan's pmctx
	 * can safely be used on return
	 */
	rcu_read_lock();
	vlan = br_vlan_find(nbp_vlan_group_rcu(pg->key.port), pg->key.addr.vid);
	if (vlan && !br_multicast_port_ctx_vlan_disabled(&vlan->port_mcast_ctx))
		pmctx = &vlan->port_mcast_ctx;
	else
		pmctx = NULL;
	rcu_read_unlock();
out:
	return pmctx;
}

static struct net_bridge_mcast_port *
br_multicast_port_vid_to_port_ctx(struct net_bridge_port *port, u16 vid)
{
	struct net_bridge_mcast_port *pmctx = NULL;
	struct net_bridge_vlan *vlan;

	lockdep_assert_held_once(&port->br->multicast_lock);

	/* Take RCU to access the vlan. */
	rcu_read_lock();

	vlan = br_vlan_find(nbp_vlan_group_rcu(port), vid);
	if (vlan)
		pmctx = &vlan->port_mcast_ctx;

	rcu_read_unlock();

	return pmctx;
}

Annotation

Implementation Notes