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 'net-microchip-vcap-rules'

Steen Hegelund says:

====================
net: microchip: Add support for two classes of VCAP rules

This adds support for two classes of VCAP rules:

- Permanent rules (added e.g. for PTP support)
- TC user rules (added by the TC userspace tool)

For this to work the VCAP Loopups must be enabled from boot, so that the
"internal" clients like PTP can add rules that are always active.

When the TC tool add a flower filter the VCAP rule corresponding to this
filter will be disabled (kept in memory) until a TC matchall filter creates
a link from chain 0 to the chain (lookup) where the flower filter was
added.

When the flower filter is enabled it will be written to the appropriate
VCAP lookup and become active in HW.

Likewise the flower filter will be disabled if there is no link from chain
0 to the chain of the filter (lookup), and when that happens the
corresponding VCAP rule will be read from the VCAP instance and stored in
memory until it is deleted or enabled again.

Version History:
================
v4 Removed a leftover 'Fixes' tag from v2. No functional changes.

v3 Removed the change that allowed rules to always be added in the
LAN996x even though the lookups are not enabled (Horatiu Vultur).
This was sent separately to net instead.

Removed the 'Fixes' tags due to the patch sent to net by Horatiu
Vultur.

Added a check for validity of the chain source when enabling a
lookup.

v2 Adding a missing goto exit in vcap_add_rule (Dan Carpenter).
Added missing checks for error returns in vcap_enable_rule.

