Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78851988 authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller
Browse files

bridge: Implement vlan ingress/egress policy with PVID.



At ingress, any untagged traffic is assigned to the PVID.
Any tagged traffic is filtered according to membership bitmap.

At egress, if the vlan matches the PVID, the frame is sent
untagged.  Otherwise the frame is sent tagged.

Signed-off-by: default avatarVlad Yasevich <vyasevic@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6cbdceeb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ err_free:
	kfree_skb(skb);
	return NULL;
}
EXPORT_SYMBOL(vlan_untag);


/*
+2 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
	struct net_bridge_fdb_entry *dst;
	struct net_bridge_mdb_entry *mdst;
	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
	u16 vid = 0;

	rcu_read_lock();
#ifdef CONFIG_BRIDGE_NETFILTER
@@ -45,7 +46,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
	brstats->tx_bytes += skb->len;
	u64_stats_update_end(&brstats->syncp);

	if (!br_allowed_ingress(br, br_get_vlan_info(br), skb))
	if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
		goto out;

	BR_INPUT_SKB_CB(skb)->brdev = dev;
+8 −0
Original line number Diff line number Diff line
@@ -64,6 +64,10 @@ int br_forward_finish(struct sk_buff *skb)

static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
	skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb);
	if (!skb)
		return;

	skb->dev = to->dev;

	if (unlikely(netpoll_tx_running(to->br->dev))) {
@@ -89,6 +93,10 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
		return;
	}

	skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb);
	if (!skb)
		return;

	indev = skb->dev;
	skb->dev = to->dev;
	skb_forward_csum(skb);
+6 −1
Original line number Diff line number Diff line
@@ -45,6 +45,10 @@ static int br_pass_frame_up(struct sk_buff *skb)
		return NET_RX_DROP;
	}

	skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
	if (!skb)
		return NET_RX_DROP;

	indev = skb->dev;
	skb->dev = brdev;

@@ -61,11 +65,12 @@ int br_handle_frame_finish(struct sk_buff *skb)
	struct net_bridge_fdb_entry *dst;
	struct net_bridge_mdb_entry *mdst;
	struct sk_buff *skb2;
	u16 vid = 0;

	if (!p || p->state == BR_STATE_DISABLED)
		goto drop;

	if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb))
	if (!br_allowed_ingress(p->br, nbp_get_vlan_info(p), skb, &vid))
		goto drop;

	/* insert into forwarding database after filtering to avoid spoofing */
+31 −3
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ struct br_ip

struct net_port_vlans {
	u16				port_idx;
	u16				pvid;
	union {
		struct net_bridge_port		*port;
		struct net_bridge		*br;
@@ -554,10 +555,13 @@ static inline void br_mdb_uninit(void)
/* br_vlan.c */
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
extern bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
			       struct sk_buff *skb);
			       struct sk_buff *skb, u16 *vid);
extern bool br_allowed_egress(struct net_bridge *br,
			      const struct net_port_vlans *v,
			      const struct sk_buff *skb);
extern struct sk_buff *br_handle_vlan(struct net_bridge *br,
				      const struct net_port_vlans *v,
				      struct sk_buff *skb);
extern int br_vlan_add(struct net_bridge *br, u16 vid);
extern int br_vlan_delete(struct net_bridge *br, u16 vid);
extern void br_vlan_flush(struct net_bridge *br);
@@ -594,10 +598,23 @@ static inline int br_vlan_get_tag(const struct sk_buff *skb, u16 *vid)

	return err;
}

static inline u16 br_get_pvid(const struct net_port_vlans *v)
{
	/* Return just the VID if it is set, or VLAN_N_VID (invalid vid) if
	 * vid wasn't set
	 */
	smp_rmb();
	return (v->pvid & VLAN_TAG_PRESENT) ?
			(v->pvid & ~VLAN_TAG_PRESENT) :
			VLAN_N_VID;
}

#else
static inline bool br_allowed_ingress(struct net_bridge *br,
				      struct net_port_vlans *v,
				      struct sk_buff *skb)
				      struct sk_buff *skb,
				      u16 *vid)
{
	return true;
}
@@ -609,6 +626,13 @@ static inline bool br_allowed_egress(struct net_bridge *br,
	return true;
}

static inline struct sk_buff *br_handle_vlan(struct net_bridge *br,
					     const struct net_port_vlans *v,
					     struct sk_buff *skb)
{
	return skb;
}

static inline int br_vlan_add(struct net_bridge *br, u16 vid)
{
	return -EOPNOTSUPP;
@@ -648,10 +672,14 @@ static inline struct net_port_vlans *nbp_get_vlan_info(
	return NULL;
}

static inline u16 br_vlan_get_tag(const struct sk_buff *skb)
static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag)
{
	return 0;
}
static inline u16 br_get_pvid(const struct net_port_vlans *v)
{
	return VLAN_N_VID;	/* Returns invalid vid */
}
#endif

/* br_netfilter.c */
Loading