History

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). ====================

Jakub Kicinski committed 6 years ago

Commit bc081a62 parents bea4b30 82c200b4 files · +119 −6Browse files

Unified · Split

4 files
  1. drivers/net/ethernet/mscc/ocelot.c +14 −1
  2. drivers/net/ethernet/mscc/ocelot_flower.c +26 −3
  3. net/dsa/tag_ocelot.c +34 −0
  4. tools/testing/selftests/drivers/net/ocelot/tc_flower_chains.sh +45 −2
drivers/net/ethernet/mscc/ocelot.c+14−1
@@ -205,8 +205,21 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, · 204 unmodified lines
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+26−3
@@ -142,10 +142,11 @@ ocelot_find_vcap_filter_that_points_at(struct ocelot *ocelot, int chain) · 141 unmodified lines
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, · 114 unmodified lines
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, · 329 unmodified lines
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+34−0
@@ -184,9 +184,14 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, · 183 unmodified lines
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, · 21 unmodified lines
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, · 8 unmodified lines
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+45−2
@@ -166,6 +166,9 @@ setup_prepare() · 165 unmodified lines
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,12 +178,12 @@ setup_prepare() · 3 unmodified lines
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)
@@ -188,6 +191,7 @@ setup_prepare() · 1 unmodified line
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() · 44 unmodified lines
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 · 18 unmodified lines
262304 ALL_TESTS="
263305 test_vlan_pop
264306 test_vlan_push
307+ test_vlan_modify
265308 test_skbedit_priority
266309 "
267310