Skip to content

Commit bc081a6

Browse files
committed
Merge branch 'Offload-tc-vlan-mangle-to-mscc_ocelot-switch'
Vladimir Oltean says: ==================== Offload tc-vlan mangle to mscc_ocelot switch This series offloads one more action to the VCAP IS1 ingress TCAM, which is to change the classified VLAN for packets, according to the VCAP IS1 keys (VLAN, source MAC, source IP, EtherType, etc). ==================== Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents bea4b30 + 82c200b commit bc081a6

4 files changed

Lines changed: 119 additions & 6 deletions

File tree

drivers/net/ethernet/mscc/ocelot.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,21 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
205205
struct ocelot_port *ocelot_port = ocelot->ports[port];
206206
u32 val;
207207

208-
if (switchdev_trans_ph_prepare(trans))
208+
if (switchdev_trans_ph_prepare(trans)) {
209+
struct ocelot_vcap_block *block = &ocelot->block[VCAP_IS1];
210+
struct ocelot_vcap_filter *filter;
211+
212+
list_for_each_entry(filter, &block->rules, list) {
213+
if (filter->ingress_port_mask & BIT(port) &&
214+
filter->action.vid_replace_ena) {
215+
dev_err(ocelot->dev,
216+
"Cannot change VLAN state with vlan modify rules active\n");
217+
return -EBUSY;
218+
}
219+
}
220+
209221
return 0;
222+
}
210223

211224
ocelot_port->vlan_aware = vlan_aware;
212225

drivers/net/ethernet/mscc/ocelot_flower.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,11 @@ ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain)
142142
return NULL;
143143
}
144144

