Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <davem@davemloft.net>

+553 -8
+1
drivers/net/ethernet/microchip/sparx5/sparx5_main.c
··· 282 282 spx5_port->phylink_pcs.poll = true; 283 283 spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops; 284 284 spx5_port->is_mrouter = false; 285 + INIT_LIST_HEAD(&spx5_port->tc_templates); 285 286 sparx5->ports[config->portno] = spx5_port; 286 287 287 288 err = sparx5_port_init(sparx5, spx5_port, &config->conf);
+1
drivers/net/ethernet/microchip/sparx5/sparx5_main.h
··· 192 192 u16 ts_id; 193 193 struct sk_buff_head tx_skbs; 194 194 bool is_mrouter; 195 + struct list_head tc_templates; /* list of TC templates on this port */ 195 196 }; 196 197 197 198 enum sparx5_core_clockfreq {
+202 -7
drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
··· 28 28 struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE]; 29 29 }; 30 30 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 + 31 39 static int 32 40 sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st) 33 41 { ··· 390 382 /* Find the keysets that the rule can use */ 391 383 matches.keysets = keysets; 392 384 matches.max = ARRAY_SIZE(keysets); 393 - if (vcap_rule_find_keysets(vrule, &matches) == 0) 385 + if (!vcap_rule_find_keysets(vrule, &matches)) 394 386 return -EINVAL; 395 387 396 388 /* Find the keysets that the port configuration supports */ ··· 1004 996 return err; 1005 997 } 1006 998 999 + /* Remove rule keys that may prevent templates from matching a keyset */ 1000 + static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin, 1001 + struct vcap_rule *vrule, 1002 + u16 l3_proto) 1003 + { 1004 + switch (admin->vtype) { 1005 + case VCAP_TYPE_IS0: 1006 + vcap_rule_rem_key(vrule, VCAP_KF_ETYPE); 1007 + switch (l3_proto) { 1008 + case ETH_P_IP: 1009 + break; 1010 + case ETH_P_IPV6: 1011 + vcap_rule_rem_key(vrule, VCAP_KF_IP_SNAP_IS); 1012 + break; 1013 + default: 1014 + break; 1015 + } 1016 + break; 1017 + case VCAP_TYPE_ES2: 1018 + switch (l3_proto) { 1019 + case ETH_P_IP: 1020 + if (vrule->keyset == VCAP_KFS_IP4_OTHER) 1021 + vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS); 1022 + break; 1023 + case ETH_P_IPV6: 1024 + if (vrule->keyset == VCAP_KFS_IP6_STD) 1025 + vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS); 1026 + vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS); 1027 + break; 1028 + default: 1029 + break; 1030 + } 1031 + break; 1032 + case VCAP_TYPE_IS2: 1033 + switch (l3_proto) { 1034 + case ETH_P_IP: 1035 + case ETH_P_IPV6: 1036 + vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS); 1037 + break; 1038 + default: 1039 + break; 1040 + } 1041 + break; 1042 + default: 1043 + break; 1044 + } 1045 + } 1046 + 1047 + static bool sparx5_tc_flower_use_template(struct net_device *ndev, 1048 + struct flow_cls_offload *fco, 1049 + struct vcap_admin *admin, 1050 + struct vcap_rule *vrule) 1051 + { 1052 + struct sparx5_port *port = netdev_priv(ndev); 1053 + struct sparx5_tc_flower_template *ftp; 1054 + 1055 + list_for_each_entry(ftp, &port->tc_templates, list) { 1056 + if (ftp->cid != fco->common.chain_index) 1057 + continue; 1058 + 1059 + vcap_set_rule_set_keyset(vrule, ftp->keyset); 1060 + sparx5_tc_flower_simplify_rule(admin, vrule, ftp->l3_proto); 1061 + return true; 1062 + } 1063 + return false; 1064 + } 1065 + 1007 1066 static int sparx5_tc_flower_replace(struct net_device *ndev, 1008 1067 struct flow_cls_offload *fco, 1009 1068 struct vcap_admin *admin, ··· 1197 1122 goto out; 1198 1123 } 1199 1124 1200 - err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, 1201 - state.l3_proto, &multi); 1202 - if (err) { 1203 - NL_SET_ERR_MSG_MOD(fco->common.extack, 1204 - "No matching port keyset for filter protocol and keys"); 1205 - goto out; 1125 + if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) { 1126 + err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, 1127 + state.l3_proto, &multi); 1128 + if (err) { 1129 + NL_SET_ERR_MSG_MOD(fco->common.extack, 1130 + "No matching port keyset for filter protocol and keys"); 1131 + goto out; 1132 + } 1206 1133 } 1207 1134 1208 1135 /* provide the l3 protocol to guide the keyset selection */ ··· 1336 1259 return err; 1337 1260 } 1338 1261 1262 + static int sparx5_tc_flower_template_create(struct net_device *ndev, 1263 + struct flow_cls_offload *fco, 1264 + struct vcap_admin *admin) 1265 + { 1266 + struct sparx5_port *port = netdev_priv(ndev); 1267 + struct vcap_tc_flower_parse_usage state = { 1268 + .fco = fco, 1269 + .l3_proto = ETH_P_ALL, 1270 + .admin = admin, 1271 + }; 1272 + struct sparx5_tc_flower_template *ftp; 1273 + struct vcap_keyset_list kslist = {}; 1274 + enum vcap_keyfield_set keysets[10]; 1275 + struct vcap_control *vctrl; 1276 + struct vcap_rule *vrule; 1277 + int count, err; 1278 + 1279 + if (admin->vtype == VCAP_TYPE_ES0) { 1280 + pr_err("%s:%d: %s\n", __func__, __LINE__, 1281 + "VCAP does not support templates"); 1282 + return -EINVAL; 1283 + } 1284 + 1285 + count = vcap_admin_rule_count(admin, fco->common.chain_index); 1286 + if (count > 0) { 1287 + pr_err("%s:%d: %s\n", __func__, __LINE__, 1288 + "Filters are already present"); 1289 + return -EBUSY; 1290 + } 1291 + 1292 + ftp = kzalloc(sizeof(*ftp), GFP_KERNEL); 1293 + if (!ftp) 1294 + return -ENOMEM; 1295 + 1296 + ftp->cid = fco->common.chain_index; 1297 + ftp->orig = VCAP_KFS_NO_VALUE; 1298 + ftp->keyset = VCAP_KFS_NO_VALUE; 1299 + 1300 + vctrl = port->sparx5->vcap_ctrl; 1301 + vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, 1302 + VCAP_USER_TC, fco->common.prio, 0); 1303 + if (IS_ERR(vrule)) { 1304 + err = PTR_ERR(vrule); 1305 + goto err_rule; 1306 + } 1307 + 1308 + state.vrule = vrule; 1309 + state.frule = flow_cls_offload_flow_rule(fco); 1310 + err = sparx5_tc_use_dissectors(&state, admin, vrule); 1311 + if (err) { 1312 + pr_err("%s:%d: key error: %d\n", __func__, __LINE__, err); 1313 + goto out; 1314 + } 1315 + 1316 + ftp->l3_proto = state.l3_proto; 1317 + 1318 + sparx5_tc_flower_simplify_rule(admin, vrule, state.l3_proto); 1319 + 1320 + /* Find the keysets that the rule can use */ 1321 + kslist.keysets = keysets; 1322 + kslist.max = ARRAY_SIZE(keysets); 1323 + if (!vcap_rule_find_keysets(vrule, &kslist)) { 1324 + pr_err("%s:%d: %s\n", __func__, __LINE__, 1325 + "Could not find a suitable keyset"); 1326 + err = -ENOENT; 1327 + goto out; 1328 + } 1329 + 1330 + ftp->keyset = vcap_select_min_rule_keyset(vctrl, admin->vtype, &kslist); 1331 + kslist.cnt = 0; 1332 + sparx5_vcap_set_port_keyset(ndev, admin, fco->common.chain_index, 1333 + state.l3_proto, 1334 + ftp->keyset, 1335 + &kslist); 1336 + 1337 + if (kslist.cnt > 0) 1338 + ftp->orig = kslist.keysets[0]; 1339 + 1340 + /* Store new template */ 1341 + list_add_tail(&ftp->list, &port->tc_templates); 1342 + vcap_free_rule(vrule); 1343 + return 0; 1344 + 1345 + out: 1346 + vcap_free_rule(vrule); 1347 + err_rule: 1348 + kfree(ftp); 1349 + return err; 1350 + } 1351 + 1352 + static int sparx5_tc_flower_template_destroy(struct net_device *ndev, 1353 + struct flow_cls_offload *fco, 1354 + struct vcap_admin *admin) 1355 + { 1356 + struct sparx5_port *port = netdev_priv(ndev); 1357 + struct sparx5_tc_flower_template *ftp, *tmp; 1358 + int err = -ENOENT; 1359 + 1360 + /* Rules using the template are removed by the tc framework */ 1361 + list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) { 1362 + if (ftp->cid != fco->common.chain_index) 1363 + continue; 1364 + 1365 + sparx5_vcap_set_port_keyset(ndev, admin, 1366 + fco->common.chain_index, 1367 + ftp->l3_proto, ftp->orig, 1368 + NULL); 1369 + list_del(&ftp->list); 1370 + kfree(ftp); 1371 + break; 1372 + } 1373 + return err; 1374 + } 1375 + 1339 1376 int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, 1340 1377 bool ingress) 1341 1378 { ··· 1473 1282 return sparx5_tc_flower_destroy(ndev, fco, admin); 1474 1283 case FLOW_CLS_STATS: 1475 1284 return sparx5_tc_flower_stats(ndev, fco, admin); 1285 + case FLOW_CLS_TMPLT_CREATE: 1286 + return sparx5_tc_flower_template_create(ndev, fco, admin); 1287 + case FLOW_CLS_TMPLT_DESTROY: 1288 + return sparx5_tc_flower_template_destroy(ndev, fco, admin); 1476 1289 default: 1477 1290 return -EOPNOTSUPP; 1478 1291 }
+1 -1
drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c
··· 198 198 out->prf(out->dst, "ip6_std"); 199 199 break; 200 200 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"); 202 202 break; 203 203 } 204 204 out->prf(out->dst, "\n ipv6_uc: ");
+270
drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
··· 1519 1519 .port_info = sparx5_port_info, 1520 1520 }; 1521 1521 1522 + static u32 sparx5_vcap_is0_keyset_to_etype_ps(enum vcap_keyfield_set keyset) 1523 + { 1524 + switch (keyset) { 1525 + case VCAP_KFS_NORMAL_7TUPLE: 1526 + return VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE; 1527 + case VCAP_KFS_NORMAL_5TUPLE_IP4: 1528 + return VCAP_IS0_PS_ETYPE_NORMAL_5TUPLE_IP4; 1529 + default: 1530 + return VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE; 1531 + } 1532 + } 1533 + 1534 + static void sparx5_vcap_is0_set_port_keyset(struct net_device *ndev, int lookup, 1535 + enum vcap_keyfield_set keyset, 1536 + int l3_proto) 1537 + { 1538 + struct sparx5_port *port = netdev_priv(ndev); 1539 + struct sparx5 *sparx5 = port->sparx5; 1540 + int portno = port->portno; 1541 + u32 value; 1542 + 1543 + switch (l3_proto) { 1544 + case ETH_P_IP: 1545 + value = sparx5_vcap_is0_keyset_to_etype_ps(keyset); 1546 + spx5_rmw(ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL_SET(value), 1547 + ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL, 1548 + sparx5, 1549 + ANA_CL_ADV_CL_CFG(portno, lookup)); 1550 + break; 1551 + case ETH_P_IPV6: 1552 + value = sparx5_vcap_is0_keyset_to_etype_ps(keyset); 1553 + spx5_rmw(ANA_CL_ADV_CL_CFG_IP6_CLM_KEY_SEL_SET(value), 1554 + ANA_CL_ADV_CL_CFG_IP6_CLM_KEY_SEL, 1555 + sparx5, 1556 + ANA_CL_ADV_CL_CFG(portno, lookup)); 1557 + break; 1558 + default: 1559 + value = sparx5_vcap_is0_keyset_to_etype_ps(keyset); 1560 + spx5_rmw(ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_SET(value), 1561 + ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL, 1562 + sparx5, 1563 + ANA_CL_ADV_CL_CFG(portno, lookup)); 1564 + break; 1565 + } 1566 + } 1567 + 1568 + static u32 sparx5_vcap_is2_keyset_to_arp_ps(enum vcap_keyfield_set keyset) 1569 + { 1570 + switch (keyset) { 1571 + case VCAP_KFS_ARP: 1572 + return VCAP_IS2_PS_ARP_ARP; 1573 + default: 1574 + return VCAP_IS2_PS_ARP_MAC_ETYPE; 1575 + } 1576 + } 1577 + 1578 + static u32 sparx5_vcap_is2_keyset_to_ipv4_ps(enum vcap_keyfield_set keyset) 1579 + { 1580 + switch (keyset) { 1581 + case VCAP_KFS_MAC_ETYPE: 1582 + return VCAP_IS2_PS_IPV4_UC_MAC_ETYPE; 1583 + case VCAP_KFS_IP4_OTHER: 1584 + case VCAP_KFS_IP4_TCP_UDP: 1585 + return VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER; 1586 + case VCAP_KFS_IP_7TUPLE: 1587 + return VCAP_IS2_PS_IPV4_UC_IP_7TUPLE; 1588 + default: 1589 + return VCAP_KFS_NO_VALUE; 1590 + } 1591 + } 1592 + 1593 + static u32 sparx5_vcap_is2_keyset_to_ipv6_uc_ps(enum vcap_keyfield_set keyset) 1594 + { 1595 + switch (keyset) { 1596 + case VCAP_KFS_MAC_ETYPE: 1597 + return VCAP_IS2_PS_IPV6_UC_MAC_ETYPE; 1598 + case VCAP_KFS_IP4_OTHER: 1599 + case VCAP_KFS_IP4_TCP_UDP: 1600 + return VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER; 1601 + case VCAP_KFS_IP_7TUPLE: 1602 + return VCAP_IS2_PS_IPV6_UC_IP_7TUPLE; 1603 + default: 1604 + return VCAP_KFS_NO_VALUE; 1605 + } 1606 + } 1607 + 1608 + static u32 sparx5_vcap_is2_keyset_to_ipv6_mc_ps(enum vcap_keyfield_set keyset) 1609 + { 1610 + switch (keyset) { 1611 + case VCAP_KFS_MAC_ETYPE: 1612 + return VCAP_IS2_PS_IPV6_MC_MAC_ETYPE; 1613 + case VCAP_KFS_IP4_OTHER: 1614 + case VCAP_KFS_IP4_TCP_UDP: 1615 + return VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER; 1616 + case VCAP_KFS_IP_7TUPLE: 1617 + return VCAP_IS2_PS_IPV6_MC_IP_7TUPLE; 1618 + default: 1619 + return VCAP_KFS_NO_VALUE; 1620 + } 1621 + } 1622 + 1623 + static void sparx5_vcap_is2_set_port_keyset(struct net_device *ndev, int lookup, 1624 + enum vcap_keyfield_set keyset, 1625 + int l3_proto) 1626 + { 1627 + struct sparx5_port *port = netdev_priv(ndev); 1628 + struct sparx5 *sparx5 = port->sparx5; 1629 + int portno = port->portno; 1630 + u32 value; 1631 + 1632 + switch (l3_proto) { 1633 + case ETH_P_ARP: 1634 + value = sparx5_vcap_is2_keyset_to_arp_ps(keyset); 1635 + spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(value), 1636 + ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL, 1637 + sparx5, 1638 + ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 1639 + break; 1640 + case ETH_P_IP: 1641 + value = sparx5_vcap_is2_keyset_to_ipv4_ps(keyset); 1642 + spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(value), 1643 + ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL, 1644 + sparx5, 1645 + ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 1646 + spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(value), 1647 + ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL, 1648 + sparx5, 1649 + ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 1650 + break; 1651 + case ETH_P_IPV6: 1652 + value = sparx5_vcap_is2_keyset_to_ipv6_uc_ps(keyset); 1653 + spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(value), 1654 + ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL, 1655 + sparx5, 1656 + ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 1657 + value = sparx5_vcap_is2_keyset_to_ipv6_mc_ps(keyset); 1658 + spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(value), 1659 + ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL, 1660 + sparx5, 1661 + ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 1662 + break; 1663 + default: 1664 + value = VCAP_IS2_PS_NONETH_MAC_ETYPE; 1665 + spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(value), 1666 + ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL, 1667 + sparx5, 1668 + ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 1669 + break; 1670 + } 1671 + } 1672 + 1673 + static u32 sparx5_vcap_es2_keyset_to_arp_ps(enum vcap_keyfield_set keyset) 1674 + { 1675 + switch (keyset) { 1676 + case VCAP_KFS_ARP: 1677 + return VCAP_ES2_PS_ARP_ARP; 1678 + default: 1679 + return VCAP_ES2_PS_ARP_MAC_ETYPE; 1680 + } 1681 + } 1682 + 1683 + static u32 sparx5_vcap_es2_keyset_to_ipv4_ps(enum vcap_keyfield_set keyset) 1684 + { 1685 + switch (keyset) { 1686 + case VCAP_KFS_MAC_ETYPE: 1687 + return VCAP_ES2_PS_IPV4_MAC_ETYPE; 1688 + case VCAP_KFS_IP_7TUPLE: 1689 + return VCAP_ES2_PS_IPV4_IP_7TUPLE; 1690 + case VCAP_KFS_IP4_TCP_UDP: 1691 + return VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER; 1692 + case VCAP_KFS_IP4_OTHER: 1693 + return VCAP_ES2_PS_IPV4_IP4_OTHER; 1694 + default: 1695 + return VCAP_ES2_PS_IPV4_MAC_ETYPE; 1696 + } 1697 + } 1698 + 1699 + static u32 sparx5_vcap_es2_keyset_to_ipv6_ps(enum vcap_keyfield_set keyset) 1700 + { 1701 + switch (keyset) { 1702 + case VCAP_KFS_MAC_ETYPE: 1703 + return VCAP_ES2_PS_IPV6_MAC_ETYPE; 1704 + case VCAP_KFS_IP4_TCP_UDP: 1705 + case VCAP_KFS_IP4_OTHER: 1706 + return VCAP_ES2_PS_IPV6_IP4_DOWNGRADE; 1707 + case VCAP_KFS_IP_7TUPLE: 1708 + return VCAP_ES2_PS_IPV6_IP_7TUPLE; 1709 + case VCAP_KFS_IP6_STD: 1710 + return VCAP_ES2_PS_IPV6_IP6_STD; 1711 + default: 1712 + return VCAP_ES2_PS_IPV6_MAC_ETYPE; 1713 + } 1714 + } 1715 + 1716 + static void sparx5_vcap_es2_set_port_keyset(struct net_device *ndev, int lookup, 1717 + enum vcap_keyfield_set keyset, 1718 + int l3_proto) 1719 + { 1720 + struct sparx5_port *port = netdev_priv(ndev); 1721 + struct sparx5 *sparx5 = port->sparx5; 1722 + int portno = port->portno; 1723 + u32 value; 1724 + 1725 + switch (l3_proto) { 1726 + case ETH_P_IP: 1727 + value = sparx5_vcap_es2_keyset_to_ipv4_ps(keyset); 1728 + spx5_rmw(EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_SET(value), 1729 + EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL, 1730 + sparx5, 1731 + EACL_VCAP_ES2_KEY_SEL(portno, lookup)); 1732 + break; 1733 + case ETH_P_IPV6: 1734 + value = sparx5_vcap_es2_keyset_to_ipv6_ps(keyset); 1735 + spx5_rmw(EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_SET(value), 1736 + EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL, 1737 + sparx5, 1738 + EACL_VCAP_ES2_KEY_SEL(portno, lookup)); 1739 + break; 1740 + case ETH_P_ARP: 1741 + value = sparx5_vcap_es2_keyset_to_arp_ps(keyset); 1742 + spx5_rmw(EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_SET(value), 1743 + EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL, 1744 + sparx5, 1745 + EACL_VCAP_ES2_KEY_SEL(portno, lookup)); 1746 + break; 1747 + } 1748 + } 1749 + 1750 + /* Change the port keyset for the lookup and protocol */ 1751 + void sparx5_vcap_set_port_keyset(struct net_device *ndev, 1752 + struct vcap_admin *admin, 1753 + int cid, 1754 + u16 l3_proto, 1755 + enum vcap_keyfield_set keyset, 1756 + struct vcap_keyset_list *orig) 1757 + { 1758 + struct sparx5_port *port; 1759 + int lookup; 1760 + 1761 + switch (admin->vtype) { 1762 + case VCAP_TYPE_IS0: 1763 + lookup = sparx5_vcap_is0_cid_to_lookup(cid); 1764 + if (orig) 1765 + sparx5_vcap_is0_get_port_keysets(ndev, lookup, orig, 1766 + l3_proto); 1767 + sparx5_vcap_is0_set_port_keyset(ndev, lookup, keyset, l3_proto); 1768 + break; 1769 + case VCAP_TYPE_IS2: 1770 + lookup = sparx5_vcap_is2_cid_to_lookup(cid); 1771 + if (orig) 1772 + sparx5_vcap_is2_get_port_keysets(ndev, lookup, orig, 1773 + l3_proto); 1774 + sparx5_vcap_is2_set_port_keyset(ndev, lookup, keyset, l3_proto); 1775 + break; 1776 + case VCAP_TYPE_ES0: 1777 + break; 1778 + case VCAP_TYPE_ES2: 1779 + lookup = sparx5_vcap_es2_cid_to_lookup(cid); 1780 + if (orig) 1781 + sparx5_vcap_es2_get_port_keysets(ndev, lookup, orig, 1782 + l3_proto); 1783 + sparx5_vcap_es2_set_port_keyset(ndev, lookup, keyset, l3_proto); 1784 + break; 1785 + default: 1786 + port = netdev_priv(ndev); 1787 + sparx5_vcap_type_err(port->sparx5, admin, __func__); 1788 + break; 1789 + } 1790 + } 1791 + 1522 1792 /* Enable IS0 lookups per port and set the keyset generation */ 1523 1793 static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5, 1524 1794 struct vcap_admin *admin)
+6
drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h
··· 195 195 u16 l3_proto, 196 196 struct vcap_keyset_list *kslist); 197 197 198 + /* Change the port keyset for the lookup and protocol */ 199 + void sparx5_vcap_set_port_keyset(struct net_device *ndev, 200 + struct vcap_admin *admin, int cid, 201 + u16 l3_proto, enum vcap_keyfield_set keyset, 202 + struct vcap_keyset_list *orig); 203 + 198 204 /* Check if the ethertype is supported by the vcap port classification */ 199 205 bool sparx5_vcap_is_known_etype(struct vcap_admin *admin, u16 etype); 200 206
+61
drivers/net/ethernet/microchip/vcap/vcap_api.c
··· 976 976 } 977 977 EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie); 978 978 979 + /* Get number of rules in a vcap instance lookup chain id range */ 980 + int vcap_admin_rule_count(struct vcap_admin *admin, int cid) 981 + { 982 + int max_cid = roundup(cid + 1, VCAP_CID_LOOKUP_SIZE); 983 + int min_cid = rounddown(cid, VCAP_CID_LOOKUP_SIZE); 984 + struct vcap_rule_internal *elem; 985 + int count = 0; 986 + 987 + list_for_each_entry(elem, &admin->rules, list) { 988 + mutex_lock(&admin->lock); 989 + if (elem->data.vcap_chain_id >= min_cid && 990 + elem->data.vcap_chain_id < max_cid) 991 + ++count; 992 + mutex_unlock(&admin->lock); 993 + } 994 + return count; 995 + } 996 + EXPORT_SYMBOL_GPL(vcap_admin_rule_count); 997 + 979 998 /* Make a copy of the rule, shallow or full */ 980 999 static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri, 981 1000 bool full) ··· 3422 3403 } 3423 3404 EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32); 3424 3405 3406 + /* Remove a key field with value and mask in the rule */ 3407 + int vcap_rule_rem_key(struct vcap_rule *rule, enum vcap_key_field key) 3408 + { 3409 + struct vcap_rule_internal *ri = to_intrule(rule); 3410 + struct vcap_client_keyfield *field; 3411 + 3412 + field = vcap_find_keyfield(rule, key); 3413 + if (!field) { 3414 + pr_err("%s:%d: key %s is not in the rule\n", 3415 + __func__, __LINE__, vcap_keyfield_name(ri->vctrl, key)); 3416 + return -EINVAL; 3417 + } 3418 + /* Deallocate the key field */ 3419 + list_del(&field->ctrl.list); 3420 + kfree(field); 3421 + return 0; 3422 + } 3423 + EXPORT_SYMBOL_GPL(vcap_rule_rem_key); 3424 + 3425 3425 static int vcap_rule_mod_action(struct vcap_rule *rule, 3426 3426 enum vcap_action_field action, 3427 3427 enum vcap_field_type ftype, ··· 3512 3474 return err; 3513 3475 } 3514 3476 EXPORT_SYMBOL_GPL(vcap_filter_rule_keys); 3477 + 3478 + /* Select the keyset from the list that results in the smallest rule size */ 3479 + enum vcap_keyfield_set 3480 + vcap_select_min_rule_keyset(struct vcap_control *vctrl, 3481 + enum vcap_type vtype, 3482 + struct vcap_keyset_list *kslist) 3483 + { 3484 + enum vcap_keyfield_set ret = VCAP_KFS_NO_VALUE; 3485 + const struct vcap_set *kset; 3486 + int max = 100, idx; 3487 + 3488 + for (idx = 0; idx < kslist->cnt; ++idx) { 3489 + kset = vcap_keyfieldset(vctrl, vtype, kslist->keysets[idx]); 3490 + if (!kset) 3491 + continue; 3492 + if (kset->sw_per_item >= max) 3493 + continue; 3494 + max = kset->sw_per_item; 3495 + ret = kslist->keysets[idx]; 3496 + } 3497 + return ret; 3498 + } 3499 + EXPORT_SYMBOL_GPL(vcap_select_min_rule_keyset); 3515 3500 3516 3501 /* Make a full copy of an existing rule with a new rule id */ 3517 3502 struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule)
+11
drivers/net/ethernet/microchip/vcap/vcap_api_client.h
··· 201 201 int vcap_rule_add_action_u32(struct vcap_rule *rule, 202 202 enum vcap_action_field action, u32 value); 203 203 204 + /* Get number of rules in a vcap instance lookup chain id range */ 205 + int vcap_admin_rule_count(struct vcap_admin *admin, int cid); 206 + 204 207 /* VCAP rule counter operations */ 205 208 int vcap_get_rule_count_by_cookie(struct vcap_control *vctrl, 206 209 struct vcap_counter *ctr, u64 cookie); ··· 271 268 /* Get a 32 bit key field value and mask from the rule */ 272 269 int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key, 273 270 u32 *value, u32 *mask); 271 + 272 + /* Remove a key field with value and mask in the rule */ 273 + int vcap_rule_rem_key(struct vcap_rule *rule, enum vcap_key_field key); 274 + 275 + /* Select the keyset from the list that results in the smallest rule size */ 276 + enum vcap_keyfield_set 277 + vcap_select_min_rule_keyset(struct vcap_control *vctrl, enum vcap_type vtype, 278 + struct vcap_keyset_list *kslist); 274 279 275 280 struct vcap_client_actionfield * 276 281 vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act);