Skip to content

Commit 75944fd

Browse files
Xiaoliang Yangdavem330
authored andcommitted
net: mscc: ocelot: offload ingress skbedit and vlan actions to VCAP IS1
VCAP IS1 is a VCAP module which can filter on the most common L2/L3/L4 Ethernet keys, and modify the results of the basic QoS classification and VLAN classification based on those flow keys. There are 3 VCAP IS1 lookups, mapped over chains 10000, 11000 and 12000. Currently the driver is hardcoded to use IS1_ACTION_TYPE_NORMAL half keys. Note that the VLAN_MANGLE has been omitted for now. In hardware, the VCAP_IS1_ACT_VID_REPLACE_ENA field replaces the classified VLAN (metadata associated with the frame) and not the VLAN from the header itself. There are currently some issues which need to be addressed when operating in standalone, or in bridge with vlan_filtering=0 modes, because in those cases the switch ports have VLAN awareness disabled, and changing the classified VLAN to anything other than the pvid causes the packets to be dropped. Another issue is that on egress, we expect port tagging to push the classified VLAN, but port tagging is disabled in the modes mentioned above, so although the classified VLAN is replaced, it is not visible in the packet transmitted by the switch. Signed-off-by: Xiaoliang Yang <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1397a2e commit 75944fd

File tree

5 files changed

+226
-0
lines changed

5 files changed

+226
-0
lines changed

drivers/net/dsa/ocelot/felix_vsc9959.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ static const struct vcap_field vsc9959_vcap_is1_actions[] = {
711711
[VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8},
712712
[VCAP_IS1_ACT_PAG_VAL] = { 21, 8},
713713
[VCAP_IS1_ACT_RSV] = { 29, 9},
714+
/* The fields below are incorrectly shifted by 2 in the manual */
714715
[VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1},
715716
[VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12},
716717
[VCAP_IS1_ACT_FID_SEL] = { 51, 2},

drivers/net/ethernet/mscc/ocelot.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ static void ocelot_vcap_enable(struct ocelot *ocelot, int port)
108108
ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA |
109109
ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa),
110110
ANA_PORT_VCAP_S2_CFG, port);
111+
112+
ocelot_write_gix(ocelot, ANA_PORT_VCAP_CFG_S1_ENA,
113+
ANA_PORT_VCAP_CFG, port);
111114
}
112115

113116
static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot)

drivers/net/ethernet/mscc/ocelot_flower.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ static int ocelot_chain_to_lookup(int chain)
5757
return (chain / VCAP_LOOKUP) % 10;
5858
}
5959

