提交 702e7014 编写于 作者: M Maksym Glubokiy 提交者: David S. Miller

net: prestera: acl: add support for 'egress' rules

The following is now supported:

  $ tc qdisc add PORT clsact
  $ tc filter add dev PORT egress ...
Signed-off-by: NMaksym Glubokiy <maksym.glubokiy@plvision.eu>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 04cfbc1d
...@@ -107,7 +107,8 @@ struct prestera_port_phy_config { ...@@ -107,7 +107,8 @@ struct prestera_port_phy_config {
struct prestera_port { struct prestera_port {
struct net_device *dev; struct net_device *dev;
struct prestera_switch *sw; struct prestera_switch *sw;
struct prestera_flow_block *flow_block; struct prestera_flow_block *ingress_flow_block;
struct prestera_flow_block *egress_flow_block;
struct devlink_port dl_port; struct devlink_port dl_port;
struct list_head lag_member; struct list_head lag_member;
struct prestera_lag *lag; struct prestera_lag *lag;
......
...@@ -61,6 +61,7 @@ struct prestera_acl_ruleset { ...@@ -61,6 +61,7 @@ struct prestera_acl_ruleset {
u32 index; u32 index;
u16 pcl_id; u16 pcl_id;
bool offload; bool offload;
bool ingress;
}; };
struct prestera_acl_vtcam { struct prestera_acl_vtcam {
...@@ -70,6 +71,7 @@ struct prestera_acl_vtcam { ...@@ -70,6 +71,7 @@ struct prestera_acl_vtcam {
u32 id; u32 id;
bool is_keymask_set; bool is_keymask_set;
u8 lookup; u8 lookup;
u8 direction;
}; };
static const struct rhashtable_params prestera_acl_ruleset_ht_params = { static const struct rhashtable_params prestera_acl_ruleset_ht_params = {
...@@ -93,23 +95,36 @@ static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = { ...@@ -93,23 +95,36 @@ static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = {
.automatic_shrinking = true, .automatic_shrinking = true,
}; };
int prestera_acl_chain_to_client(u32 chain_index, u32 *client) int prestera_acl_chain_to_client(u32 chain_index, bool ingress, u32 *client)
{ {
static const u32 client_map[] = { static const u32 ingress_client_map[] = {
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0, PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_0,
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1, PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_1,
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2 PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_2
}; };
if (chain_index >= ARRAY_SIZE(client_map)) if (!ingress) {
/* prestera supports only one chain on egress */
if (chain_index > 0)
return -EINVAL;
*client = PRESTERA_HW_COUNTER_CLIENT_EGRESS_LOOKUP;
return 0;
}
if (chain_index >= ARRAY_SIZE(ingress_client_map))
return -EINVAL; return -EINVAL;
*client = client_map[chain_index]; *client = ingress_client_map[chain_index];
return 0; return 0;
} }
static bool prestera_acl_chain_is_supported(u32 chain_index) static bool prestera_acl_chain_is_supported(u32 chain_index, bool ingress)
{ {
if (!ingress)
/* prestera supports only one chain on egress */
return chain_index == 0;
return (chain_index & ~PRESTERA_ACL_CHAIN_MASK) == 0; return (chain_index & ~PRESTERA_ACL_CHAIN_MASK) == 0;
} }
...@@ -122,7 +137,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl, ...@@ -122,7 +137,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
u32 uid = 0; u32 uid = 0;
int err; int err;
if (!prestera_acl_chain_is_supported(chain_index)) if (!prestera_acl_chain_is_supported(chain_index, block->ingress))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL); ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL);
...@@ -130,6 +145,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl, ...@@ -130,6 +145,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ruleset->acl = acl; ruleset->acl = acl;
ruleset->ingress = block->ingress;
ruleset->ht_key.block = block; ruleset->ht_key.block = block;
ruleset->ht_key.chain_index = chain_index; ruleset->ht_key.chain_index = chain_index;
refcount_set(&ruleset->refcount, 1); refcount_set(&ruleset->refcount, 1);
...@@ -172,13 +188,18 @@ int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset) ...@@ -172,13 +188,18 @@ int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset)
{ {
struct prestera_acl_iface iface; struct prestera_acl_iface iface;
u32 vtcam_id; u32 vtcam_id;
int dir;
int err; int err;
dir = ruleset->ingress ?
PRESTERA_HW_VTCAM_DIR_INGRESS : PRESTERA_HW_VTCAM_DIR_EGRESS;
if (ruleset->offload) if (ruleset->offload)
return -EEXIST; return -EEXIST;
err = prestera_acl_vtcam_id_get(ruleset->acl, err = prestera_acl_vtcam_id_get(ruleset->acl,
ruleset->ht_key.chain_index, ruleset->ht_key.chain_index,
dir,
ruleset->keymask, &vtcam_id); ruleset->keymask, &vtcam_id);
if (err) if (err)
goto err_vtcam_create; goto err_vtcam_create;
...@@ -719,7 +740,7 @@ static int __prestera_acl_vtcam_id_try_fit(struct prestera_acl *acl, u8 lookup, ...@@ -719,7 +740,7 @@ static int __prestera_acl_vtcam_id_try_fit(struct prestera_acl *acl, u8 lookup,
return 0; return 0;
} }
int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, u8 dir,
void *keymask, u32 *vtcam_id) void *keymask, u32 *vtcam_id)
{ {
struct prestera_acl_vtcam *vtcam; struct prestera_acl_vtcam *vtcam;
...@@ -731,7 +752,8 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, ...@@ -731,7 +752,8 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
* fine for now * fine for now
*/ */
list_for_each_entry(vtcam, &acl->vtcam_list, list) { list_for_each_entry(vtcam, &acl->vtcam_list, list) {
if (lookup != vtcam->lookup) if (lookup != vtcam->lookup ||
dir != vtcam->direction)
continue; continue;
if (!keymask && !vtcam->is_keymask_set) { if (!keymask && !vtcam->is_keymask_set) {
...@@ -752,7 +774,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, ...@@ -752,7 +774,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
return -ENOMEM; return -ENOMEM;
err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id, err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id,
PRESTERA_HW_VTCAM_DIR_INGRESS); dir);
if (err) { if (err) {
kfree(vtcam); kfree(vtcam);
...@@ -765,6 +787,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, ...@@ -765,6 +787,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
return 0; return 0;
} }
vtcam->direction = dir;
vtcam->id = new_vtcam_id; vtcam->id = new_vtcam_id;
vtcam->lookup = lookup; vtcam->lookup = lookup;
if (keymask) { if (keymask) {
......
...@@ -199,9 +199,9 @@ void ...@@ -199,9 +199,9 @@ void
prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule,
u16 pcl_id); u16 pcl_id);
int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, u8 dir,
void *keymask, u32 *vtcam_id); void *keymask, u32 *vtcam_id);
int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id); int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id);
int prestera_acl_chain_to_client(u32 chain_index, u32 *client); int prestera_acl_chain_to_client(u32 chain_index, bool ingress, u32 *client);
#endif /* _PRESTERA_ACL_H_ */ #endif /* _PRESTERA_ACL_H_ */
...@@ -75,7 +75,9 @@ static void prestera_flow_block_destroy(void *cb_priv) ...@@ -75,7 +75,9 @@ static void prestera_flow_block_destroy(void *cb_priv)
} }
static struct prestera_flow_block * static struct prestera_flow_block *
prestera_flow_block_create(struct prestera_switch *sw, struct net *net) prestera_flow_block_create(struct prestera_switch *sw,
struct net *net,
bool ingress)
{ {
struct prestera_flow_block *block; struct prestera_flow_block *block;
...@@ -87,6 +89,7 @@ prestera_flow_block_create(struct prestera_switch *sw, struct net *net) ...@@ -87,6 +89,7 @@ prestera_flow_block_create(struct prestera_switch *sw, struct net *net)
INIT_LIST_HEAD(&block->template_list); INIT_LIST_HEAD(&block->template_list);
block->net = net; block->net = net;
block->sw = sw; block->sw = sw;
block->ingress = ingress;
return block; return block;
} }
...@@ -165,7 +168,8 @@ static int prestera_flow_block_unbind(struct prestera_flow_block *block, ...@@ -165,7 +168,8 @@ static int prestera_flow_block_unbind(struct prestera_flow_block *block,
static struct prestera_flow_block * static struct prestera_flow_block *
prestera_flow_block_get(struct prestera_switch *sw, prestera_flow_block_get(struct prestera_switch *sw,
struct flow_block_offload *f, struct flow_block_offload *f,
bool *register_block) bool *register_block,
bool ingress)
{ {
struct prestera_flow_block *block; struct prestera_flow_block *block;
struct flow_block_cb *block_cb; struct flow_block_cb *block_cb;
...@@ -173,7 +177,7 @@ prestera_flow_block_get(struct prestera_switch *sw, ...@@ -173,7 +177,7 @@ prestera_flow_block_get(struct prestera_switch *sw,
block_cb = flow_block_cb_lookup(f->block, block_cb = flow_block_cb_lookup(f->block,
prestera_flow_block_cb, sw); prestera_flow_block_cb, sw);
if (!block_cb) { if (!block_cb) {
block = prestera_flow_block_create(sw, f->net); block = prestera_flow_block_create(sw, f->net, ingress);
if (!block) if (!block)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -209,7 +213,7 @@ static void prestera_flow_block_put(struct prestera_flow_block *block) ...@@ -209,7 +213,7 @@ static void prestera_flow_block_put(struct prestera_flow_block *block)
} }
static int prestera_setup_flow_block_bind(struct prestera_port *port, static int prestera_setup_flow_block_bind(struct prestera_port *port,
struct flow_block_offload *f) struct flow_block_offload *f, bool ingress)
{ {
struct prestera_switch *sw = port->sw; struct prestera_switch *sw = port->sw;
struct prestera_flow_block *block; struct prestera_flow_block *block;
...@@ -217,7 +221,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port, ...@@ -217,7 +221,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
bool register_block; bool register_block;
int err; int err;
block = prestera_flow_block_get(sw, f, &register_block); block = prestera_flow_block_get(sw, f, &register_block, ingress);
if (IS_ERR(block)) if (IS_ERR(block))
return PTR_ERR(block); return PTR_ERR(block);
...@@ -232,7 +236,11 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port, ...@@ -232,7 +236,11 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
list_add_tail(&block_cb->driver_list, &prestera_block_cb_list); list_add_tail(&block_cb->driver_list, &prestera_block_cb_list);
} }
port->flow_block = block; if (ingress)
port->ingress_flow_block = block;
else
port->egress_flow_block = block;
return 0; return 0;
err_block_bind: err_block_bind:
...@@ -242,7 +250,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port, ...@@ -242,7 +250,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
} }
static void prestera_setup_flow_block_unbind(struct prestera_port *port, static void prestera_setup_flow_block_unbind(struct prestera_port *port,
struct flow_block_offload *f) struct flow_block_offload *f, bool ingress)
{ {
struct prestera_switch *sw = port->sw; struct prestera_switch *sw = port->sw;
struct prestera_flow_block *block; struct prestera_flow_block *block;
...@@ -266,24 +274,38 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port, ...@@ -266,24 +274,38 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port,
list_del(&block_cb->driver_list); list_del(&block_cb->driver_list);
} }
error: error:
port->flow_block = NULL; if (ingress)
port->ingress_flow_block = NULL;
else
port->egress_flow_block = NULL;
} }
int prestera_flow_block_setup(struct prestera_port *port, static int prestera_setup_flow_block_clsact(struct prestera_port *port,
struct flow_block_offload *f) struct flow_block_offload *f,
bool ingress)
{ {
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
f->driver_block_list = &prestera_block_cb_list; f->driver_block_list = &prestera_block_cb_list;
switch (f->command) { switch (f->command) {
case FLOW_BLOCK_BIND: case FLOW_BLOCK_BIND:
return prestera_setup_flow_block_bind(port, f); return prestera_setup_flow_block_bind(port, f, ingress);
case FLOW_BLOCK_UNBIND: case FLOW_BLOCK_UNBIND:
prestera_setup_flow_block_unbind(port, f); prestera_setup_flow_block_unbind(port, f, ingress);
return 0; return 0;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
} }
int prestera_flow_block_setup(struct prestera_port *port,
struct flow_block_offload *f)
{
switch (f->binder_type) {
case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:
return prestera_setup_flow_block_clsact(port, f, true);
case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:
return prestera_setup_flow_block_clsact(port, f, false);
default:
return -EOPNOTSUPP;
}
}
...@@ -23,6 +23,7 @@ struct prestera_flow_block { ...@@ -23,6 +23,7 @@ struct prestera_flow_block {
struct flow_block_cb *block_cb; struct flow_block_cb *block_cb;
struct list_head template_list; struct list_head template_list;
unsigned int rule_count; unsigned int rule_count;
bool ingress;
}; };
int prestera_flow_block_setup(struct prestera_port *port, int prestera_flow_block_setup(struct prestera_port *port,
......
...@@ -79,7 +79,7 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block, ...@@ -79,7 +79,7 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block,
} else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) { } else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) {
/* setup counter first */ /* setup counter first */
rule->re_arg.count.valid = true; rule->re_arg.count.valid = true;
err = prestera_acl_chain_to_client(chain_index, err = prestera_acl_chain_to_client(chain_index, block->ingress,
&rule->re_arg.count.client); &rule->re_arg.count.client);
if (err) if (err)
return err; return err;
......
...@@ -123,9 +123,10 @@ enum prestera_hw_vtcam_direction_t { ...@@ -123,9 +123,10 @@ enum prestera_hw_vtcam_direction_t {
}; };
enum { enum {
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0 = 0, PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_0 = 0,
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1 = 1, PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_1 = 1,
PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2 = 2, PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_2 = 2,
PRESTERA_HW_COUNTER_CLIENT_EGRESS_LOOKUP = 3,
}; };
struct prestera_switch; struct prestera_switch;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册