Skip to content

Commit

Permalink
net: dsa: tag_8021q: merge RX and TX VLANs
Browse files Browse the repository at this point in the history
In the old Shared VLAN Learning mode of operation that tag_8021q
previously used for forwarding, we needed to have distinct concepts for
an RX and a TX VLAN.

An RX VLAN could be installed on all ports that were members of a given
bridge, so that autonomous forwarding could still work, while a TX VLAN
was dedicated for precise packet steering, so it just contained the CPU
port and one egress port.

Now that tag_8021q uses Independent VLAN Learning and imprecise RX/TX
all over, those lines have been blurred and we no longer have the need
to do precise TX towards a port that is in a bridge. As for standalone
ports, it is fine to use the same VLAN ID for both RX and TX.

This patch changes the tag_8021q format by shifting the VLAN range it
reserves, and halving it. Previously, our DIR bits were encoding the
VLAN direction (RX/TX) and were set to either 1 or 2. This meant that
tag_8021q reserved 2K VLANs, or 50% of the available range.

Change the DIR bits to a hardcoded value of 3 now, which makes tag_8021q
reserve only 1K VLANs, and a different range now (the last 1K). This is
done so that we leave the old format in place in case we need to return
to it.

In terms of code, the vid_is_dsa_8021q_rxvlan and vid_is_dsa_8021q_txvlan
functions go away. Any vid_is_dsa_8021q is both a TX and an RX VLAN, and
they are no longer distinct. For example, felix which did different
things for different VLAN types, now needs to handle the RX and the TX
logic for the same VLAN.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vladimir Oltean authored and David S. Miller committed Feb 27, 2022
1 parent 08f44db commit 04b67e1
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 193 deletions.
120 changes: 64 additions & 56 deletions drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
#include <net/dsa.h>
#include "felix.h"

static int felix_tag_8021q_rxvlan_add(struct felix *felix, int port, u16 vid,
bool pvid, bool untagged)
/* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that
* the tagger can perform RX source port identification.
*/
static int felix_tag_8021q_vlan_add_rx(struct felix *felix, int port, u16 vid)
{
struct ocelot_vcap_filter *outer_tagging_rule;
struct ocelot *ocelot = &felix->ocelot;
Expand Down Expand Up @@ -64,21 +66,32 @@ static int felix_tag_8021q_rxvlan_add(struct felix *felix, int port, u16 vid,
return err;
}

static int felix_tag_8021q_txvlan_add(struct felix *felix, int port, u16 vid,
bool pvid, bool untagged)
static int felix_tag_8021q_vlan_del_rx(struct felix *felix, int port, u16 vid)
{
struct ocelot_vcap_filter *outer_tagging_rule;
struct ocelot_vcap_block *block_vcap_es0;
struct ocelot *ocelot = &felix->ocelot;

block_vcap_es0 = &ocelot->block[VCAP_ES0];

outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0,
port, false);
if (!outer_tagging_rule)
return -ENOENT;

return ocelot_vcap_filter_del(ocelot, outer_tagging_rule);
}

/* Set up VCAP IS1 rules for stripping the tag_8021q VLAN on TX and VCAP IS2
* rules for steering those tagged packets towards the correct destination port
*/
static int felix_tag_8021q_vlan_add_tx(struct felix *felix, int port, u16 vid)
{
struct ocelot_vcap_filter *untagging_rule, *redirect_rule;
struct ocelot *ocelot = &felix->ocelot;
struct dsa_switch *ds = felix->ds;
int upstream, err;

/* tag_8021q.c assumes we are implementing this via port VLAN
* membership, which we aren't. So we don't need to add any VCAP filter
* for the CPU port.
*/
if (ocelot->ports[port]->is_dsa_8021q_cpu)
return 0;

untagging_rule = kzalloc(sizeof(struct ocelot_vcap_filter), GFP_KERNEL);
if (!untagging_rule)
return -ENOMEM;
Expand Down Expand Up @@ -135,51 +148,14 @@ static int felix_tag_8021q_txvlan_add(struct felix *felix, int port, u16 vid,
return 0;
}

static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid,
u16 flags)
{
bool untagged = flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
struct ocelot *ocelot = ds->priv;

if (vid_is_dsa_8021q_rxvlan(vid))
return felix_tag_8021q_rxvlan_add(ocelot_to_felix(ocelot),
port, vid, pvid, untagged);

if (vid_is_dsa_8021q_txvlan(vid))
return felix_tag_8021q_txvlan_add(ocelot_to_felix(ocelot),
port, vid, pvid, untagged);

return 0;
}

static int felix_tag_8021q_rxvlan_del(struct felix *felix, int port, u16 vid)
{
struct ocelot_vcap_filter *outer_tagging_rule;
struct ocelot_vcap_block *block_vcap_es0;
struct ocelot *ocelot = &felix->ocelot;

block_vcap_es0 = &ocelot->block[VCAP_ES0];

outer_tagging_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_es0,
port, false);
if (!outer_tagging_rule)
return -ENOENT;

