Skip to content

Commit b3f4cd0

Browse files
committed
Merge branch 'sparx5-tc-flower-templates'
Steen Hegelund says: ==================== Add support for TC flower templates in Sparx5 This adds support for the TC template mechanism in the Sparx5 flower filter implementation. Templates are as such handled by the TC framework, but when a template is created (using a chain id) there are by definition no filters on this chain (an error will be returned if there are any). If the templates chain id is one that is represented by a VCAP lookup, then when the template is created, we know that it is safe to use the keys provided in the template to change the keyset configuration for the (port, lookup) combination, if this is needed to improve the match on the template. The original port keyset configuration is captured in the template state information which is kept per port, so that when the template is deleted the port keyset configuration can be restored to its previous setting. The template also provides the protocol parameter which is the basic information that is used to find out which port keyset configuration needs to be changed. The VCAPs and lookups are slightly different when it comes to which keys, keysets and protocol are supported and used for selection, so in some cases a bit of tweaking is needed to find a useful match. This is done by e.g. removing a key that prevents the best matching keyset from being selected. The debugfs output that is provided for a port allows inspection of the currently used keyset in each of the VCAPs lookups. So when a template has been created the debugfs output allows you to verify if the keyset configuration has been changed successfully. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7d8c489 + e1d597e commit b3f4cd0

File tree

8 files changed

+553
-8
lines changed

8 files changed

+553
-8
lines changed

drivers/net/ethernet/microchip/sparx5/sparx5_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ static int sparx5_create_port(struct sparx5 *sparx5,
282282
spx5_port->phylink_pcs.poll = true;
283283
spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops;
284284
spx5_port->is_mrouter = false;
285+
INIT_LIST_HEAD(&spx5_port->tc_templates);
285286
sparx5->ports[config->portno] = spx5_port;
286287

287288
err = sparx5_port_init(sparx5, spx5_port, &config->conf);

drivers/net/ethernet/microchip/sparx5/sparx5_main.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ struct sparx5_port {
192192
u16 ts_id;
193193
struct sk_buff_head tx_skbs;
194194
bool is_mrouter;
195+
struct list_head tc_templates; /* list of TC templates on this port */
195196
};
196197

197198
enum sparx5_core_clockfreq {

drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c

Lines changed: 202 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ struct sparx5_multiple_rules {
2828
struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
2929
};
3030

31+
struct sparx5_tc_flower_template {
32+
struct list_head list; /* for insertion in the list of templates */
33+
int cid; /* chain id */
34+
enum vcap_keyfield_set orig; /* keyset used before the template */
35+
enum vcap_keyfield_set keyset; /* new keyset used by template */
36+
u16 l3_proto; /* protocol specified in the template */
37+
};
38+
3139
static int
3240
sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st)
3341
{
@@ -382,7 +390,7 @@ static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
382390
/* Find the keysets that the rule can use */
383391
matches.keysets = keysets;
384392
matches.max = ARRAY_SIZE(keysets);
385-
if (vcap_rule_find_keysets(vrule, &matches) == 0)
393+
if (!vcap_rule_find_keysets(vrule, &matches))
386394
return -EINVAL;
387395

388396
/* Find the keysets that the port configuration supports */
@@ -996,6 +1004,73 @@ static int sparx5_tc_action_vlan_push(struct vcap_admin *admin,
9961004
return err;
9971005
}
9981006

1007+
/* Remove rule keys that may prevent templates from matching a keyset */
1008+
static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin,
1009+
struct vcap_rule *vrule,
1010+
u16 l3_proto)
1011+
{
1012+
switch (admin->vtype) {
1013+
case VCAP_TYPE_IS0:
1014+
vcap_rule_rem_key(vrule, VCAP_KF_ETYPE);
1015+
switch (l3_proto) {
1016+
case ETH_P_IP:
1017+
break;
1018+
case ETH_P_IPV6:
1019+
vcap_rule_rem_key(vrule, VCAP_KF_IP_SNAP_IS);
1020+
break;
1021+
default:
1022+
break;
1023+
}
1024+
break;
1025+
case VCAP_TYPE_ES2:
1026+
switch (l3_proto) {
1027+
case ETH_P_IP:
1028+
if (vrule->keyset == VCAP_KFS_IP4_OTHER)
1029+
vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1030+
break;
1031+
case ETH_P_IPV6:
1032+
if (vrule->keyset == VCAP_KFS_IP6_STD)
1033+
vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1034+
vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1035+
break;
1036+
default:
1037+
break;
1038+
}
1039+
break;
1040+
case VCAP_TYPE_IS2:
1041+
switch (l3_proto) {
1042+
case ETH_P_IP:
1043+
case ETH_P_IPV6:
1044+
vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1045+
break;
1046+
default:
1047+
break;
1048+
}
1049+
break;
1050+
default:
1051+
break;
1052+
}
1053+
}
1054+
1055+
static bool sparx5_tc_flower_use_template(struct net_device *ndev,
1056+
struct flow_cls_offload *fco,
1057+
struct vcap_admin *admin,
1058+
struct vcap_rule *vrule)
1059+
{
1060+
struct sparx5_port *port = netdev_priv(ndev);
1061+
struct sparx5_tc_flower_template *ftp;
1062+
1063+
list_for_each_entry(ftp, &port->tc_templates, list) {
1064+
if (ftp->cid != fco->common.chain_index)
1065+
continue;
1066+
1067+
vcap_set_rule_set_keyset(vrule, ftp->keyset);
1068+
sparx5_tc_flower_simplify_rule(admin, vrule, ftp->l3_proto);
1069+
return true;
1070+
}
1071+
return false;
1072+
}
1073+
9991074
static int sparx5_tc_flower_replace(struct net_device *ndev,
10001075
struct flow_cls_offload *fco,
10011076
struct vcap_admin *admin,
@@ -1122,12 +1197,14 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
11221197
goto out;
11231198
}
11241199

1125-
err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
1126-
state.l3_proto, &multi);
1127-
if (err) {
1128-
NL_SET_ERR_MSG_MOD(fco->common.extack,
1129-
"No matching port keyset for filter protocol and keys");
1130-
goto out;
1200+
if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) {
1201+
err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
1202+
state.l3_proto, &multi);
1203+
if (err) {
1204+
NL_SET_ERR_MSG_MOD(fco->common.extack,
1205+
"No matching port keyset for filter protocol and keys");
1206+
goto out;
1207+
}
11311208
}
11321209