v1 Initial version
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+709 -357
+3 -7
drivers/net/ethernet/microchip/lan966x/lan966x_goto.c
··· 4 4 #include "vcap_api_client.h" 5 5 6 6 int lan966x_goto_port_add(struct lan966x_port *port, 7 - struct flow_action_entry *act, 7 + int from_cid, int to_cid, 8 8 unsigned long goto_id, 9 9 struct netlink_ext_ack *extack) 10 10 { ··· 12 12 int err; 13 13 14 14 err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev, 15 - act->chain_index, goto_id, 15 + from_cid, to_cid, goto_id, 16 16 true); 17 17 if (err == -EFAULT) { 18 18 NL_SET_ERR_MSG_MOD(extack, "Unsupported goto chain"); ··· 29 29 return err; 30 30 } 31 31 32 - port->tc.goto_id = goto_id; 33 - 34 32 return 0; 35 33 } 36 34 ··· 39 41 struct lan966x *lan966x = port->lan966x; 40 42 int err; 41 43 42 - err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev, 0, 44 + err = vcap_enable_lookups(lan966x->vcap_ctrl, port->dev, 0, 0, 43 45 goto_id, false); 44 46 if (err) { 45 47 NL_SET_ERR_MSG_MOD(extack, "Could not disable VCAP lookups"); 46 48 return err; 47 49 } 48 - 49 - port->tc.goto_id = 0; 50 50 51 51 return 0; 52 52 }
+1 -2
drivers/net/ethernet/microchip/lan966x/lan966x_main.h
··· 332 332 unsigned long police_id; 333 333 unsigned long ingress_mirror_id; 334 334 unsigned long egress_mirror_id; 335 - unsigned long goto_id; 336 335 struct flow_stats police_stat; 337 336 struct flow_stats mirror_stat; 338 337 }; ··· 606 607 struct flow_cls_offload *f); 607 608 608 609 int lan966x_goto_port_add(struct lan966x_port *port, 609 - struct flow_action_entry *act, 610 + int from_cid, int to_cid, 610 611 unsigned long goto_id, 611 612 struct netlink_ext_ack *extack); 612 613 int lan966x_goto_port_del(struct lan966x_port *port,
+16 -14
drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c
··· 82 82 } 83 83 84 84 static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, 85 - struct flow_cls_offload *fco, 86 - struct vcap_admin *admin) 85 + struct net_device *dev, 86 + struct flow_cls_offload *fco) 87 87 { 88 88 struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 89 89 struct flow_action_entry *actent, *last_actent = NULL; ··· 109 109 last_actent = actent; /* Save last action for later check */ 110 110 } 111 111 112 - /* Check that last action is a goto */ 113 - if (last_actent->id != FLOW_ACTION_GOTO) { 112 + /* Check that last action is a goto 113 + * The last chain/lookup does not need to have goto action 114 + */ 115 + if (last_actent->id == FLOW_ACTION_GOTO) { 116 + /* Check if the destination chain is in one of the VCAPs */ 117 + if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 118 + last_actent->chain_index)) { 119 + NL_SET_ERR_MSG_MOD(fco->common.extack, 120 + "Invalid goto chain"); 121 + return -EINVAL; 122 + } 123 + } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) { 114 124 NL_SET_ERR_MSG_MOD(fco->common.extack, 115 125 "Last action must be 'goto'"); 116 - return -EINVAL; 117 - } 118 - 119 - /* Check if the goto chain is in the next lookup */ 120 - if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 121 - last_actent->chain_index)) { 122 - NL_SET_ERR_MSG_MOD(fco->common.extack, 123 - "Invalid goto chain"); 124 126 return -EINVAL; 125 127 } 126 128 ··· 147 145 struct vcap_rule *vrule; 148 146 int err, idx; 149 147 150 - err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, f, 151 - admin); 148 + err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, 149 + port->dev, f); 152 150 if (err) 153 151 return err; 154 152
+3 -13
drivers/net/ethernet/microchip/lan966x/lan966x_tc_matchall.c
··· 24 24 return lan966x_mirror_port_add(port, act, f->cookie, 25 25 ingress, f->common.extack); 26 26 case FLOW_ACTION_GOTO: 27 - return lan966x_goto_port_add(port, act, f->cookie, 27 + return lan966x_goto_port_add(port, f->common.chain_index, 28 + act->chain_index, f->cookie, 28 29 f->common.extack); 29 30 default: 30 31 NL_SET_ERR_MSG_MOD(f->common.extack, ··· 47 46 f->cookie == port->tc.egress_mirror_id) { 48 47 return lan966x_mirror_port_del(port, ingress, 49 48 f->common.extack); 50 - } else if (f->cookie == port->tc.goto_id) { 51 - return lan966x_goto_port_del(port, f->cookie, 52 - f->common.extack); 53 49 } else { 54 - NL_SET_ERR_MSG_MOD(f->common.extack, 55 - "Unsupported action"); 56 - return -EOPNOTSUPP; 50 + return lan966x_goto_port_del(port, f->cookie, f->common.extack); 57 51 } 58 52 59 53 return 0; ··· 76 80 struct tc_cls_matchall_offload *f, 77 81 bool ingress) 78 82 { 79 - if (!tc_cls_can_offload_and_chain0(port->dev, &f->common)) { 80 - NL_SET_ERR_MSG_MOD(f->common.extack, 81 - "Only chain zero is supported"); 82 - return -EOPNOTSUPP; 83 - } 84 - 85 83 switch (f->command) { 86 84 case TC_CLSMATCHALL_REPLACE: 87 85 return lan966x_tc_matchall_add(port, f, ingress);
+6 -15
drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c
··· 390 390 return 0; 391 391 } 392 392 393 - static int lan966x_vcap_enable(struct net_device *dev, 394 - struct vcap_admin *admin, 395 - bool enable) 396 - { 397 - struct lan966x_port *port = netdev_priv(dev); 398 - struct lan966x *lan966x = port->lan966x; 399 - 400 - lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(enable), 401 - ANA_VCAP_S2_CFG_ENA, 402 - lan966x, ANA_VCAP_S2_CFG(port->chip_port)); 403 - 404 - return 0; 405 - } 406 - 407 393 static struct vcap_operations lan966x_vcap_ops = { 408 394 .validate_keyset = lan966x_vcap_validate_keyset, 409 395 .add_default_fields = lan966x_vcap_add_default_fields, ··· 400 414 .update = lan966x_vcap_update, 401 415 .move = lan966x_vcap_move, 402 416 .port_info = lan966x_vcap_port_info, 403 - .enable = lan966x_vcap_enable, 404 417 }; 405 418 406 419 static void lan966x_vcap_admin_free(struct vcap_admin *admin) ··· 505 520 506 521 list_add_tail(&admin->list, &ctrl->list); 507 522 } 523 + 524 + for (int p = 0; p < lan966x->num_phys_ports; ++p) 525 + if (lan966x->ports[p]) 526 + lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(true), 527 + ANA_VCAP_S2_CFG_ENA, lan966x, 528 + ANA_VCAP_S2_CFG(lan966x->ports[p]->chip_port)); 508 529 509 530 lan966x->vcap_ctrl = ctrl; 510 531
+15 -13
drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
··· 573 573 } 574 574 575 575 static int sparx5_tc_flower_action_check(struct vcap_control *vctrl, 576 - struct flow_cls_offload *fco, 577 - struct vcap_admin *admin) 576 + struct net_device *ndev, 577 + struct flow_cls_offload *fco) 578 578 { 579 579 struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 580 580 struct flow_action_entry *actent, *last_actent = NULL; ··· 600 600 last_actent = actent; /* Save last action for later check */ 601 601 } 602 602 603 - /* Check that last action is a goto */ 604 - if (last_actent->id != FLOW_ACTION_GOTO) { 603 + /* Check if last action is a goto 604 + * The last chain/lookup does not need to have a goto action 605 + */ 606 + if (last_actent->id == FLOW_ACTION_GOTO) { 607 + /* Check if the destination chain is in one of the VCAPs */ 608 + if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 609 + last_actent->chain_index)) { 610 + NL_SET_ERR_MSG_MOD(fco->common.extack, 611 + "Invalid goto chain"); 612 + return -EINVAL; 613 + } 614 + } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) { 605 615 NL_SET_ERR_MSG_MOD(fco->common.extack, 606 616 "Last action must be 'goto'"); 607 - return -EINVAL; 608 - } 609 - 610 - /* Check if the goto chain is in the next lookup */ 611 - if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 612 - last_actent->chain_index)) { 613 - NL_SET_ERR_MSG_MOD(fco->common.extack, 614 - "Invalid goto chain"); 615 617 return -EINVAL; 616 618 } 617 619 ··· 835 833 836 834 vctrl = port->sparx5->vcap_ctrl; 837 835 838 - err = sparx5_tc_flower_action_check(vctrl, fco, admin); 836 + err = sparx5_tc_flower_action_check(vctrl, ndev, fco); 839 837 if (err) 840 838 return err; 841 839
+8 -8
drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
··· 31 31 switch (action->id) { 32 32 case FLOW_ACTION_GOTO: 33 33 err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 34 + tmo->common.chain_index, 34 35 action->chain_index, tmo->cookie, 35 36 true); 36 37 if (err == -EFAULT) { ··· 42 41 if (err == -EADDRINUSE) { 43 42 NL_SET_ERR_MSG_MOD(tmo->common.extack, 44 43 "VCAP already enabled"); 44 + return -EOPNOTSUPP; 45 + } 46 + if (err == -EADDRNOTAVAIL) { 47 + NL_SET_ERR_MSG_MOD(tmo->common.extack, 48 + "Already matching this chain"); 45 49 return -EOPNOTSUPP; 46 50 } 47 51 if (err) { ··· 72 66 73 67 sparx5 = port->sparx5; 74 68 if (!tmo->rule && tmo->cookie) { 75 - err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 0, 76 - tmo->cookie, false); 69 + err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 70 + 0, 0, tmo->cookie, false); 77 71 if (err) 78 72 return err; 79 73 return 0; ··· 86 80 struct tc_cls_matchall_offload *tmo, 87 81 bool ingress) 88 82 { 89 - if (!tc_cls_can_offload_and_chain0(ndev, &tmo->common)) { 90 - NL_SET_ERR_MSG_MOD(tmo->common.extack, 91 - "Only chain zero is supported"); 92 - return -EOPNOTSUPP; 93 - } 94 - 95 83 switch (tmo->command) { 96 84 case TC_CLSMATCHALL_REPLACE: 97 85 return sparx5_tc_matchall_replace(ndev, tmo, ingress);
+1 -1
drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c
··· 29 29 /* Get lookup state */ 30 30 value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_CFG(port->portno)); 31 31 out->prf(out->dst, "\n state: "); 32 - if (ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(value)) 32 + if (ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(value) & BIT(lookup)) 33 33 out->prf(out->dst, "on"); 34 34 else 35 35 out->prf(out->dst, "off");
+6 -23
drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
··· 510 510 sparx5_vcap_wait_super_update(sparx5); 511 511 } 512 512 513 - /* Enable all lookups in the VCAP instance */ 514 - static int sparx5_vcap_enable(struct net_device *ndev, 515 - struct vcap_admin *admin, 516 - bool enable) 517 - { 518 - struct sparx5_port *port = netdev_priv(ndev); 519 - struct sparx5 *sparx5; 520 - int portno; 521 - 522 - sparx5 = port->sparx5; 523 - portno = port->portno; 524 - 525 - /* For now we only consider IS2 */ 526 - if (enable) 527 - spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5, 528 - ANA_ACL_VCAP_S2_CFG(portno)); 529 - else 530 - spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), sparx5, 531 - ANA_ACL_VCAP_S2_CFG(portno)); 532 - return 0; 533 - } 534 - 535 513 /* API callback operations: only IS2 is supported for now */ 536 514 static struct vcap_operations sparx5_vcap_ops = { 537 515 .validate_keyset = sparx5_vcap_validate_keyset, ··· 521 543 .update = sparx5_vcap_update, 522 544 .move = sparx5_vcap_move, 523 545 .port_info = sparx5_port_info, 524 - .enable = sparx5_vcap_enable, 525 546 }; 526 547 527 548 /* Enable lookups per port and set the keyset generation: only IS2 for now */ ··· 545 568 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 546 569 } 547 570 } 571 + /* IS2 lookups are in bit 0:3 */ 572 + for (portno = 0; portno < SPX5_PORTS; ++portno) 573 + spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), 574 + ANA_ACL_VCAP_S2_CFG_SEC_ENA, 575 + sparx5, 576 + ANA_ACL_VCAP_S2_CFG(portno)); 548 577 } 549 578 550 579 /* Disable lookups per port and set the keyset generation: only IS2 for now */
+572 -203
drivers/net/ethernet/microchip/vcap/vcap_api.c
··· 37 37 int count; /* blocksize of addresses to move */ 38 38 }; 39 39 40 - /* Stores the filter cookie that enabled the port */ 40 + /* Stores the filter cookie and chain id that enabled the port */ 41 41 struct vcap_enabled_port { 42 42 struct list_head list; /* for insertion in enabled ports list */ 43 43 struct net_device *ndev; /* the enabled port */ 44 44 unsigned long cookie; /* filter that enabled the port */ 45 + int src_cid; /* source chain id */ 46 + int dst_cid; /* destination chain id */ 45 47 }; 46 48 47 49 void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width, ··· 510 508 vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true); 511 509 } 512 510 511 + /* Copy data from src to dst but reverse the data in chunks of 32bits. 512 + * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will 513 + * have the value 22:33:44:55:00:11. 514 + */ 515 + static void vcap_copy_to_w32be(u8 *dst, const u8 *src, int size) 516 + { 517 + for (int idx = 0; idx < size; ++idx) { 518 + int first_byte_index = 0; 519 + int nidx; 520 + 521 + first_byte_index = size - (((idx >> 2) + 1) << 2); 522 + if (first_byte_index < 0) 523 + first_byte_index = 0; 524 + nidx = idx + first_byte_index - (idx & ~0x3); 525 + dst[nidx] = src[idx]; 526 + } 527 + } 528 + 529 + static void 530 + vcap_copy_from_client_keyfield(struct vcap_rule *rule, 531 + struct vcap_client_keyfield *dst, 532 + const struct vcap_client_keyfield *src) 533 + { 534 + struct vcap_rule_internal *ri = to_intrule(rule); 535 + const struct vcap_client_keyfield_data *sdata; 536 + struct vcap_client_keyfield_data *ddata; 537 + int size; 538 + 539 + dst->ctrl.type = src->ctrl.type; 540 + dst->ctrl.key = src->ctrl.key; 541 + INIT_LIST_HEAD(&dst->ctrl.list); 542 + sdata = &src->data; 543 + ddata = &dst->data; 544 + 545 + if (!ri->admin->w32be) { 546 + memcpy(ddata, sdata, sizeof(dst->data)); 547 + return; 548 + } 549 + 550 + size = keyfield_size_table[dst->ctrl.type] / 2; 551 + 552 + switch (dst->ctrl.type) { 553 + case VCAP_FIELD_BIT: 554 + case VCAP_FIELD_U32: 555 + memcpy(ddata, sdata, sizeof(dst->data)); 556 + break; 557 + case VCAP_FIELD_U48: 558 + vcap_copy_to_w32be(ddata->u48.value, src->data.u48.value, size); 559 + vcap_copy_to_w32be(ddata->u48.mask, src->data.u48.mask, size); 560 + break; 561 + case VCAP_FIELD_U56: 562 + vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size); 563 + vcap_copy_to_w32be(ddata->u56.mask, sdata->u56.mask, size); 564 + break; 565 + case VCAP_FIELD_U64: 566 + vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size); 567 + vcap_copy_to_w32be(ddata->u64.mask, sdata->u64.mask, size); 568 + break; 569 + case VCAP_FIELD_U72: 570 + vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size); 571 + vcap_copy_to_w32be(ddata->u72.mask, sdata->u72.mask, size); 572 + break; 573 + case VCAP_FIELD_U112: 574 + vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size); 575 + vcap_copy_to_w32be(ddata->u112.mask, sdata->u112.mask, size); 576 + break; 577 + case VCAP_FIELD_U128: 578 + vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size); 579 + vcap_copy_to_w32be(ddata->u128.mask, sdata->u128.mask, size); 580 + break; 581 + } 582 + } 583 + 584 + static void 585 + vcap_copy_from_client_actionfield(struct vcap_rule *rule, 586 + struct vcap_client_actionfield *dst, 587 + const struct vcap_client_actionfield *src) 588 + { 589 + struct vcap_rule_internal *ri = to_intrule(rule); 590 + const struct vcap_client_actionfield_data *sdata; 591 + struct vcap_client_actionfield_data *ddata; 592 + int size; 593 + 594 + dst->ctrl.type = src->ctrl.type; 595 + dst->ctrl.action = src->ctrl.action; 596 + INIT_LIST_HEAD(&dst->ctrl.list); 597 + sdata = &src->data; 598 + ddata = &dst->data; 599 + 600 + if (!ri->admin->w32be) { 601 + memcpy(ddata, sdata, sizeof(dst->data)); 602 + return; 603 + } 604 + 605 + size = actionfield_size_table[dst->ctrl.type]; 606 + 607 + switch (dst->ctrl.type) { 608 + case VCAP_FIELD_BIT: 609 + case VCAP_FIELD_U32: 610 + memcpy(ddata, sdata, sizeof(dst->data)); 611 + break; 612 + case VCAP_FIELD_U48: 613 + vcap_copy_to_w32be(ddata->u48.value, sdata->u48.value, size); 614 + break; 615 + case VCAP_FIELD_U56: 616 + vcap_copy_to_w32be(ddata->u56.value, sdata->u56.value, size); 617 + break; 618 + case VCAP_FIELD_U64: 619 + vcap_copy_to_w32be(ddata->u64.value, sdata->u64.value, size); 620 + break; 621 + case VCAP_FIELD_U72: 622 + vcap_copy_to_w32be(ddata->u72.value, sdata->u72.value, size); 623 + break; 624 + case VCAP_FIELD_U112: 625 + vcap_copy_to_w32be(ddata->u112.value, sdata->u112.value, size); 626 + break; 627 + case VCAP_FIELD_U128: 628 + vcap_copy_to_w32be(ddata->u128.value, sdata->u128.value, size); 629 + break; 630 + } 631 + } 632 + 513 633 static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri) 514 634 { 515 635 const struct vcap_client_keyfield *ckf; 516 636 const struct vcap_typegroup *tg_table; 637 + struct vcap_client_keyfield tempkf; 517 638 const struct vcap_field *kf_table; 518 639 int keyset_size; 519 640 ··· 677 552 __func__, __LINE__, ckf->ctrl.key); 678 553 return -EINVAL; 679 554 } 680 - vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table); 555 + vcap_copy_from_client_keyfield(&ri->data, &tempkf, ckf); 556 + vcap_encode_keyfield(ri, &tempkf, &kf_table[ckf->ctrl.key], 557 + tg_table); 681 558 } 682 559 /* Add typegroup bits to the key/mask bitstreams */ 683 560 vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table); ··· 794 667 { 795 668 const struct vcap_client_actionfield *caf; 796 669 const struct vcap_typegroup *tg_table; 670 + struct vcap_client_actionfield tempaf; 797 671 const struct vcap_field *af_table; 798 672 int actionset_size; 799 673 ··· 835 707 __func__, __LINE__, caf->ctrl.action); 836 708 return -EINVAL; 837 709 } 838 - vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action], 839 - tg_table); 710 + vcap_copy_from_client_actionfield(&ri->data, &tempaf, caf); 711 + vcap_encode_actionfield(ri, &tempaf, 712 + &af_table[caf->ctrl.action], tg_table); 840 713 } 841 714 /* Add typegroup bits to the entry bitstreams */ 842 715 vcap_encode_actionfield_typegroups(ri, tg_table); ··· 867 738 !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase || 868 739 !ctrl->ops->cache_write || !ctrl->ops->cache_read || 869 740 !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move || 870 - !ctrl->ops->port_info || !ctrl->ops->enable) { 741 + !ctrl->ops->port_info) { 871 742 pr_err("%s:%d: client operations are missing\n", 872 743 __func__, __LINE__); 873 744 return -ENOENT; ··· 950 821 } 951 822 EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie); 952 823 953 - /* Make a shallow copy of the rule without the fields */ 954 - struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri) 824 + /* Make a copy of the rule, shallow or full */ 825 + static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri, 826 + bool full) 955 827 { 828 + struct vcap_client_actionfield *caf, *newcaf; 829 + struct vcap_client_keyfield *ckf, *newckf; 956 830 struct vcap_rule_internal *duprule; 957 831 958 832 /* Allocate the client part */ ··· 968 836 /* No elements in these lists */ 969 837 INIT_LIST_HEAD(&duprule->data.keyfields); 970 838 INIT_LIST_HEAD(&duprule->data.actionfields); 839 + 840 + /* A full rule copy includes keys and actions */ 841 + if (!full) 842 + return duprule; 843 + 844 + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { 845 + newckf = kzalloc(sizeof(*newckf), GFP_KERNEL); 846 + if (!newckf) 847 + return ERR_PTR(-ENOMEM); 848 + memcpy(newckf, ckf, sizeof(*newckf)); 849 + list_add_tail(&newckf->ctrl.list, &duprule->data.keyfields); 850 + } 851 + 852 + list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { 853 + newcaf = kzalloc(sizeof(*newcaf), GFP_KERNEL); 854 + if (!newcaf) 855 + return ERR_PTR(-ENOMEM); 856 + memcpy(newcaf, caf, sizeof(*newcaf)); 857 + list_add_tail(&newcaf->ctrl.list, &duprule->data.actionfields); 858 + } 859 + 971 860 return duprule; 972 861 } 973 862 ··· 1577 1424 } 1578 1425 EXPORT_SYMBOL_GPL(vcap_find_admin); 1579 1426 1580 - /* Is the next chain id in the following lookup, possible in another VCAP */ 1581 - bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid) 1427 + /* Is the next chain id in one of the following lookups 1428 + * For now this does not support filters linked to other filters using 1429 + * keys and actions. That will be added later. 1430 + */ 1431 + bool vcap_is_next_lookup(struct vcap_control *vctrl, int src_cid, int dst_cid) 1582 1432 { 1583 - struct vcap_admin *admin, *next_admin; 1584 - int lookup, next_lookup; 1585 - 1586 - /* The offset must be at least one lookup */ 1587 - if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE) 1588 - return false; 1433 + struct vcap_admin *admin; 1434 + int next_cid; 1589 1435 1590 1436 if (vcap_api_check(vctrl)) 1591 1437 return false; 1592 1438 1593 - admin = vcap_find_admin(vctrl, cur_cid); 1439 + /* The offset must be at least one lookup, round up */ 1440 + next_cid = src_cid + VCAP_CID_LOOKUP_SIZE; 1441 + next_cid /= VCAP_CID_LOOKUP_SIZE; 1442 + next_cid *= VCAP_CID_LOOKUP_SIZE; 1443 + 1444 + if (dst_cid < next_cid) 1445 + return false; 1446 + 1447 + admin = vcap_find_admin(vctrl, dst_cid); 1594 1448 if (!admin) 1595 1449 return false; 1596 1450 1597 - /* If no VCAP contains the next chain, the next chain must be beyond 1598 - * the last chain in the current VCAP 1599 - */ 1600 - next_admin = vcap_find_admin(vctrl, next_cid); 1601 - if (!next_admin) 1602 - return next_cid > admin->last_cid; 1603 - 1604 - lookup = vcap_chain_id_to_lookup(admin, cur_cid); 1605 - next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid); 1606 - 1607 - /* Next lookup must be the following lookup */ 1608 - if (admin == next_admin || admin->vtype == next_admin->vtype) 1609 - return next_lookup == lookup + 1; 1610 - 1611 - /* Must be the first lookup in the next VCAP instance */ 1612 - return next_lookup == 0; 1451 + return true; 1613 1452 } 1614 1453 EXPORT_SYMBOL_GPL(vcap_is_next_lookup); 1615 1454 ··· 1901 1756 ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri); 1902 1757 admin->last_used_addr = ri->addr; 1903 1758 1904 - /* Add a shallow copy of the rule to the VCAP list */ 1905 - duprule = vcap_dup_rule(ri); 1759 + /* Add a copy of the rule to the VCAP list */ 1760 + duprule = vcap_dup_rule(ri, ri->state == VCAP_RS_DISABLED); 1906 1761 if (IS_ERR(duprule)) 1907 1762 return PTR_ERR(duprule); 1908 1763 ··· 1915 1770 ri->addr = vcap_next_rule_addr(addr, ri); 1916 1771 addr = ri->addr; 1917 1772 1918 - /* Add a shallow copy of the rule to the VCAP list */ 1919 - duprule = vcap_dup_rule(ri); 1773 + /* Add a copy of the rule to the VCAP list */ 1774 + duprule = vcap_dup_rule(ri, ri->state == VCAP_RS_DISABLED); 1920 1775 if (IS_ERR(duprule)) 1921 1776 return PTR_ERR(duprule); 1922 1777 ··· 1948 1803 move->offset, move->count); 1949 1804 } 1950 1805 1806 + /* Check if the chain is already used to enable a VCAP lookup for this port */ 1807 + static bool vcap_is_chain_used(struct vcap_control *vctrl, 1808 + struct net_device *ndev, int src_cid) 1809 + { 1810 + struct vcap_enabled_port *eport; 1811 + struct vcap_admin *admin; 1812 + 1813 + list_for_each_entry(admin, &vctrl->list, list) 1814 + list_for_each_entry(eport, &admin->enabled, list) 1815 + if (eport->src_cid == src_cid && eport->ndev == ndev) 1816 + return true; 1817 + 1818 + return false; 1819 + } 1820 + 1821 + /* Fetch the next chain in the enabled list for the port */ 1822 + static int vcap_get_next_chain(struct vcap_control *vctrl, 1823 + struct net_device *ndev, 1824 + int dst_cid) 1825 + { 1826 + struct vcap_enabled_port *eport; 1827 + struct vcap_admin *admin; 1828 + 1829 + list_for_each_entry(admin, &vctrl->list, list) { 1830 + list_for_each_entry(eport, &admin->enabled, list) { 1831 + if (eport->ndev != ndev) 1832 + continue; 1833 + if (eport->src_cid == dst_cid) 1834 + return eport->dst_cid; 1835 + } 1836 + } 1837 + 1838 + return 0; 1839 + } 1840 + 1841 + static bool vcap_path_exist(struct vcap_control *vctrl, struct net_device *ndev, 1842 + int dst_cid) 1843 + { 1844 + struct vcap_enabled_port *eport, *elem; 1845 + struct vcap_admin *admin; 1846 + int tmp; 1847 + 1848 + if (dst_cid == 0) /* Chain zero is always available */ 1849 + return true; 1850 + 1851 + /* Find first entry that starts from chain 0*/ 1852 + list_for_each_entry(admin, &vctrl->list, list) { 1853 + list_for_each_entry(elem, &admin->enabled, list) { 1854 + if (elem->src_cid == 0 && elem->ndev == ndev) { 1855 + eport = elem; 1856 + break; 1857 + } 1858 + } 1859 + if (eport) 1860 + break; 1861 + } 1862 + 1863 + if (!eport) 1864 + return false; 1865 + 1866 + tmp = eport->dst_cid; 1867 + while (tmp != dst_cid && tmp != 0) 1868 + tmp = vcap_get_next_chain(vctrl, ndev, tmp); 1869 + 1870 + return !!tmp; 1871 + } 1872 + 1873 + /* Internal clients can always store their rules in HW 1874 + * External clients can store their rules if the chain is enabled all 1875 + * the way from chain 0, otherwise the rule will be cached until 1876 + * the chain is enabled. 1877 + */ 1878 + static void vcap_rule_set_state(struct vcap_rule_internal *ri) 1879 + { 1880 + if (ri->data.user <= VCAP_USER_QOS) 1881 + ri->state = VCAP_RS_PERMANENT; 1882 + else if (vcap_path_exist(ri->vctrl, ri->ndev, ri->data.vcap_chain_id)) 1883 + ri->state = VCAP_RS_ENABLED; 1884 + else 1885 + ri->state = VCAP_RS_DISABLED; 1886 + } 1887 + 1951 1888 /* Encode and write a validated rule to the VCAP */ 1952 1889 int vcap_add_rule(struct vcap_rule *rule) 1953 1890 { 1954 1891 struct vcap_rule_internal *ri = to_intrule(rule); 1955 1892 struct vcap_rule_move move = {0}; 1893 + struct vcap_counter ctr = {0}; 1956 1894 int ret; 1957 1895 1958 1896 ret = vcap_api_check(ri->vctrl); ··· 2043 1815 return ret; 2044 1816 /* Insert the new rule in the list of vcap rules */ 2045 1817 mutex_lock(&ri->admin->lock); 1818 + 1819 + vcap_rule_set_state(ri); 2046 1820 ret = vcap_insert_rule(ri, &move); 2047 1821 if (ret < 0) { 2048 1822 pr_err("%s:%d: could not insert rule in vcap list: %d\n", ··· 2053 1823 } 2054 1824 if (move.count > 0) 2055 1825 vcap_move_rules(ri, &move); 1826 + 1827 + if (ri->state == VCAP_RS_DISABLED) { 1828 + /* Erase the rule area */ 1829 + ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size); 1830 + goto out; 1831 + } 1832 + 1833 + vcap_erase_cache(ri); 2056 1834 ret = vcap_encode_rule(ri); 2057 1835 if (ret) { 2058 1836 pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret); ··· 2068 1830 } 2069 1831 2070 1832 ret = vcap_write_rule(ri); 2071 - if (ret) 1833 + if (ret) { 2072 1834 pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret); 1835 + goto out; 1836 + } 1837 + /* Set the counter to zero */ 1838 + ret = vcap_write_counter(ri, &ctr); 2073 1839 out: 2074 1840 mutex_unlock(&ri->admin->lock); 2075 1841 return ret; ··· 2127 1885 ri->vctrl = vctrl; /* refer to the client */ 2128 1886 if (vcap_set_rule_id(ri) == 0) 2129 1887 goto out_free; 2130 - vcap_erase_cache(ri); 2131 1888 return (struct vcap_rule *)ri; 2132 1889 2133 1890 out_free: ··· 2171 1930 if (!elem) 2172 1931 return NULL; 2173 1932 mutex_lock(&elem->admin->lock); 2174 - ri = vcap_dup_rule(elem); 1933 + ri = vcap_dup_rule(elem, elem->state == VCAP_RS_DISABLED); 2175 1934 if (IS_ERR(ri)) 2176 1935 goto unlock; 1936 + 1937 + if (ri->state == VCAP_RS_DISABLED) 1938 + goto unlock; 1939 + 2177 1940 err = vcap_read_rule(ri); 2178 1941 if (err) { 2179 1942 ri = ERR_PTR(err); ··· 2215 1970 return -ENOENT; 2216 1971 2217 1972 mutex_lock(&ri->admin->lock); 1973 + 1974 + vcap_rule_set_state(ri); 1975 + if (ri->state == VCAP_RS_DISABLED) 1976 + goto out; 1977 + 2218 1978 /* Encode the bitstreams to the VCAP cache */ 2219 1979 vcap_erase_cache(ri); 2220 1980 err = vcap_encode_rule(ri); ··· 2312 2062 mutex_lock(&admin->lock); 2313 2063 list_del(&ri->list); 2314 2064 vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap); 2315 - kfree(ri); 2065 + vcap_free_rule(&ri->data); 2316 2066 mutex_unlock(&admin->lock); 2317 2067 2318 2068 /* Update the last used address, set to default when no rules */ ··· 2341 2091 list_for_each_entry_safe(ri, next_ri, &admin->rules, list) { 2342 2092 vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size); 2343 2093 list_del(&ri->list); 2344 - kfree(ri); 2094 + vcap_free_rule(&ri->data); 2345 2095 } 2346 2096 admin->last_used_addr = admin->last_valid_addr; 2347 2097 ··· 2386 2136 return &fields[key]; 2387 2137 } 2388 2138 EXPORT_SYMBOL_GPL(vcap_lookup_keyfield); 2389 - 2390 - /* Copy data from src to dst but reverse the data in chunks of 32bits. 2391 - * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will 2392 - * have the value 22:33:44:55:00:11. 2393 - */ 2394 - static void vcap_copy_to_w32be(u8 *dst, u8 *src, int size) 2395 - { 2396 - for (int idx = 0; idx < size; ++idx) { 2397 - int first_byte_index = 0; 2398 - int nidx; 2399 - 2400 - first_byte_index = size - (((idx >> 2) + 1) << 2); 2401 - if (first_byte_index < 0) 2402 - first_byte_index = 0; 2403 - nidx = idx + first_byte_index - (idx & ~0x3); 2404 - dst[nidx] = src[idx]; 2405 - } 2406 - } 2407 - 2408 - static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, 2409 - struct vcap_client_keyfield *field, 2410 - struct vcap_client_keyfield_data *data) 2411 - { 2412 - struct vcap_rule_internal *ri = to_intrule(rule); 2413 - int size; 2414 - 2415 - if (!ri->admin->w32be) { 2416 - memcpy(&field->data, data, sizeof(field->data)); 2417 - return; 2418 - } 2419 - 2420 - size = keyfield_size_table[field->ctrl.type] / 2; 2421 - switch (field->ctrl.type) { 2422 - case VCAP_FIELD_BIT: 2423 - case VCAP_FIELD_U32: 2424 - memcpy(&field->data, data, sizeof(field->data)); 2425 - break; 2426 - case VCAP_FIELD_U48: 2427 - vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size); 2428 - vcap_copy_to_w32be(field->data.u48.mask, data->u48.mask, size); 2429 - break; 2430 - case VCAP_FIELD_U56: 2431 - vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size); 2432 - vcap_copy_to_w32be(field->data.u56.mask, data->u56.mask, size); 2433 - break; 2434 - case VCAP_FIELD_U64: 2435 - vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size); 2436 - vcap_copy_to_w32be(field->data.u64.mask, data->u64.mask, size); 2437 - break; 2438 - case VCAP_FIELD_U72: 2439 - vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size); 2440 - vcap_copy_to_w32be(field->data.u72.mask, data->u72.mask, size); 2441 - break; 2442 - case VCAP_FIELD_U112: 2443 - vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size); 2444 - vcap_copy_to_w32be(field->data.u112.mask, data->u112.mask, size); 2445 - break; 2446 - case VCAP_FIELD_U128: 2447 - vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size); 2448 - vcap_copy_to_w32be(field->data.u128.mask, data->u128.mask, size); 2449 - break; 2450 - } 2451 - } 2452 2139 2453 2140 /* Check if the keyfield is already in the rule */ 2454 2141 static bool vcap_keyfield_unique(struct vcap_rule *rule, ··· 2444 2257 field = kzalloc(sizeof(*field), GFP_KERNEL); 2445 2258 if (!field) 2446 2259 return -ENOMEM; 2260 + memcpy(&field->data, data, sizeof(field->data)); 2447 2261 field->ctrl.key = key; 2448 2262 field->ctrl.type = ftype; 2449 - vcap_copy_from_client_keyfield(rule, field, data); 2450 2263 list_add_tail(&field->ctrl.list, &rule->keyfields); 2451 2264 return 0; 2452 2265 } ··· 2554 2367 return NULL; 2555 2368 } 2556 2369 2557 - static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, 2558 - struct vcap_client_actionfield *field, 2559 - struct vcap_client_actionfield_data *data) 2560 - { 2561 - struct vcap_rule_internal *ri = to_intrule(rule); 2562 - int size; 2563 - 2564 - if (!ri->admin->w32be) { 2565 - memcpy(&field->data, data, sizeof(field->data)); 2566 - return; 2567 - } 2568 - 2569 - size = actionfield_size_table[field->ctrl.type]; 2570 - switch (field->ctrl.type) { 2571 - case VCAP_FIELD_BIT: 2572 - case VCAP_FIELD_U32: 2573 - memcpy(&field->data, data, sizeof(field->data)); 2574 - break; 2575 - case VCAP_FIELD_U48: 2576 - vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size); 2577 - break; 2578 - case VCAP_FIELD_U56: 2579 - vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size); 2580 - break; 2581 - case VCAP_FIELD_U64: 2582 - vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size); 2583 - break; 2584 - case VCAP_FIELD_U72: 2585 - vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size); 2586 - break; 2587 - case VCAP_FIELD_U112: 2588 - vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size); 2589 - break; 2590 - case VCAP_FIELD_U128: 2591 - vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size); 2592 - break; 2593 - } 2594 - } 2595 - 2596 2370 /* Check if the actionfield is already in the rule */ 2597 2371 static bool vcap_actionfield_unique(struct vcap_rule *rule, 2598 2372 enum vcap_action_field act) ··· 2611 2463 field = kzalloc(sizeof(*field), GFP_KERNEL); 2612 2464 if (!field) 2613 2465 return -ENOMEM; 2466 + memcpy(&field->data, data, sizeof(field->data)); 2614 2467 field->ctrl.action = action; 2615 2468 field->ctrl.type = ftype; 2616 - vcap_copy_from_client_actionfield(rule, field, data); 2617 2469 list_add_tail(&field->ctrl.list, &rule->actionfields); 2618 2470 return 0; 2619 2471 } ··· 2712 2564 } 2713 2565 EXPORT_SYMBOL_GPL(vcap_set_tc_exterr); 2714 2566 2567 + /* Write a rule to VCAP HW to enable it */ 2568 + static int vcap_enable_rule(struct vcap_rule_internal *ri) 2569 + { 2570 + struct vcap_client_actionfield *af, *naf; 2571 + struct vcap_client_keyfield *kf, *nkf; 2572 + int err; 2573 + 2574 + vcap_erase_cache(ri); 2575 + err = vcap_encode_rule(ri); 2576 + if (err) 2577 + goto out; 2578 + err = vcap_write_rule(ri); 2579 + if (err) 2580 + goto out; 2581 + 2582 + /* Deallocate the list of keys and actions */ 2583 + list_for_each_entry_safe(kf, nkf, &ri->data.keyfields, ctrl.list) { 2584 + list_del(&kf->ctrl.list); 2585 + kfree(kf); 2586 + } 2587 + list_for_each_entry_safe(af, naf, &ri->data.actionfields, ctrl.list) { 2588 + list_del(&af->ctrl.list); 2589 + kfree(af); 2590 + } 2591 + ri->state = VCAP_RS_ENABLED; 2592 + out: 2593 + return err; 2594 + } 2595 + 2596 + /* Enable all disabled rules for a specific chain/port in the VCAP HW */ 2597 + static int vcap_enable_rules(struct vcap_control *vctrl, 2598 + struct net_device *ndev, int chain) 2599 + { 2600 + struct vcap_rule_internal *ri; 2601 + struct vcap_admin *admin; 2602 + int err = 0; 2603 + 2604 + list_for_each_entry(admin, &vctrl->list, list) { 2605 + if (!(chain >= admin->first_cid && chain <= admin->last_cid)) 2606 + continue; 2607 + 2608 + /* Found the admin, now find the offloadable rules */ 2609 + mutex_lock(&admin->lock); 2610 + list_for_each_entry(ri, &admin->rules, list) { 2611 + if (ri->data.vcap_chain_id != chain) 2612 + continue; 2613 + 2614 + if (ri->ndev != ndev) 2615 + continue; 2616 + 2617 + if (ri->state != VCAP_RS_DISABLED) 2618 + continue; 2619 + 2620 + err = vcap_enable_rule(ri); 2621 + if (err) 2622 + break; 2623 + } 2624 + mutex_unlock(&admin->lock); 2625 + if (err) 2626 + break; 2627 + } 2628 + return err; 2629 + } 2630 + 2631 + /* Read and erase a rule from VCAP HW to disable it */ 2632 + static int vcap_disable_rule(struct vcap_rule_internal *ri) 2633 + { 2634 + int err; 2635 + 2636 + err = vcap_read_rule(ri); 2637 + if (err) 2638 + return err; 2639 + err = vcap_decode_keyset(ri); 2640 + if (err) 2641 + return err; 2642 + err = vcap_decode_actionset(ri); 2643 + if (err) 2644 + return err; 2645 + 2646 + ri->state = VCAP_RS_DISABLED; 2647 + ri->vctrl->ops->init(ri->ndev, ri->admin, ri->addr, ri->size); 2648 + return 0; 2649 + } 2650 + 2651 + /* Disable all enabled rules for a specific chain/port in the VCAP HW */ 2652 + static int vcap_disable_rules(struct vcap_control *vctrl, 2653 + struct net_device *ndev, int chain) 2654 + { 2655 + struct vcap_rule_internal *ri; 2656 + struct vcap_admin *admin; 2657 + int err = 0; 2658 + 2659 + list_for_each_entry(admin, &vctrl->list, list) { 2660 + if (!(chain >= admin->first_cid && chain <= admin->last_cid)) 2661 + continue; 2662 + 2663 + /* Found the admin, now find the rules on the chain */ 2664 + mutex_lock(&admin->lock); 2665 + list_for_each_entry(ri, &admin->rules, list) { 2666 + if (ri->data.vcap_chain_id != chain) 2667 + continue; 2668 + 2669 + if (ri->ndev != ndev) 2670 + continue; 2671 + 2672 + if (ri->state != VCAP_RS_ENABLED) 2673 + continue; 2674 + 2675 + err = vcap_disable_rule(ri); 2676 + if (err) 2677 + break; 2678 + } 2679 + mutex_unlock(&admin->lock); 2680 + if (err) 2681 + break; 2682 + } 2683 + return err; 2684 + } 2685 + 2715 2686 /* Check if this port is already enabled for this VCAP instance */ 2716 - static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev, 2717 - unsigned long cookie) 2687 + static bool vcap_is_enabled(struct vcap_control *vctrl, struct net_device *ndev, 2688 + int dst_cid) 2718 2689 { 2719 2690 struct vcap_enabled_port *eport; 2691 + struct vcap_admin *admin; 2720 2692 2721 - list_for_each_entry(eport, &admin->enabled, list) 2722 - if (eport->cookie == cookie || eport->ndev == ndev) 2723 - return true; 2693 + list_for_each_entry(admin, &vctrl->list, list) 2694 + list_for_each_entry(eport, &admin->enabled, list) 2695 + if (eport->dst_cid == dst_cid && eport->ndev == ndev) 2696 + return true; 2724 2697 2725 2698 return false; 2726 2699 } 2727 2700 2728 - /* Enable this port for this VCAP instance */ 2729 - static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev, 2730 - unsigned long cookie) 2701 + /* Enable this port and chain id in a VCAP instance */ 2702 + static int vcap_enable(struct vcap_control *vctrl, struct net_device *ndev, 2703 + unsigned long cookie, int src_cid, int dst_cid) 2731 2704 { 2732 2705 struct vcap_enabled_port *eport; 2706 + struct vcap_admin *admin; 2707 + 2708 + if (src_cid >= dst_cid) 2709 + return -EFAULT; 2710 + 2711 + admin = vcap_find_admin(vctrl, dst_cid); 2712 + if (!admin) 2713 + return -ENOENT; 2733 2714 2734 2715 eport = kzalloc(sizeof(*eport), GFP_KERNEL); 2735 2716 if (!eport) ··· 2866 2589 2867 2590 eport->ndev = ndev; 2868 2591 eport->cookie = cookie; 2592 + eport->src_cid = src_cid; 2593 + eport->dst_cid = dst_cid; 2594 + mutex_lock(&admin->lock); 2869 2595 list_add_tail(&eport->list, &admin->enabled); 2596 + mutex_unlock(&admin->lock); 2870 2597 2598 + if (vcap_path_exist(vctrl, ndev, src_cid)) { 2599 + /* Enable chained lookups */ 2600 + while (dst_cid) { 2601 + admin = vcap_find_admin(vctrl, dst_cid); 2602 + if (!admin) 2603 + return -ENOENT; 2604 + 2605 + vcap_enable_rules(vctrl, ndev, dst_cid); 2606 + dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid); 2607 + } 2608 + } 2871 2609 return 0; 2872 2610 } 2873 2611 2874 - /* Disable this port for this VCAP instance */ 2875 - static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev, 2612 + /* Disable this port and chain id for a VCAP instance */ 2613 + static int vcap_disable(struct vcap_control *vctrl, struct net_device *ndev, 2876 2614 unsigned long cookie) 2877 2615 { 2878 - struct vcap_enabled_port *eport; 2616 + struct vcap_enabled_port *elem, *eport = NULL; 2617 + struct vcap_admin *found = NULL, *admin; 2618 + int dst_cid; 2879 2619 2880 - list_for_each_entry(eport, &admin->enabled, list) { 2881 - if (eport->cookie == cookie && eport->ndev == ndev) { 2882 - list_del(&eport->list); 2883 - kfree(eport); 2884 - return 0; 2620 + list_for_each_entry(admin, &vctrl->list, list) { 2621 + list_for_each_entry(elem, &admin->enabled, list) { 2622 + if (elem->cookie == cookie && elem->ndev == ndev) { 2623 + eport = elem; 2624 + found = admin; 2625 + break; 2626 + } 2885 2627 } 2628 + if (eport) 2629 + break; 2886 2630 } 2887 2631 2888 - return -ENOENT; 2632 + if (!eport) 2633 + return -ENOENT; 2634 + 2635 + /* Disable chained lookups */ 2636 + dst_cid = eport->dst_cid; 2637 + while (dst_cid) { 2638 + admin = vcap_find_admin(vctrl, dst_cid); 2639 + if (!admin) 2640 + return -ENOENT; 2641 + 2642 + vcap_disable_rules(vctrl, ndev, dst_cid); 2643 + dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid); 2644 + } 2645 + 2646 + mutex_lock(&found->lock); 2647 + list_del(&eport->list); 2648 + mutex_unlock(&found->lock); 2649 + kfree(eport); 2650 + return 0; 2889 2651 } 2890 2652 2891 - /* Find the VCAP instance that enabled the port using a specific filter */ 2892 - static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl, 2893 - unsigned long cookie) 2894 - { 2895 - struct vcap_enabled_port *eport; 2896 - struct vcap_admin *admin; 2897 - 2898 - list_for_each_entry(admin, &vctrl->list, list) 2899 - list_for_each_entry(eport, &admin->enabled, list) 2900 - if (eport->cookie == cookie) 2901 - return admin; 2902 - 2903 - return NULL; 2904 - } 2905 - 2906 - /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */ 2653 + /* Enable/Disable the VCAP instance lookups */ 2907 2654 int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, 2908 - int chain_id, unsigned long cookie, bool enable) 2655 + int src_cid, int dst_cid, unsigned long cookie, 2656 + bool enable) 2909 2657 { 2910 - struct vcap_admin *admin; 2911 2658 int err; 2912 2659 2913 2660 err = vcap_api_check(vctrl); ··· 2941 2640 if (!ndev) 2942 2641 return -ENODEV; 2943 2642 2944 - if (chain_id) 2945 - admin = vcap_find_admin(vctrl, chain_id); 2946 - else 2947 - admin = vcap_find_admin_by_cookie(vctrl, cookie); 2948 - if (!admin) 2949 - return -ENOENT; 2950 - 2951 - /* first instance and first chain */ 2952 - if (admin->vinst || chain_id > admin->first_cid) 2643 + /* Source and destination must be the first chain in a lookup */ 2644 + if (src_cid % VCAP_CID_LOOKUP_SIZE) 2645 + return -EFAULT; 2646 + if (dst_cid % VCAP_CID_LOOKUP_SIZE) 2953 2647 return -EFAULT; 2954 2648 2955 - err = vctrl->ops->enable(ndev, admin, enable); 2956 - if (err) 2957 - return err; 2958 - 2959 - if (chain_id) { 2960 - if (vcap_is_enabled(admin, ndev, cookie)) 2649 + if (enable) { 2650 + if (vcap_is_enabled(vctrl, ndev, dst_cid)) 2961 2651 return -EADDRINUSE; 2962 - mutex_lock(&admin->lock); 2963 - vcap_enable(admin, ndev, cookie); 2652 + if (vcap_is_chain_used(vctrl, ndev, src_cid)) 2653 + return -EADDRNOTAVAIL; 2654 + err = vcap_enable(vctrl, ndev, cookie, src_cid, dst_cid); 2964 2655 } else { 2965 - mutex_lock(&admin->lock); 2966 - vcap_disable(admin, ndev, cookie); 2656 + err = vcap_disable(vctrl, ndev, cookie); 2967 2657 } 2968 - mutex_unlock(&admin->lock); 2969 2658 2970 - return 0; 2659 + return err; 2971 2660 } 2972 2661 EXPORT_SYMBOL_GPL(vcap_enable_lookups); 2662 + 2663 + /* Is this chain id the last lookup of all VCAPs */ 2664 + bool vcap_is_last_chain(struct vcap_control *vctrl, int cid) 2665 + { 2666 + struct vcap_admin *admin; 2667 + int lookup; 2668 + 2669 + if (vcap_api_check(vctrl)) 2670 + return false; 2671 + 2672 + admin = vcap_find_admin(vctrl, cid); 2673 + if (!admin) 2674 + return false; 2675 + 2676 + /* This must be the last lookup in this VCAP type */ 2677 + lookup = vcap_chain_id_to_lookup(admin, cid); 2678 + return lookup == admin->lookups - 1; 2679 + } 2680 + EXPORT_SYMBOL_GPL(vcap_is_last_chain); 2973 2681 2974 2682 /* Set a rule counter id (for certain vcaps only) */ 2975 2683 void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id) ··· 3046 2736 } 3047 2737 EXPORT_SYMBOL_GPL(vcap_rule_get_counter); 3048 2738 2739 + /* Get a copy of a client key field */ 2740 + static int vcap_rule_get_key(struct vcap_rule *rule, 2741 + enum vcap_key_field key, 2742 + struct vcap_client_keyfield *ckf) 2743 + { 2744 + struct vcap_client_keyfield *field; 2745 + 2746 + field = vcap_find_keyfield(rule, key); 2747 + if (!field) 2748 + return -EINVAL; 2749 + memcpy(ckf, field, sizeof(*ckf)); 2750 + INIT_LIST_HEAD(&ckf->ctrl.list); 2751 + return 0; 2752 + } 2753 + 2754 + /* Get the keysets that matches the rule key type/mask */ 2755 + int vcap_rule_get_keysets(struct vcap_rule_internal *ri, 2756 + struct vcap_keyset_list *matches) 2757 + { 2758 + struct vcap_control *vctrl = ri->vctrl; 2759 + enum vcap_type vt = ri->admin->vtype; 2760 + const struct vcap_set *keyfield_set; 2761 + struct vcap_client_keyfield kf = {}; 2762 + u32 value, mask; 2763 + int err, idx; 2764 + 2765 + err = vcap_rule_get_key(&ri->data, VCAP_KF_TYPE, &kf); 2766 + if (err) 2767 + return err; 2768 + 2769 + if (kf.ctrl.type == VCAP_FIELD_BIT) { 2770 + value = kf.data.u1.value; 2771 + mask = kf.data.u1.mask; 2772 + } else if (kf.ctrl.type == VCAP_FIELD_U32) { 2773 + value = kf.data.u32.value; 2774 + mask = kf.data.u32.mask; 2775 + } else { 2776 + return -EINVAL; 2777 + } 2778 + 2779 + keyfield_set = vctrl->vcaps[vt].keyfield_set; 2780 + for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) { 2781 + if (keyfield_set[idx].sw_per_item != ri->keyset_sw) 2782 + continue; 2783 + 2784 + if (keyfield_set[idx].type_id == (u8)-1) { 2785 + vcap_keyset_list_add(matches, idx); 2786 + continue; 2787 + } 2788 + 2789 + if ((keyfield_set[idx].type_id & mask) == value) 2790 + vcap_keyset_list_add(matches, idx); 2791 + } 2792 + if (matches->cnt > 0) 2793 + return 0; 2794 + 2795 + return -EINVAL; 2796 + } 2797 + 3049 2798 static int vcap_rule_mod_key(struct vcap_rule *rule, 3050 2799 enum vcap_key_field key, 3051 2800 enum vcap_field_type ftype, ··· 3115 2746 field = vcap_find_keyfield(rule, key); 3116 2747 if (!field) 3117 2748 return vcap_rule_add_key(rule, key, ftype, data); 3118 - vcap_copy_from_client_keyfield(rule, field, data); 2749 + memcpy(&field->data, data, sizeof(field->data)); 3119 2750 return 0; 3120 2751 } 3121 2752 ··· 3141 2772 field = vcap_find_actionfield(rule, action); 3142 2773 if (!field) 3143 2774 return vcap_rule_add_action(rule, action, ftype, data); 3144 - vcap_copy_from_client_actionfield(rule, field, data); 2775 + memcpy(&field->data, data, sizeof(field->data)); 3145 2776 return 0; 3146 2777 } 3147 2778
-5
drivers/net/ethernet/microchip/vcap/vcap_api.h
··· 259 259 (struct net_device *ndev, 260 260 struct vcap_admin *admin, 261 261 struct vcap_output_print *out); 262 - /* enable/disable the lookups in a vcap instance */ 263 - int (*enable) 264 - (struct net_device *ndev, 265 - struct vcap_admin *admin, 266 - bool enable); 267 262 }; 268 263 269 264 /* VCAP API Client control interface */
+5 -3
drivers/net/ethernet/microchip/vcap/vcap_api_client.h
··· 148 148 bool sticky; 149 149 }; 150 150 151 - /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */ 151 + /* Enable/Disable the VCAP instance lookups */ 152 152 int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, 153 - int chain_id, unsigned long cookie, bool enable); 153 + int from_cid, int to_cid, unsigned long cookie, 154 + bool enable); 154 155 155 156 /* VCAP rule operations */ 156 157 /* Allocate a rule and fill in the basic information */ ··· 217 216 int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie); 218 217 /* Is the next chain id in the following lookup, possible in another VCAP */ 219 218 bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid); 219 + /* Is this chain id the last lookup of all VCAPs */ 220 + bool vcap_is_last_chain(struct vcap_control *vctrl, int cid); 220 221 /* Provide all rules via a callback interface */ 221 222 int vcap_rule_iter(struct vcap_control *vctrl, 222 223 int (*callback)(void *, struct vcap_rule *), void *arg); ··· 264 261 /* Get a 32 bit key field value and mask from the rule */ 265 262 int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key, 266 263 u32 *value, u32 *mask); 267 - 268 264 #endif /* __VCAP_API_CLIENT__ */
+46 -23
drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
··· 152 152 out->prf(out->dst, "\n"); 153 153 } 154 154 155 + static int vcap_debugfs_show_keysets(struct vcap_rule_internal *ri, 156 + struct vcap_output_print *out) 157 + { 158 + struct vcap_admin *admin = ri->admin; 159 + enum vcap_keyfield_set keysets[10]; 160 + struct vcap_keyset_list matches; 161 + int err; 162 + 163 + matches.keysets = keysets; 164 + matches.cnt = 0; 165 + matches.max = ARRAY_SIZE(keysets); 166 + 167 + if (ri->state == VCAP_RS_DISABLED) 168 + err = vcap_rule_get_keysets(ri, &matches); 169 + else 170 + err = vcap_find_keystream_keysets(ri->vctrl, admin->vtype, 171 + admin->cache.keystream, 172 + admin->cache.maskstream, 173 + false, 0, &matches); 174 + if (err) { 175 + pr_err("%s:%d: could not find valid keysets: %d\n", 176 + __func__, __LINE__, err); 177 + return err; 178 + } 179 + 180 + out->prf(out->dst, " keysets:"); 181 + for (int idx = 0; idx < matches.cnt; ++idx) 182 + out->prf(out->dst, " %s", 183 + vcap_keyset_name(ri->vctrl, matches.keysets[idx])); 184 + out->prf(out->dst, "\n"); 185 + return 0; 186 + } 187 + 155 188 static int vcap_debugfs_show_rule_keyset(struct vcap_rule_internal *ri, 156 189 struct vcap_output_print *out) 157 190 { 158 191 struct vcap_control *vctrl = ri->vctrl; 159 192 struct vcap_admin *admin = ri->admin; 160 - enum vcap_keyfield_set keysets[10]; 161 193 const struct vcap_field *keyfield; 162 - enum vcap_type vt = admin->vtype; 163 194 struct vcap_client_keyfield *ckf; 164 - struct vcap_keyset_list matches; 165 - u32 *maskstream; 166 - u32 *keystream; 167 - int res; 168 195 169 - keystream = admin->cache.keystream; 170 - maskstream = admin->cache.maskstream; 171 - matches.keysets = keysets; 172 - matches.cnt = 0; 173 - matches.max = ARRAY_SIZE(keysets); 174 - res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream, 175 - false, 0, &matches); 176 - if (res < 0) { 177 - pr_err("%s:%d: could not find valid keysets: %d\n", 178 - __func__, __LINE__, res); 179 - return -EINVAL; 180 - } 181 - out->prf(out->dst, " keysets:"); 182 - for (int idx = 0; idx < matches.cnt; ++idx) 183 - out->prf(out->dst, " %s", 184 - vcap_keyset_name(vctrl, matches.keysets[idx])); 185 - out->prf(out->dst, "\n"); 196 + vcap_debugfs_show_keysets(ri, out); 186 197 out->prf(out->dst, " keyset_sw: %d\n", ri->keyset_sw); 187 198 out->prf(out->dst, " keyset_sw_regs: %d\n", ri->keyset_sw_regs); 188 199 ··· 244 233 out->prf(out->dst, " chain_id: %d\n", ri->data.vcap_chain_id); 245 234 out->prf(out->dst, " user: %d\n", ri->data.user); 246 235 out->prf(out->dst, " priority: %d\n", ri->data.priority); 236 + out->prf(out->dst, " state: "); 237 + switch (ri->state) { 238 + case VCAP_RS_PERMANENT: 239 + out->prf(out->dst, "permanent\n"); 240 + break; 241 + case VCAP_RS_DISABLED: 242 + out->prf(out->dst, "disabled\n"); 243 + break; 244 + case VCAP_RS_ENABLED: 245 + out->prf(out->dst, "enabled\n"); 246 + break; 247 + } 247 248 vcap_debugfs_show_rule_keyset(ri, out); 248 249 vcap_debugfs_show_rule_actionset(ri, out); 249 250 }
+2 -8
drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c
··· 221 221 return 0; 222 222 } 223 223 224 - static int vcap_test_enable(struct net_device *ndev, 225 - struct vcap_admin *admin, 226 - bool enable) 227 - { 228 - return 0; 229 - } 230 - 231 224 static struct vcap_operations test_callbacks = { 232 225 .validate_keyset = test_val_keyset, 233 226 .add_default_fields = test_add_def_fields, ··· 231 238 .update = test_cache_update, 232 239 .move = test_cache_move, 233 240 .port_info = vcap_test_port_info, 234 - .enable = vcap_test_enable, 235 241 }; 236 242 237 243 static struct vcap_control test_vctrl = { ··· 245 253 INIT_LIST_HEAD(&test_vctrl.list); 246 254 INIT_LIST_HEAD(&admin->list); 247 255 INIT_LIST_HEAD(&admin->rules); 256 + INIT_LIST_HEAD(&admin->enabled); 248 257 list_add_tail(&admin->list, &test_vctrl.list); 249 258 memset(test_updateaddr, 0, sizeof(test_updateaddr)); 250 259 test_updateaddridx = 0; ··· 445 452 " chain_id: 0\n", 446 453 " user: 0\n", 447 454 " priority: 0\n", 455 + " state: permanent\n", 448 456 " keysets: VCAP_KFS_MAC_ETYPE\n", 449 457 " keyset_sw: 6\n", 450 458 " keyset_sw_regs: 2\n",
+15 -17
drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
··· 211 211 return 0; 212 212 } 213 213 214 - static int vcap_test_enable(struct net_device *ndev, 215 - struct vcap_admin *admin, 216 - bool enable) 217 - { 218 - return 0; 219 - } 220 - 221 214 static struct vcap_operations test_callbacks = { 222 215 .validate_keyset = test_val_keyset, 223 216 .add_default_fields = test_add_def_fields, ··· 221 228 .update = test_cache_update, 222 229 .move = test_cache_move, 223 230 .port_info = vcap_test_port_info, 224 - .enable = vcap_test_enable, 225 231 }; 226 232 227 233 static struct vcap_control test_vctrl = { ··· 235 243 INIT_LIST_HEAD(&test_vctrl.list); 236 244 INIT_LIST_HEAD(&admin->list); 237 245 INIT_LIST_HEAD(&admin->rules); 246 + INIT_LIST_HEAD(&admin->enabled); 238 247 list_add_tail(&admin->list, &test_vctrl.list); 239 248 memset(test_updateaddr, 0, sizeof(test_updateaddr)); 240 249 test_updateaddridx = 0; ··· 1305 1312 1306 1313 struct vcap_admin is2_admin = { 1307 1314 .vtype = VCAP_TYPE_IS2, 1308 - .first_cid = 10000, 1309 - .last_cid = 19999, 1315 + .first_cid = 8000000, 1316 + .last_cid = 8099999, 1310 1317 .lookups = 4, 1311 1318 .last_valid_addr = 3071, 1312 1319 .first_valid_addr = 0, ··· 1319 1326 }; 1320 1327 struct vcap_rule *rule; 1321 1328 struct vcap_rule_internal *ri; 1322 - int vcap_chain_id = 10005; 1329 + int vcap_chain_id = 8000000; 1323 1330 enum vcap_user user = VCAP_USER_VCAP_UTIL; 1324 1331 u16 priority = 10; 1325 1332 int id = 100; ··· 1336 1343 u32 port_mask_rng_mask = 0x0f; 1337 1344 u32 igr_port_mask_value = 0xffabcd01; 1338 1345 u32 igr_port_mask_mask = ~0; 1339 - /* counter is not written yet, so it is not in expwriteaddr */ 1340 - u32 expwriteaddr[] = {792, 793, 794, 795, 796, 797, 0}; 1346 + /* counter is written as the last operation */ 1347 + u32 expwriteaddr[] = {792, 793, 794, 795, 796, 797, 792}; 1341 1348 int idx; 1342 1349 1343 1350 vcap_test_api_init(&is2_admin); ··· 1390 1397 KUNIT_EXPECT_EQ(test, 6, ri->size); 1391 1398 KUNIT_EXPECT_EQ(test, 2, ri->keyset_sw_regs); 1392 1399 KUNIT_EXPECT_EQ(test, 4, ri->actionset_sw_regs); 1400 + 1401 + /* Enable lookup, so the rule will be written */ 1402 + ret = vcap_enable_lookups(&test_vctrl, &test_netdev, 0, 1403 + rule->vcap_chain_id, rule->cookie, true); 1404 + KUNIT_EXPECT_EQ(test, 0, ret); 1393 1405 1394 1406 /* Add rule with write callback */ 1395 1407 ret = vcap_add_rule(rule); ··· 1870 1872 ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000); 1871 1873 KUNIT_EXPECT_EQ(test, false, ret); 1872 1874 ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000); 1873 - KUNIT_EXPECT_EQ(test, true, ret); 1875 + KUNIT_EXPECT_EQ(test, false, ret); 1874 1876 } 1875 1877 1876 1878 static void vcap_api_next_lookup_advanced_test(struct kunit *test) ··· 1931 1933 ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1201000); 1932 1934 KUNIT_EXPECT_EQ(test, true, ret); 1933 1935 ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1301000); 1934 - KUNIT_EXPECT_EQ(test, false, ret); 1936 + KUNIT_EXPECT_EQ(test, true, ret); 1935 1937 ret = vcap_is_next_lookup(&test_vctrl, 1100000, 8101000); 1936 - KUNIT_EXPECT_EQ(test, false, ret); 1938 + KUNIT_EXPECT_EQ(test, true, ret); 1937 1939 ret = vcap_is_next_lookup(&test_vctrl, 1300000, 1401000); 1938 1940 KUNIT_EXPECT_EQ(test, true, ret); 1939 1941 ret = vcap_is_next_lookup(&test_vctrl, 1400000, 1501000); ··· 1949 1951 ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000); 1950 1952 KUNIT_EXPECT_EQ(test, false, ret); 1951 1953 ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000); 1952 - KUNIT_EXPECT_EQ(test, true, ret); 1954 + KUNIT_EXPECT_EQ(test, false, ret); 1953 1955 } 1954 1956 1955 1957 static void vcap_api_filter_unsupported_keys_test(struct kunit *test)
+10 -2
drivers/net/ethernet/microchip/vcap/vcap_api_private.h
··· 13 13 14 14 #define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data) 15 15 16 + enum vcap_rule_state { 17 + VCAP_RS_PERMANENT, /* the rule is always stored in HW */ 18 + VCAP_RS_ENABLED, /* enabled in HW but can be disabled */ 19 + VCAP_RS_DISABLED, /* disabled (stored in SW) and can be enabled */ 20 + }; 21 + 16 22 /* Private VCAP API rule data */ 17 23 struct vcap_rule_internal { 18 24 struct vcap_rule data; /* provided by the client */ ··· 35 29 u32 addr; /* address in the VCAP at insertion */ 36 30 u32 counter_id; /* counter id (if a dedicated counter is available) */ 37 31 struct vcap_counter counter; /* last read counter value */ 32 + enum vcap_rule_state state; /* rule storage state */ 38 33 }; 39 34 40 35 /* Bit iterator for the VCAP cache streams */ ··· 50 43 51 44 /* Check that the control has a valid set of callbacks */ 52 45 int vcap_api_check(struct vcap_control *ctrl); 53 - /* Make a shallow copy of the rule without the fields */ 54 - struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri); 55 46 /* Erase the VCAP cache area used or encoding and decoding */ 56 47 void vcap_erase_cache(struct vcap_rule_internal *ri); 57 48 ··· 115 110 u32 *keystream, u32 *mskstream, bool mask, 116 111 int sw_max, struct vcap_keyset_list *kslist); 117 112 113 + /* Get the keysets that matches the rule key type/mask */ 114 + int vcap_rule_get_keysets(struct vcap_rule_internal *ri, 115 + struct vcap_keyset_list *matches); 118 116 #endif /* __VCAP_API_PRIVATE__ */