return ocelot_vcap_filter_del(ocelot, outer_tagging_rule);
}

static int felix_tag_8021q_txvlan_del(struct felix *felix, int port, u16 vid)
static int felix_tag_8021q_vlan_del_tx(struct felix *felix, int port, u16 vid)
{
struct ocelot_vcap_filter *untagging_rule, *redirect_rule;
struct ocelot_vcap_block *block_vcap_is1;
struct ocelot_vcap_block *block_vcap_is2;
struct ocelot *ocelot = &felix->ocelot;
int err;

if (ocelot->ports[port]->is_dsa_8021q_cpu)
return 0;

block_vcap_is1 = &ocelot->block[VCAP_IS1];
block_vcap_is2 = &ocelot->block[VCAP_IS2];

Expand All @@ -195,22 +171,54 @@ static int felix_tag_8021q_txvlan_del(struct felix *felix, int port, u16 vid)
redirect_rule = ocelot_vcap_block_find_filter_by_id(block_vcap_is2,
port, false);
if (!redirect_rule)
return 0;
return -ENOENT;

return ocelot_vcap_filter_del(ocelot, redirect_rule);
}

static int felix_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid,
u16 flags)
{
struct ocelot *ocelot = ds->priv;
int err;

/* tag_8021q.c assumes we are implementing this via port VLAN
* membership, which we aren't. So we don't need to add any VCAP filter
* for the CPU port.
*/
if (!dsa_is_user_port(ds, port))
return 0;

err = felix_tag_8021q_vlan_add_rx(ocelot_to_felix(ocelot), port, vid);
if (err)
return err;

err = felix_tag_8021q_vlan_add_tx(ocelot_to_felix(ocelot), port, vid);
if (err) {
felix_tag_8021q_vlan_del_rx(ocelot_to_felix(ocelot), port, vid);
return err;
}

return 0;
}

static int felix_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid)
{
struct ocelot *ocelot = ds->priv;
int err;

if (!dsa_is_user_port(ds, port))
return 0;

if (vid_is_dsa_8021q_rxvlan(vid))
return felix_tag_8021q_rxvlan_del(ocelot_to_felix(ocelot),
port, vid);
err = felix_tag_8021q_vlan_del_rx(ocelot_to_felix(ocelot), port, vid);
if (err)
return err;

if (vid_is_dsa_8021q_txvlan(vid))
return felix_tag_8021q_txvlan_del(ocelot_to_felix(ocelot),
port, vid);
err = felix_tag_8021q_vlan_del_tx(ocelot_to_felix(ocelot), port, vid);
if (err) {
felix_tag_8021q_vlan_add_rx(ocelot_to_felix(ocelot), port, vid);
return err;
}

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/dsa/sja1105/sja1105_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2509,7 +2509,7 @@ static int sja1105_bridge_vlan_add(struct dsa_switch *ds, int port,
*/
if (vid_is_dsa_8021q(vlan->vid)) {
NL_SET_ERR_MSG_MOD(extack,
"Range 1024-3071 reserved for dsa_8021q operation");
"Range 3072-4095 reserved for dsa_8021q operation");
return -EBUSY;
}

Expand Down
3 changes: 2 additions & 1 deletion drivers/net/dsa/sja1105/sja1105_vl.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ static u16 sja1105_port_get_tag_8021q_vid(struct dsa_port *dp)
unsigned long bridge_num;

if (!dp->bridge)
return dsa_tag_8021q_rx_vid(dp);
return dsa_tag_8021q_standalone_vid(dp);

bridge_num = dsa_port_bridge_num_get(dp);

Expand Down Expand Up @@ -407,6 +407,7 @@ static int sja1105_init_virtual_links(struct sja1105_private *priv,
vl_lookup[k].vlanid = rule->key.vl.vid;
vl_lookup[k].vlanprior = rule->key.vl.pcp;
} else {
/* FIXME */
struct dsa_port *dp = dsa_to_port(priv->ds, port);
u16 vid = sja1105_port_get_tag_8021q_vid(dp);

Expand Down
8 changes: 1 addition & 7 deletions include/linux/dsa/8021q.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,12 @@ struct net_device *dsa_tag_8021q_find_port_by_vbid(struct net_device *master,

u16 dsa_8021q_bridge_tx_fwd_offload_vid(unsigned int bridge_num);

u16 dsa_tag_8021q_tx_vid(const struct dsa_port *dp);

u16 dsa_tag_8021q_rx_vid(const struct dsa_port *dp);
u16 dsa_tag_8021q_standalone_vid(const struct dsa_port *dp);

int dsa_8021q_rx_switch_id(u16 vid);

int dsa_8021q_rx_source_port(u16 vid);

bool vid_is_dsa_8021q_rxvlan(u16 vid);

bool vid_is_dsa_8021q_txvlan(u16 vid);

bool vid_is_dsa_8021q(u16 vid);

#endif /* _NET_DSA_8021Q_H */
Loading

0 comments on commit 04b67e1

Please sign in to comment.