60+
/* Caller must ensure this is a valid IS2 chain first,
61+
* by calling ocelot_chain_to_block.
62+
*/
63+
static int ocelot_chain_to_pag(int chain)
64+
{
65+
int lookup = ocelot_chain_to_lookup(chain);
66+
67+
/* calculate PAG value as chain index relative to the first PAG */
68+
return chain - VCAP_IS2_CHAIN(lookup, 0);
69+
}
70+
6071
static bool ocelot_is_goto_target_valid(int goto_target, int chain,
6172
bool ingress)
6273
{
@@ -209,8 +220,52 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f, bool ingress,
209220
filter->action.pol.burst = a->police.burst;
210221
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
211222
break;
223+
case FLOW_ACTION_VLAN_POP:
224+
if (filter->block_id != VCAP_IS1) {
225+
NL_SET_ERR_MSG_MOD(extack,
226+
"VLAN pop action can only be offloaded to VCAP IS1");
227+
return -EOPNOTSUPP;
228+
}
229+
if (filter->goto_target != -1) {
230+
NL_SET_ERR_MSG_MOD(extack,
231+
"Last action must be GOTO");
232+
return -EOPNOTSUPP;
233+
}
234+
filter->action.vlan_pop_cnt_ena = true;
235+
filter->action.vlan_pop_cnt++;
236+
if (filter->action.vlan_pop_cnt > 2) {
237+
NL_SET_ERR_MSG_MOD(extack,
238+
"Cannot pop more than 2 VLAN headers");
239+
return -EOPNOTSUPP;
240+
}
241+
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
242+
break;
243+
case FLOW_ACTION_PRIORITY:
244+
if (filter->block_id != VCAP_IS1) {
245+
NL_SET_ERR_MSG_MOD(extack,
246+
"Priority action can only be offloaded to VCAP IS1");
247+
return -EOPNOTSUPP;
248+
}
249+
if (filter->goto_target != -1) {
250+
NL_SET_ERR_MSG_MOD(extack,
251+
"Last action must be GOTO");
252+
return -EOPNOTSUPP;
253+
}
254+
filter->action.qos_ena = true;
255+
filter->action.qos_val = a->priority;
256+
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
257+
break;
212258
case FLOW_ACTION_GOTO:
213259
filter->goto_target = a->chain_index;
260+
261+
if (filter->block_id == VCAP_IS1 &&
262+
ocelot_chain_to_lookup(chain) == 2) {
263+
int pag = ocelot_chain_to_pag(filter->goto_target);
264+
265+
filter->action.pag_override_mask = 0xff;
266+
filter->action.pag_val = pag;
267+
filter->type = OCELOT_VCAP_FILTER_PAG;
268+
}
214269
break;
215270
default:
216271
NL_SET_ERR_MSG_MOD(extack, "Cannot offload action");
@@ -242,6 +297,7 @@ static int ocelot_flower_parse_key(struct flow_cls_offload *f, bool ingress,
242297
{
243298
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
244299
struct flow_dissector *dissector = rule->match.dissector;
300+
struct netlink_ext_ack *extack = f->common.extack;
245301
u16 proto = ntohs(f->common.protocol);
246302
bool match_protocol = true;
247303

@@ -265,6 +321,13 @@ static int ocelot_flower_parse_key(struct flow_cls_offload *f, bool ingress,
265321
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
266322
struct flow_match_eth_addrs match;
267323

324+
if (filter->block_id == VCAP_IS1 &&
325+
!is_zero_ether_addr(match.mask->dst)) {
326+
NL_SET_ERR_MSG_MOD(extack,
327+
"Key type S1_NORMAL cannot match on destination MAC");
328+
return -EOPNOTSUPP;
329+
}
330+
268331
/* The hw support mac matches only for MAC_ETYPE key,
269332
* therefore if other matches(port, tcp flags, etc) are added
270333
* then just bail out
@@ -318,6 +381,12 @@ static int ocelot_flower_parse_key(struct flow_cls_offload *f, bool ingress,
318381
struct flow_match_ipv4_addrs match;
319382
u8 *tmp;
320383

384+
if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
385+
NL_SET_ERR_MSG_MOD(extack,
386+
"Key type S1_NORMAL cannot match on destination IP");
387+
return -EOPNOTSUPP;
388+
}
389+
321390
flow_rule_match_ipv4_addrs(rule, &match);
322391
tmp = &filter->key.ipv4.sip.value.addr[0];
323392
memcpy(tmp, &match.key->src, 4);

drivers/net/ethernet/mscc/ocelot_vcap.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,140 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
640640
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
641641
}
642642

643+
static void is1_action_set(struct ocelot *ocelot, struct vcap_data *data,
644+
const struct ocelot_vcap_filter *filter)
645+
{
646+
const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
647+
const struct ocelot_vcap_action *a = &filter->action;
648+
649+
vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_REPLACE_ENA,
650+
a->vid_replace_ena);
651+
vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_ADD_VAL, a->vid);
652+
vcap_action_set(vcap, data, VCAP_IS1_ACT_VLAN_POP_CNT_ENA,
653+
a->vlan_pop_cnt_ena);
654+
vcap_action_set(vcap, data, VCAP_IS1_ACT_VLAN_POP_CNT,
655+
a->vlan_pop_cnt);
656+
vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_DEI_ENA, a->pcp_dei_ena);
657+
vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_VAL, a->pcp);
658+
vcap_action_set(vcap, data, VCAP_IS1_ACT_DEI_VAL, a->dei);
659+
vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_ENA, a->qos_ena);
660+
vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_VAL, a->qos_val);
661+
vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_OVERRIDE_MASK,
662+
a->pag_override_mask);
663+
vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_VAL, a->pag_val);
664+
}
665+
666+
static void is1_entry_set(struct ocelot *ocelot, int ix,
667+
struct ocelot_vcap_filter *filter)
668+
{
669+
const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
670+
struct ocelot_vcap_key_vlan *tag = &filter->vlan;
671+
struct ocelot_vcap_u64 payload;
672+
struct vcap_data data;
673+
int row = ix / 2;
674+
u32 type;
675+
676+
memset(&payload, 0, sizeof(payload));
677+
memset(&data, 0, sizeof(data));
678+
679+
/* Read row */
680+
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL);
681+
vcap_cache2entry(ocelot, vcap, &data);
682+
vcap_cache2action(ocelot, vcap, &data);
683+
684+
data.tg_sw = VCAP_TG_HALF;
685+
data.type = IS1_ACTION_TYPE_NORMAL;
686+
vcap_data_offset_get(vcap, &data, ix);
687+
data.tg = (data.tg & ~data.tg_mask);
688+
if (filter->prio != 0)
689+
data.tg |= data.tg_value;
690+
691+
vcap_key_set(vcap, &data, VCAP_IS1_HK_IGR_PORT_MASK, 0,
692+
~filter->ingress_port_mask);
693+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_MC, filter->dmac_mc);
694+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_BC, filter->dmac_bc);
695+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_TAGGED, tag->tagged);
696+
vcap_key_set(vcap, &data, VCAP_IS1_HK_VID,
697+
tag->vid.value, tag->vid.mask);
698+
vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP,
699+
tag->pcp.value[0], tag->pcp.mask[0]);
700+
type = IS1_TYPE_S1_NORMAL;
701+
702+
switch (filter->key_type) {
703+
case OCELOT_VCAP_KEY_ETYPE: {
704+
struct ocelot_vcap_key_etype *etype = &filter->key.etype;
705+
706+
vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L2_SMAC,
707+
etype->smac.value, etype->smac.mask);
708+
vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE,
709+
etype->etype.value, etype->etype.mask);
710+
break;
711+
}
712+
case OCELOT_VCAP_KEY_IPV4: {
713+
struct ocelot_vcap_key_ipv4 *ipv4 = &filter->key.ipv4;
714+
struct ocelot_vcap_udp_tcp *sport = &ipv4->sport;
715+
struct ocelot_vcap_udp_tcp *dport = &ipv4->dport;
716+
enum ocelot_vcap_bit tcp_udp = OCELOT_VCAP_BIT_0;
717+
struct ocelot_vcap_u8 proto = ipv4->proto;
718+
struct ocelot_vcap_ipv4 sip = ipv4->sip;
719+
u32 val, msk;
720+
721+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP_SNAP,
722+
OCELOT_VCAP_BIT_1);
723+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4,
724+
OCELOT_VCAP_BIT_1);
725+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_ETYPE_LEN,
726+
OCELOT_VCAP_BIT_1);
727+
vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L3_IP4_SIP,
728+
sip.value.addr, sip.mask.addr);
729+
730+
val = proto.value[0];
731+
msk = proto.mask[0];
732+
733+
if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) && msk == 0xff)
734+
tcp_udp = OCELOT_VCAP_BIT_1;
735+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP_UDP, tcp_udp);
736+
737+
if (tcp_udp) {
738+
enum ocelot_vcap_bit tcp = OCELOT_VCAP_BIT_0;
739+
740+
if (val == NEXTHDR_TCP)
741+
tcp = OCELOT_VCAP_BIT_1;
742+
743+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP, tcp);
744+
vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_L4_SPORT,
745+
sport);
746+
/* Overloaded field */
747+
vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_ETYPE,
748+
dport);
749+
} else {
750+
/* IPv4 "other" frame */
751+
struct ocelot_vcap_u16 etype = {0};
752+
753+
/* Overloaded field */
754+
etype.value[0] = proto.value[0];
755+
etype.mask[0] = proto.mask[0];
756+
757+
vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE,
758+
etype.value, etype.mask);
759+
}
760+
}
761+
default:
762+
break;
763+
}
764+
vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TYPE,
765+
type ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
766+
767+
is1_action_set(ocelot, &data, filter);
768+
vcap_data_set(data.counter, data.counter_offset,
769+
vcap->counter_width, filter->stats.pkts);
770+
771+
/* Write row */
772+
vcap_entry2cache(ocelot, vcap, &data);
773+
vcap_action2cache(ocelot, vcap, &data);
774+
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
775+
}
776+
643777
static void vcap_entry_get(struct ocelot *ocelot, int ix,
644778
struct ocelot_vcap_filter *filter)
645779
{
@@ -663,6 +797,8 @@ static void vcap_entry_get(struct ocelot *ocelot, int ix,
663797
static void vcap_entry_set(struct ocelot *ocelot, int ix,
664798
struct ocelot_vcap_filter *filter)
665799
{
800+
if (filter->block_id == VCAP_IS1)
801+
return is1_entry_set(ocelot, ix, filter);
666802
if (filter->block_id == VCAP_IS2)
667803
return is2_entry_set(ocelot, ix, filter);
668804
}

drivers/net/ethernet/mscc/ocelot_vcap.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ struct ocelot_vcap_key_ipv4 {
160160
struct ocelot_vcap_key_ipv6 {
161161
struct ocelot_vcap_u8 proto; /* IPv6 protocol */
162162
struct ocelot_vcap_u128 sip; /* IPv6 source (byte 0-7 ignored) */
163+
struct ocelot_vcap_u128 dip; /* IPv6 destination (byte 0-7 ignored) */
163164
enum ocelot_vcap_bit ttl; /* TTL zero */
164165
struct ocelot_vcap_u8 ds;
165166
struct ocelot_vcap_u48 data; /* Not UDP/TCP: IP data */
@@ -185,6 +186,21 @@ enum ocelot_mask_mode {
185186

186187
struct ocelot_vcap_action {
187188
union {
189+
/* VCAP IS1 */
190+
struct {
191+
bool vid_replace_ena;
192+
u16 vid;
193+
bool vlan_pop_cnt_ena;
194+
int vlan_pop_cnt;
195+
bool pcp_dei_ena;
196+
u8 pcp;
197+
u8 dei;
198+
bool qos_ena;
199+
u8 qos_val;
200+
u8 pag_override_mask;
201+
u8 pag_val;
202+
};
203+
188204
/* VCAP IS2 */
189205
struct {
190206
bool cpu_copy_ena;
@@ -217,6 +233,7 @@ struct ocelot_vcap_filter {
217233
int block_id;
218234
int goto_target;
219235
int lookup;
236+
u8 pag;
220237
u16 prio;
221238
u32 id;
222239

0 commit comments

Comments
 (0)