145-
static int ocelot_flower_parse_action(struct ocelot *ocelot, bool ingress,
146-
struct flow_cls_offload *f,
145+
static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
146+
bool ingress, struct flow_cls_offload *f,
147147
struct ocelot_vcap_filter *filter)
148148
{
149+
struct ocelot_port *ocelot_port = ocelot->ports[port];
149150
struct netlink_ext_ack *extack = f->common.extack;
150151
bool allow_missing_goto_target = false;
151152
const struct flow_action_entry *a;
@@ -266,6 +267,28 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, bool ingress,
266267
}
267268
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
268269
break;
270+
case FLOW_ACTION_VLAN_MANGLE:
271+
if (filter->block_id != VCAP_IS1) {
272+
NL_SET_ERR_MSG_MOD(extack,
273+
"VLAN modify action can only be offloaded to VCAP IS1");
274+
return -EOPNOTSUPP;
275+
}
276+
if (filter->goto_target != -1) {
277+
NL_SET_ERR_MSG_MOD(extack,
278+
"Last action must be GOTO");
279+
return -EOPNOTSUPP;
280+
}
281+
if (!ocelot_port->vlan_aware) {
282+
NL_SET_ERR_MSG_MOD(extack,
283+
"Can only modify VLAN under VLAN aware bridge");
284+
return -EOPNOTSUPP;
285+
}
286+
filter->action.vid_replace_ena = true;
287+
filter->action.pcp_dei_ena = true;
288+
filter->action.vid = a->vlan.vid;
289+
filter->action.pcp = a->vlan.prio;
290+
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
291+
break;
269292
case FLOW_ACTION_PRIORITY:
270293
if (filter->block_id != VCAP_IS1) {
271294
NL_SET_ERR_MSG_MOD(extack,
@@ -601,7 +624,7 @@ static int ocelot_flower_parse(struct ocelot *ocelot, int port, bool ingress,
601624
filter->prio = f->common.prio;
602625
filter->id = f->cookie;
603626

604-
ret = ocelot_flower_parse_action(ocelot, ingress, f, filter);
627+
ret = ocelot_flower_parse_action(ocelot, port, ingress, f, filter);
605628
if (ret)
606629
return ret;
607630

net/dsa/tag_ocelot.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,14 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
184184
struct net_device *netdev,
185185
struct packet_type *pt)
186186
{
187+
struct dsa_port *cpu_dp = netdev->dsa_ptr;
188+
struct dsa_switch *ds = cpu_dp->ds;
189+
struct ocelot *ocelot = ds->priv;
187190
u64 src_port, qos_class;
191+
u64 vlan_tci, tag_type;
188192
u8 *start = skb->data;
189193
u8 *extraction;
194+
u16 vlan_tpid;
190195

191196
/* Revert skb->data by the amount consumed by the DSA master,
192197
* so it points to the beginning of the frame.
@@ -214,6 +219,8 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
214219

215220
packing(extraction, &src_port, 46, 43, OCELOT_TAG_LEN, UNPACK, 0);
216221
packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
222+
packing(extraction, &tag_type, 16, 16, OCELOT_TAG_LEN, UNPACK, 0);
223+
packing(extraction, &vlan_tci, 15, 0, OCELOT_TAG_LEN, UNPACK, 0);
217224

218225
skb->dev = dsa_master_find_slave(netdev, 0, src_port);
219226
if (!skb->dev)
@@ -228,6 +235,33 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
228235
skb->offload_fwd_mark = 1;
229236
skb->priority = qos_class;
230237

238+
/* Ocelot switches copy frames unmodified to the CPU. However, it is
239+
* possible for the user to request a VLAN modification through
240+
* VCAP_IS1_ACT_VID_REPLACE_ENA. In this case, what will happen is that
241+
* the VLAN ID field from the Extraction Header gets updated, but the
242+
* 802.1Q header does not (the classified VLAN only becomes visible on
243+
* egress through the "port tag" of front-panel ports).
244+
* So, for traffic extracted by the CPU, we want to pick up the
245+
* classified VLAN and manually replace the existing 802.1Q header from
246+
* the packet with it, so that the operating system is always up to
247+
* date with the result of tc-vlan actions.
248+
* NOTE: In VLAN-unaware mode, we don't want to do that, we want the
249+
* frame to remain unmodified, because the classified VLAN is always
250+
* equal to the pvid of the ingress port and should not be used for
251+
* processing.
252+
*/
253+
vlan_tpid = tag_type ? ETH_P_8021AD : ETH_P_8021Q;
254+
255+
if (ocelot->ports[src_port]->vlan_aware &&
256+
eth_hdr(skb)->h_proto == htons(vlan_tpid)) {
257+
u16 dummy_vlan_tci;
258+
259+
skb_push_rcsum(skb, ETH_HLEN);
260+
__skb_vlan_pop(skb, &dummy_vlan_tci);
261+
skb_pull_rcsum(skb, ETH_HLEN);
262+
__vlan_hwaccel_put_tag(skb, htons(vlan_tpid), vlan_tci);
263+
}
264+
231265
return skb;
232266
}
233267

tools/testing/selftests/drivers/net/ocelot/tc_flower_chains.sh

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ setup_prepare()
166166
ip link add link $eth3 name $eth3.100 type vlan id 100
167167
ip link set $eth3.100 up
168168

169+
ip link add link $eth3 name $eth3.200 type vlan id 200
170+
ip link set $eth3.200 up
171+
169172
tc filter add dev $eth0 ingress chain $(IS1 1) pref 1 \
170173
protocol 802.1Q flower skip_sw vlan_id 100 \
171174
action vlan pop \
@@ -175,19 +178,20 @@ setup_prepare()
175178
flower skip_sw indev $eth1 \
176179
action vlan push protocol 802.1Q id 100
177180

178-
tc filter add dev $eth0 ingress chain $(IS1 0) \
181+
tc filter add dev $eth0 ingress chain $(IS1 0) pref 2 \
179182
protocol ipv4 flower skip_sw src_ip 10.1.1.2 \
180183
action skbedit priority 7 \
181184
action goto chain $(IS1 1)
182185

183-
tc filter add dev $eth0 ingress chain $(IS2 0 0) \
186+
tc filter add dev $eth0 ingress chain $(IS2 0 0) pref 1 \
184187
protocol ipv4 flower skip_sw ip_proto udp dst_port 5201 \
185188
action police rate 50mbit burst 64k \
186189
action goto chain $(IS2 1 0)
187190
}
188191

189192
cleanup()
190193
{
194+
ip link del $eth3.200
191195
ip link del $eth3.100
192196
tc qdisc del dev $eth0 clsact
193197
ip link del br0
@@ -238,6 +242,44 @@ test_vlan_push()
238242
tcpdump_cleanup
239243
}
240244

245+
test_vlan_modify()
246+
{
247+
printf "Testing VLAN modification.. "
248+
249+
ip link set br0 type bridge vlan_filtering 1
250+
bridge vlan add dev $eth0 vid 200
251+
bridge vlan add dev $eth0 vid 300
252+
bridge vlan add dev $eth1 vid 300
253+
254+
tc filter add dev $eth0 ingress chain $(IS1 2) pref 3 \
255+
protocol 802.1Q flower skip_sw vlan_id 200 \
256+
action vlan modify id 300 \
257+
action goto chain $(IS2 0 0)
258+
259+
tcpdump_start $eth2
260+
261+
$MZ $eth3.200 -q -c 1 -p 64 -a $eth3_mac -b $eth2_mac -t ip
262+
263+
sleep 1
264+
265+
tcpdump_stop
266+
267+
if tcpdump_show | grep -q "$eth3_mac > $eth2_mac, .* vlan 300"; then
268+
echo "OK"
269+
else
270+
echo "FAIL"
271+
fi
272+
273+
tcpdump_cleanup
274+
275+
tc filter del dev $eth0 ingress chain $(IS1 2) pref 3
276+
277+
bridge vlan del dev $eth0 vid 200
278+
bridge vlan del dev $eth0 vid 300
279+
bridge vlan del dev $eth1 vid 300
280+
ip link set br0 type bridge vlan_filtering 0
281+
}
282+
241283
test_skbedit_priority()
242284
{
243285
local num_pkts=100
@@ -262,6 +304,7 @@ trap cleanup EXIT
262304
ALL_TESTS="
263305
test_vlan_pop
264306
test_vlan_push
307+
test_vlan_modify
265308
test_skbedit_priority
266309
"
267310

0 commit comments

Comments
 (0)