11331210
/* provide the l3 protocol to guide the keyset selection */
@@ -1259,6 +1336,120 @@ static int sparx5_tc_flower_stats(struct net_device *ndev,
12591336
return err;
12601337
}
12611338

1339+
static int sparx5_tc_flower_template_create(struct net_device *ndev,
1340+
struct flow_cls_offload *fco,
1341+
struct vcap_admin *admin)
1342+
{
1343+
struct sparx5_port *port = netdev_priv(ndev);
1344+
struct vcap_tc_flower_parse_usage state = {
1345+
.fco = fco,
1346+
.l3_proto = ETH_P_ALL,
1347+
.admin = admin,
1348+
};
1349+
struct sparx5_tc_flower_template *ftp;
1350+
struct vcap_keyset_list kslist = {};
1351+
enum vcap_keyfield_set keysets[10];
1352+
struct vcap_control *vctrl;
1353+
struct vcap_rule *vrule;
1354+
int count, err;
1355+
1356+
if (admin->vtype == VCAP_TYPE_ES0) {
1357+
pr_err("%s:%d: %s\n", __func__, __LINE__,
1358+
"VCAP does not support templates");
1359+
return -EINVAL;
1360+
}
1361+
1362+
count = vcap_admin_rule_count(admin, fco->common.chain_index);
1363+
if (count > 0) {
1364+
pr_err("%s:%d: %s\n", __func__, __LINE__,
1365+
"Filters are already present");
1366+
return -EBUSY;
1367+
}
1368+
1369+
ftp = kzalloc(sizeof(*ftp), GFP_KERNEL);
1370+
if (!ftp)
1371+
return -ENOMEM;
1372+
1373+
ftp->cid = fco->common.chain_index;
1374+
ftp->orig = VCAP_KFS_NO_VALUE;
1375+
ftp->keyset = VCAP_KFS_NO_VALUE;
1376+
1377+
vctrl = port->sparx5->vcap_ctrl;
1378+
vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index,
1379+
VCAP_USER_TC, fco->common.prio, 0);
1380+
if (IS_ERR(vrule)) {
1381+
err = PTR_ERR(vrule);
1382+
goto err_rule;
1383+
}
1384+
1385+
state.vrule = vrule;
1386+
state.frule = flow_cls_offload_flow_rule(fco);
1387+
err = sparx5_tc_use_dissectors(&state, admin, vrule);
1388+
if (err) {
1389+
pr_err("%s:%d: key error: %d\n", __func__, __LINE__, err);
1390+
goto out;
1391+
}
1392+
1393+
ftp->l3_proto = state.l3_proto;
1394+
1395+
sparx5_tc_flower_simplify_rule(admin, vrule, state.l3_proto);
1396+
1397+
/* Find the keysets that the rule can use */
1398+
kslist.keysets = keysets;
1399+
kslist.max = ARRAY_SIZE(keysets);
1400+
if (!vcap_rule_find_keysets(vrule, &kslist)) {
1401+
pr_err("%s:%d: %s\n", __func__, __LINE__,
1402+
"Could not find a suitable keyset");
1403+
err = -ENOENT;
1404+
goto out;
1405+
}
1406+
1407+
ftp->keyset = vcap_select_min_rule_keyset(vctrl, admin->vtype, &kslist);
1408+
kslist.cnt = 0;
1409+
sparx5_vcap_set_port_keyset(ndev, admin, fco->common.chain_index,
1410+
state.l3_proto,
1411+
ftp->keyset,
1412+
&kslist);
1413+
1414+
if (kslist.cnt > 0)
1415+
ftp->orig = kslist.keysets[0];
1416+
1417+
/* Store new template */
1418+
list_add_tail(&ftp->list, &port->tc_templates);
1419+
vcap_free_rule(vrule);
1420+
return 0;
1421+
1422+
out:
1423+
vcap_free_rule(vrule);
1424+
err_rule:
1425+
kfree(ftp);
1426+
return err;
1427+
}
1428+
1429+
static int sparx5_tc_flower_template_destroy(struct net_device *ndev,
1430+
struct flow_cls_offload *fco,
1431+
struct vcap_admin *admin)
1432+
{
1433+
struct sparx5_port *port = netdev_priv(ndev);
1434+
struct sparx5_tc_flower_template *ftp, *tmp;
1435+
int err = -ENOENT;
1436+
1437+
/* Rules using the template are removed by the tc framework */
1438+
list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) {
1439+
if (ftp->cid != fco->common.chain_index)
1440+
continue;
1441+
1442+
sparx5_vcap_set_port_keyset(ndev, admin,
1443+
fco->common.chain_index,
1444+
ftp->l3_proto, ftp->orig,
1445+
NULL);
1446+
list_del(&ftp->list);
1447+
kfree(ftp);
1448+
break;
1449+
}
1450+
return err;
1451+
}
1452+
12621453
int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
12631454
bool ingress)
12641455
{
@@ -1282,6 +1473,10 @@ int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
12821473
return sparx5_tc_flower_destroy(ndev, fco, admin);
12831474
case FLOW_CLS_STATS:
12841475
return sparx5_tc_flower_stats(ndev, fco, admin);
1476+
case FLOW_CLS_TMPLT_CREATE:
1477+
return sparx5_tc_flower_template_create(ndev, fco, admin);
1478+
case FLOW_CLS_TMPLT_DESTROY:
1479+
return sparx5_tc_flower_template_destroy(ndev, fco, admin);
12851480
default:
12861481
return -EOPNOTSUPP;
12871482
}

drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static void sparx5_vcap_is2_port_keys(struct sparx5 *sparx5,
198198
out->prf(out->dst, "ip6_std");
199199
break;
200200
case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER:
201-
out->prf(out->dst, "ip4_tcp_udp ipv4_other");
201+
out->prf(out->dst, "ip4_tcp_udp ip4_other");
202202
break;
203203
}
204204
out->prf(out->dst, "\n ipv6_uc: ");

0 commit comments

Comments
 (0)