提交 47327e19 编写于 作者: V Volodymyr Mytnyk 提交者: David S. Miller

net: prestera: acl: migrate to new vTCAM api

- Add new vTCAM HW API to configure HW ACLs.
- Migrate acl to use new vTCAM HW API.
- No counter support in this patch-set.
Co-developed-by: NYevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: NYevhen Orlov <yevhen.orlov@plvision.eu>
Signed-off-by: NVolodymyr Mytnyk <vmytnyk@marvell.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 4c897cfc
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/* Copyright (c) 2020 Marvell International Ltd. All rights reserved. */ /* Copyright (c) 2020-2021 Marvell International Ltd. All rights reserved. */
#ifndef _PRESTERA_ACL_H_ #ifndef _PRESTERA_ACL_H_
#define _PRESTERA_ACL_H_ #define _PRESTERA_ACL_H_
enum prestera_acl_rule_match_entry_type { #include <linux/types.h>
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE = 1,
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC, #define PRESTERA_ACL_KEYMASK_PCL_ID 0x3FF
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC, #define PRESTERA_ACL_KEYMASK_PCL_ID_USER \
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO, (PRESTERA_ACL_KEYMASK_PCL_ID & 0x00FF)
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT,
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC, #define rule_match_set_n(match_p, type, val_p, size) \
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST, memcpy(&(match_p)[PRESTERA_ACL_RULE_MATCH_TYPE_##type], \
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC, val_p, size)
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST, #define rule_match_set(match_p, type, val) \
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_SRC, memcpy(&(match_p)[PRESTERA_ACL_RULE_MATCH_TYPE_##type], \
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_DST, &(val), sizeof(val))
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID,
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID, enum prestera_acl_match_type {
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE, PRESTERA_ACL_RULE_MATCH_TYPE_PCL_ID,
PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE PRESTERA_ACL_RULE_MATCH_TYPE_ETH_TYPE,
PRESTERA_ACL_RULE_MATCH_TYPE_ETH_DMAC_0,
PRESTERA_ACL_RULE_MATCH_TYPE_ETH_DMAC_1,
PRESTERA_ACL_RULE_MATCH_TYPE_ETH_SMAC_0,
PRESTERA_ACL_RULE_MATCH_TYPE_ETH_SMAC_1,
PRESTERA_ACL_RULE_MATCH_TYPE_IP_PROTO,
PRESTERA_ACL_RULE_MATCH_TYPE_SYS_PORT,
PRESTERA_ACL_RULE_MATCH_TYPE_SYS_DEV,
PRESTERA_ACL_RULE_MATCH_TYPE_IP_SRC,
PRESTERA_ACL_RULE_MATCH_TYPE_IP_DST,
PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_SRC,
PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_DST,
PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_RANGE_SRC,
PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_RANGE_DST,
PRESTERA_ACL_RULE_MATCH_TYPE_VLAN_ID,
PRESTERA_ACL_RULE_MATCH_TYPE_VLAN_TPID,
PRESTERA_ACL_RULE_MATCH_TYPE_ICMP_TYPE,
PRESTERA_ACL_RULE_MATCH_TYPE_ICMP_CODE,
__PRESTERA_ACL_RULE_MATCH_TYPE_MAX
}; };
enum prestera_acl_rule_action { enum prestera_acl_rule_action {
PRESTERA_ACL_RULE_ACTION_ACCEPT, PRESTERA_ACL_RULE_ACTION_ACCEPT = 0,
PRESTERA_ACL_RULE_ACTION_DROP, PRESTERA_ACL_RULE_ACTION_DROP = 1,
PRESTERA_ACL_RULE_ACTION_TRAP PRESTERA_ACL_RULE_ACTION_TRAP = 2,
PRESTERA_ACL_RULE_ACTION_COUNT = 7,
PRESTERA_ACL_RULE_ACTION_MAX
}; };
struct prestera_switch; enum {
struct prestera_port; PRESTERA_ACL_IFACE_TYPE_PORT,
struct prestera_acl_rule; PRESTERA_ACL_IFACE_TYPE_INDEX
struct prestera_acl_ruleset; };
struct prestera_flow_block_binding { struct prestera_acl_match {
struct list_head list; __be32 key[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];
struct prestera_port *port; __be32 mask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];
int span_id;
}; };
struct prestera_flow_block { struct prestera_acl_rule_entry_key {
struct list_head binding_list; u32 prio;
struct prestera_switch *sw; struct prestera_acl_match match;
struct net *net;
struct prestera_acl_ruleset *ruleset;
struct flow_block_cb *block_cb;
}; };
struct prestera_acl_rule_action_entry { struct prestera_acl_hw_action_info {
struct list_head list;
enum prestera_acl_rule_action id; enum prestera_acl_rule_action id;
}; };
struct prestera_acl_rule_match_entry { /* This struct (arg) used only to be passed as parameter for
struct list_head list; * acl_rule_entry_create. Must be flat. Can contain object keys, which will be
enum prestera_acl_rule_match_entry_type type; * resolved to object links, before saving to acl_rule_entry struct
union { */
struct { struct prestera_acl_rule_entry_arg {
u8 key; u32 vtcam_id;
u8 mask;
} u8;
struct { struct {
u16 key;
u16 mask;
} u16;
struct { struct {
u32 key; u8 valid:1;
u32 mask; } accept, drop, trap;
} u32; };
struct {
u64 key;
u64 mask;
} u64;
struct {
u8 key[ETH_ALEN];
u8 mask[ETH_ALEN];
} mac;
} keymask;
}; };
struct prestera_acl_rule {
struct rhash_head ht_node; /* Member of acl HT */
struct list_head list;
struct prestera_acl_ruleset *ruleset;
unsigned long cookie;
u32 priority;
struct prestera_acl_rule_entry_key re_key;
struct prestera_acl_rule_entry_arg re_arg;
struct prestera_acl_rule_entry *re;
};
struct prestera_acl_iface {
union {
struct prestera_port *port;
u32 index;
};
u8 type;
};
struct prestera_acl;
struct prestera_switch;
struct prestera_flow_block;
int prestera_acl_init(struct prestera_switch *sw); int prestera_acl_init(struct prestera_switch *sw);
void prestera_acl_fini(struct prestera_switch *sw); void prestera_acl_fini(struct prestera_switch *sw);
struct prestera_flow_block *
prestera_acl_block_create(struct prestera_switch *sw, struct net *net);
void prestera_acl_block_destroy(struct prestera_flow_block *block);
struct net *prestera_acl_block_net(struct prestera_flow_block *block);
struct prestera_switch *prestera_acl_block_sw(struct prestera_flow_block *block);
int prestera_acl_block_bind(struct prestera_flow_block *block,
struct prestera_port *port);
int prestera_acl_block_unbind(struct prestera_flow_block *block,
struct prestera_port *port);
struct prestera_acl_ruleset *
prestera_acl_block_ruleset_get(struct prestera_flow_block *block);
struct prestera_acl_rule * struct prestera_acl_rule *
prestera_acl_rule_create(struct prestera_flow_block *block, prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset,
unsigned long cookie); unsigned long cookie);
u32 prestera_acl_rule_priority_get(struct prestera_acl_rule *rule);
void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule, void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule,
u32 priority); u32 priority);
u16 prestera_acl_rule_ruleset_id_get(const struct prestera_acl_rule *rule);
struct list_head *
prestera_acl_rule_action_list_get(struct prestera_acl_rule *rule);
u8 prestera_acl_rule_action_len(struct prestera_acl_rule *rule);
u8 prestera_acl_rule_match_len(struct prestera_acl_rule *rule);
int prestera_acl_rule_action_add(struct prestera_acl_rule *rule,
struct prestera_acl_rule_action_entry *entry);
struct list_head *
prestera_acl_rule_match_list_get(struct prestera_acl_rule *rule);
int prestera_acl_rule_match_add(struct prestera_acl_rule *rule,
struct prestera_acl_rule_match_entry *entry);
void prestera_acl_rule_destroy(struct prestera_acl_rule *rule); void prestera_acl_rule_destroy(struct prestera_acl_rule *rule);
struct prestera_acl_rule * struct prestera_acl_rule *
prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset, prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset,
...@@ -117,8 +121,37 @@ int prestera_acl_rule_add(struct prestera_switch *sw, ...@@ -117,8 +121,37 @@ int prestera_acl_rule_add(struct prestera_switch *sw,
struct prestera_acl_rule *rule); struct prestera_acl_rule *rule);
void prestera_acl_rule_del(struct prestera_switch *sw, void prestera_acl_rule_del(struct prestera_switch *sw,
struct prestera_acl_rule *rule); struct prestera_acl_rule *rule);
int prestera_acl_rule_get_stats(struct prestera_switch *sw, int prestera_acl_rule_get_stats(struct prestera_acl *acl,
struct prestera_acl_rule *rule, struct prestera_acl_rule *rule,
u64 *packets, u64 *bytes, u64 *last_use); u64 *packets, u64 *bytes, u64 *last_use);
struct prestera_acl_rule_entry *
prestera_acl_rule_entry_find(struct prestera_acl *acl,
struct prestera_acl_rule_entry_key *key);
void prestera_acl_rule_entry_destroy(struct prestera_acl *acl,
struct prestera_acl_rule_entry *e);
struct prestera_acl_rule_entry *
prestera_acl_rule_entry_create(struct prestera_acl *acl,
struct prestera_acl_rule_entry_key *key,
struct prestera_acl_rule_entry_arg *arg);
struct prestera_acl_ruleset *
prestera_acl_ruleset_get(struct prestera_acl *acl,
struct prestera_flow_block *block);
struct prestera_acl_ruleset *
prestera_acl_ruleset_lookup(struct prestera_acl *acl,
struct prestera_flow_block *block);
bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset);
int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset);
void prestera_acl_ruleset_put(struct prestera_acl_ruleset *ruleset);
int prestera_acl_ruleset_bind(struct prestera_acl_ruleset *ruleset,
struct prestera_port *port);
int prestera_acl_ruleset_unbind(struct prestera_acl_ruleset *ruleset,
struct prestera_port *port);
void
prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule,
u16 pcl_id);
int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
void *keymask, u32 *vtcam_id);
int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id);
#endif /* _PRESTERA_ACL_H_ */ #endif /* _PRESTERA_ACL_H_ */
...@@ -60,11 +60,100 @@ static int prestera_flow_block_cb(enum tc_setup_type type, ...@@ -60,11 +60,100 @@ static int prestera_flow_block_cb(enum tc_setup_type type,
} }
} }
static void prestera_flow_block_destroy(void *cb_priv)
{
struct prestera_flow_block *block = cb_priv;
WARN_ON(!list_empty(&block->binding_list));
kfree(block);
}
static struct prestera_flow_block *
prestera_flow_block_create(struct prestera_switch *sw, struct net *net)
{
struct prestera_flow_block *block;
block = kzalloc(sizeof(*block), GFP_KERNEL);
if (!block)
return NULL;
INIT_LIST_HEAD(&block->binding_list);
block->net = net;
block->sw = sw;
return block;
}
static void prestera_flow_block_release(void *cb_priv) static void prestera_flow_block_release(void *cb_priv)
{ {
struct prestera_flow_block *block = cb_priv; struct prestera_flow_block *block = cb_priv;
prestera_acl_block_destroy(block); prestera_flow_block_destroy(block);
}
static bool
prestera_flow_block_is_bound(const struct prestera_flow_block *block)
{
return block->ruleset_zero;
}
static struct prestera_flow_block_binding *
prestera_flow_block_lookup(struct prestera_flow_block *block,
struct prestera_port *port)
{
struct prestera_flow_block_binding *binding;
list_for_each_entry(binding, &block->binding_list, list)
if (binding->port == port)
return binding;
return NULL;
}
static int prestera_flow_block_bind(struct prestera_flow_block *block,
struct prestera_port *port)
{
struct prestera_flow_block_binding *binding;
int err;
binding = kzalloc(sizeof(*binding), GFP_KERNEL);
if (!binding)
return -ENOMEM;
binding->span_id = PRESTERA_SPAN_INVALID_ID;
binding->port = port;
if (prestera_flow_block_is_bound(block)) {
err = prestera_acl_ruleset_bind(block->ruleset_zero, port);
if (err)
goto err_ruleset_bind;
}
list_add(&binding->list, &block->binding_list);
return 0;
err_ruleset_bind:
kfree(binding);
return err;
}
static int prestera_flow_block_unbind(struct prestera_flow_block *block,
struct prestera_port *port)
{
struct prestera_flow_block_binding *binding;
binding = prestera_flow_block_lookup(block, port);
if (!binding)
return -ENOENT;
list_del(&binding->list);
if (prestera_flow_block_is_bound(block))
prestera_acl_ruleset_unbind(block->ruleset_zero, port);
kfree(binding);
return 0;
} }
static struct prestera_flow_block * static struct prestera_flow_block *
...@@ -78,7 +167,7 @@ prestera_flow_block_get(struct prestera_switch *sw, ...@@ -78,7 +167,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_acl_block_create(sw, f->net); block = prestera_flow_block_create(sw, f->net);
if (!block) if (!block)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -86,7 +175,7 @@ prestera_flow_block_get(struct prestera_switch *sw, ...@@ -86,7 +175,7 @@ prestera_flow_block_get(struct prestera_switch *sw,
sw, block, sw, block,
prestera_flow_block_release); prestera_flow_block_release);
if (IS_ERR(block_cb)) { if (IS_ERR(block_cb)) {
prestera_acl_block_destroy(block); prestera_flow_block_destroy(block);
return ERR_CAST(block_cb); return ERR_CAST(block_cb);
} }
...@@ -110,7 +199,7 @@ static void prestera_flow_block_put(struct prestera_flow_block *block) ...@@ -110,7 +199,7 @@ static void prestera_flow_block_put(struct prestera_flow_block *block)
return; return;
flow_block_cb_free(block_cb); flow_block_cb_free(block_cb);
prestera_acl_block_destroy(block); prestera_flow_block_destroy(block);
} }
static int prestera_setup_flow_block_bind(struct prestera_port *port, static int prestera_setup_flow_block_bind(struct prestera_port *port,
...@@ -128,7 +217,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port, ...@@ -128,7 +217,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
block_cb = block->block_cb; block_cb = block->block_cb;
err = prestera_acl_block_bind(block, port); err = prestera_flow_block_bind(block, port);
if (err) if (err)
goto err_block_bind; goto err_block_bind;
...@@ -162,7 +251,7 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port, ...@@ -162,7 +251,7 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port,
prestera_span_destroy(block); prestera_span_destroy(block);
err = prestera_acl_block_unbind(block, port); err = prestera_flow_block_unbind(block, port);
if (err) if (err)
goto error; goto error;
......
...@@ -7,6 +7,22 @@ ...@@ -7,6 +7,22 @@
#include <net/flow_offload.h> #include <net/flow_offload.h>
struct prestera_port; struct prestera_port;
struct prestera_switch;
struct prestera_flow_block_binding {
struct list_head list;
struct prestera_port *port;
int span_id;
};
struct prestera_flow_block {
struct list_head binding_list;
struct prestera_switch *sw;
unsigned int rule_count;
struct net *net;
struct prestera_acl_ruleset *ruleset_zero;
struct flow_block_cb *block_cb;
};
int prestera_flow_block_setup(struct prestera_port *port, int prestera_flow_block_setup(struct prestera_port *port,
struct flow_block_offload *f); struct flow_block_offload *f);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "prestera.h" #include "prestera.h"
#include "prestera_acl.h" #include "prestera_acl.h"
#include "prestera_flow.h"
#include "prestera_flower.h" #include "prestera_flower.h"
static int prestera_flower_parse_actions(struct prestera_flow_block *block, static int prestera_flower_parse_actions(struct prestera_flow_block *block,
...@@ -10,35 +11,38 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block, ...@@ -10,35 +11,38 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block,
struct flow_action *flow_action, struct flow_action *flow_action,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct prestera_acl_rule_action_entry a_entry;
const struct flow_action_entry *act; const struct flow_action_entry *act;
int err, i; int i;
/* whole struct (rule->re_arg) must be initialized with 0 */
if (!flow_action_has_entries(flow_action)) if (!flow_action_has_entries(flow_action))
return 0; return 0;
flow_action_for_each(i, act, flow_action) { flow_action_for_each(i, act, flow_action) {
memset(&a_entry, 0, sizeof(a_entry));
switch (act->id) { switch (act->id) {
case FLOW_ACTION_ACCEPT: case FLOW_ACTION_ACCEPT:
a_entry.id = PRESTERA_ACL_RULE_ACTION_ACCEPT; if (rule->re_arg.accept.valid)
return -EEXIST;
rule->re_arg.accept.valid = 1;
break; break;
case FLOW_ACTION_DROP: case FLOW_ACTION_DROP:
a_entry.id = PRESTERA_ACL_RULE_ACTION_DROP; if (rule->re_arg.drop.valid)
return -EEXIST;
rule->re_arg.drop.valid = 1;
break; break;
case FLOW_ACTION_TRAP: case FLOW_ACTION_TRAP:
a_entry.id = PRESTERA_ACL_RULE_ACTION_TRAP; if (rule->re_arg.trap.valid)
return -EEXIST;
rule->re_arg.trap.valid = 1;
break; break;
default: default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported action"); NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
pr_err("Unsupported action\n"); pr_err("Unsupported action\n");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
err = prestera_acl_rule_action_add(rule, &a_entry);
if (err)
return err;
} }
return 0; return 0;
...@@ -47,12 +51,12 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block, ...@@ -47,12 +51,12 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block,
static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
struct flow_cls_offload *f, struct flow_cls_offload *f,
struct prestera_flow_block *block) struct prestera_flow_block *block)
{ { struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
struct flow_rule *f_rule = flow_cls_offload_flow_rule(f); struct prestera_acl_match *r_match = &rule->re_key.match;
struct prestera_acl_rule_match_entry m_entry = {0}; struct prestera_port *port;
struct net_device *ingress_dev; struct net_device *ingress_dev;
struct flow_match_meta match; struct flow_match_meta match;
struct prestera_port *port; __be16 key, mask;
flow_rule_match_meta(f_rule, &match); flow_rule_match_meta(f_rule, &match);
if (match.mask->ingress_ifindex != 0xFFFFFFFF) { if (match.mask->ingress_ifindex != 0xFFFFFFFF) {
...@@ -61,7 +65,7 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, ...@@ -61,7 +65,7 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
return -EINVAL; return -EINVAL;
} }
ingress_dev = __dev_get_by_index(prestera_acl_block_net(block), ingress_dev = __dev_get_by_index(block->net,
match.key->ingress_ifindex); match.key->ingress_ifindex);
if (!ingress_dev) { if (!ingress_dev) {
NL_SET_ERR_MSG_MOD(f->common.extack, NL_SET_ERR_MSG_MOD(f->common.extack,
...@@ -76,22 +80,28 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, ...@@ -76,22 +80,28 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
} }
port = netdev_priv(ingress_dev); port = netdev_priv(ingress_dev);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT; mask = htons(0x1FFF);
m_entry.keymask.u64.key = port->hw_id | ((u64)port->dev_id << 32); key = htons(port->hw_id);
m_entry.keymask.u64.mask = ~(u64)0; rule_match_set(r_match->key, SYS_PORT, key);
rule_match_set(r_match->mask, SYS_PORT, mask);
mask = htons(0x1FF);
key = htons(port->dev_id);
rule_match_set(r_match->key, SYS_DEV, key);
rule_match_set(r_match->mask, SYS_DEV, mask);
return 0;
return prestera_acl_rule_match_add(rule, &m_entry);
} }
static int prestera_flower_parse(struct prestera_flow_block *block, static int prestera_flower_parse(struct prestera_flow_block *block,
struct prestera_acl_rule *rule, struct prestera_acl_rule *rule,
struct flow_cls_offload *f) struct flow_cls_offload *f)
{ { struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
struct flow_rule *f_rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = f_rule->match.dissector; struct flow_dissector *dissector = f_rule->match.dissector;
struct prestera_acl_rule_match_entry m_entry; struct prestera_acl_match *r_match = &rule->re_key.match;
u16 n_proto_mask = 0; __be16 n_proto_mask = 0;
u16 n_proto_key = 0; __be16 n_proto_key = 0;
u16 addr_type = 0; u16 addr_type = 0;
u8 ip_proto = 0; u8 ip_proto = 0;
int err; int err;
...@@ -129,32 +139,19 @@ static int prestera_flower_parse(struct prestera_flow_block *block, ...@@ -129,32 +139,19 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
struct flow_match_basic match; struct flow_match_basic match;
flow_rule_match_basic(f_rule, &match); flow_rule_match_basic(f_rule, &match);
n_proto_key = ntohs(match.key->n_proto); n_proto_key = match.key->n_proto;
n_proto_mask = ntohs(match.mask->n_proto); n_proto_mask = match.mask->n_proto;
if (n_proto_key == ETH_P_ALL) { if (ntohs(match.key->n_proto) == ETH_P_ALL) {
n_proto_key = 0; n_proto_key = 0;
n_proto_mask = 0; n_proto_mask = 0;
} }
/* add eth type key,mask */ rule_match_set(r_match->key, ETH_TYPE, n_proto_key);
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->mask, ETH_TYPE, n_proto_mask);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE;
m_entry.keymask.u16.key = n_proto_key;
m_entry.keymask.u16.mask = n_proto_mask;
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
/* add ip proto key,mask */
memset(&m_entry, 0, sizeof(m_entry));
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO;
m_entry.keymask.u8.key = match.key->ip_proto;
m_entry.keymask.u8.mask = match.mask->ip_proto;
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
rule_match_set(r_match->key, IP_PROTO, match.key->ip_proto);
rule_match_set(r_match->mask, IP_PROTO, match.mask->ip_proto);
ip_proto = match.key->ip_proto; ip_proto = match.key->ip_proto;
} }
...@@ -163,27 +160,27 @@ static int prestera_flower_parse(struct prestera_flow_block *block, ...@@ -163,27 +160,27 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
flow_rule_match_eth_addrs(f_rule, &match); flow_rule_match_eth_addrs(f_rule, &match);
/* add ethernet dst key,mask */ /* DA key, mask */
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set_n(r_match->key,
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC; ETH_DMAC_0, &match.key->dst[0], 4);
memcpy(&m_entry.keymask.mac.key, rule_match_set_n(r_match->key,
&match.key->dst, sizeof(match.key->dst)); ETH_DMAC_1, &match.key->dst[4], 2);
memcpy(&m_entry.keymask.mac.mask,
&match.mask->dst, sizeof(match.mask->dst)); rule_match_set_n(r_match->mask,
err = prestera_acl_rule_match_add(rule, &m_entry); ETH_DMAC_0, &match.mask->dst[0], 4);
if (err) rule_match_set_n(r_match->mask,
return err; ETH_DMAC_1, &match.mask->dst[4], 2);
/* add ethernet src key,mask */ /* SA key, mask */
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set_n(r_match->key,
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC; ETH_SMAC_0, &match.key->src[0], 4);
memcpy(&m_entry.keymask.mac.key, rule_match_set_n(r_match->key,
&match.key->src, sizeof(match.key->src)); ETH_SMAC_1, &match.key->src[4], 2);
memcpy(&m_entry.keymask.mac.mask,
&match.mask->src, sizeof(match.mask->src)); rule_match_set_n(r_match->mask,
err = prestera_acl_rule_match_add(rule, &m_entry); ETH_SMAC_0, &match.mask->src[0], 4);
if (err) rule_match_set_n(r_match->mask,
return err; ETH_SMAC_1, &match.mask->src[4], 2);
} }
if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
...@@ -191,25 +188,11 @@ static int prestera_flower_parse(struct prestera_flow_block *block, ...@@ -191,25 +188,11 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
flow_rule_match_ipv4_addrs(f_rule, &match); flow_rule_match_ipv4_addrs(f_rule, &match);
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->key, IP_SRC, match.key->src);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC; rule_match_set(r_match->mask, IP_SRC, match.mask->src);
memcpy(&m_entry.keymask.u32.key,
&match.key->src, sizeof(match.key->src));
memcpy(&m_entry.keymask.u32.mask,
&match.mask->src, sizeof(match.mask->src));
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->key, IP_DST, match.key->dst);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST; rule_match_set(r_match->mask, IP_DST, match.mask->dst);
memcpy(&m_entry.keymask.u32.key,
&match.key->dst, sizeof(match.key->dst));
memcpy(&m_entry.keymask.u32.mask,
&match.mask->dst, sizeof(match.mask->dst));
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
} }
if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) { if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) {
...@@ -224,21 +207,11 @@ static int prestera_flower_parse(struct prestera_flow_block *block, ...@@ -224,21 +207,11 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
flow_rule_match_ports(f_rule, &match); flow_rule_match_ports(f_rule, &match);
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->key, L4_PORT_SRC, match.key->src);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC; rule_match_set(r_match->mask, L4_PORT_SRC, match.mask->src);
m_entry.keymask.u16.key = ntohs(match.key->src);
m_entry.keymask.u16.mask = ntohs(match.mask->src);
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->key, L4_PORT_DST, match.key->dst);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST; rule_match_set(r_match->mask, L4_PORT_DST, match.mask->dst);
m_entry.keymask.u16.key = ntohs(match.key->dst);
m_entry.keymask.u16.mask = ntohs(match.mask->dst);
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
} }
if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) { if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) {
...@@ -247,22 +220,15 @@ static int prestera_flower_parse(struct prestera_flow_block *block, ...@@ -247,22 +220,15 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
flow_rule_match_vlan(f_rule, &match); flow_rule_match_vlan(f_rule, &match);
if (match.mask->vlan_id != 0) { if (match.mask->vlan_id != 0) {
memset(&m_entry, 0, sizeof(m_entry)); __be16 key = cpu_to_be16(match.key->vlan_id);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID; __be16 mask = cpu_to_be16(match.mask->vlan_id);
m_entry.keymask.u16.key = match.key->vlan_id;
m_entry.keymask.u16.mask = match.mask->vlan_id; rule_match_set(r_match->key, VLAN_ID, key);
err = prestera_acl_rule_match_add(rule, &m_entry); rule_match_set(r_match->mask, VLAN_ID, mask);
if (err)
return err;
} }
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->key, VLAN_TPID, match.key->vlan_tpid);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID; rule_match_set(r_match->mask, VLAN_TPID, match.mask->vlan_tpid);
m_entry.keymask.u16.key = ntohs(match.key->vlan_tpid);
m_entry.keymask.u16.mask = ntohs(match.mask->vlan_tpid);
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
} }
if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) { if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) {
...@@ -270,90 +236,109 @@ static int prestera_flower_parse(struct prestera_flow_block *block, ...@@ -270,90 +236,109 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
flow_rule_match_icmp(f_rule, &match); flow_rule_match_icmp(f_rule, &match);
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->key, ICMP_TYPE, match.key->type);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE; rule_match_set(r_match->mask, ICMP_TYPE, match.mask->type);
m_entry.keymask.u8.key = match.key->type;
m_entry.keymask.u8.mask = match.mask->type;
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
memset(&m_entry, 0, sizeof(m_entry)); rule_match_set(r_match->key, ICMP_CODE, match.key->code);
m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE; rule_match_set(r_match->mask, ICMP_CODE, match.mask->code);
m_entry.keymask.u8.key = match.key->code;
m_entry.keymask.u8.mask = match.mask->code;
err = prestera_acl_rule_match_add(rule, &m_entry);
if (err)
return err;
} }
return prestera_flower_parse_actions(block, rule, return prestera_flower_parse_actions(block, rule, &f->rule->action,
&f->rule->action,
f->common.extack); f->common.extack);
} }
int prestera_flower_replace(struct prestera_flow_block *block, int prestera_flower_replace(struct prestera_flow_block *block,
struct flow_cls_offload *f) struct flow_cls_offload *f)
{ {
struct prestera_switch *sw = prestera_acl_block_sw(block); struct prestera_acl_ruleset *ruleset;
struct prestera_acl *acl = block->sw->acl;
struct prestera_acl_rule *rule; struct prestera_acl_rule *rule;
int err; int err;
rule = prestera_acl_rule_create(block, f->cookie); ruleset = prestera_acl_ruleset_get(acl, block);
if (IS_ERR(rule)) if (IS_ERR(ruleset))
return PTR_ERR(rule); return PTR_ERR(ruleset);
/* increments the ruleset reference */
rule = prestera_acl_rule_create(ruleset, f->cookie);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
goto err_rule_create;
}
err = prestera_flower_parse(block, rule, f); err = prestera_flower_parse(block, rule, f);
if (err) if (err)
goto err_flower_parse; goto err_rule_add;
err = prestera_acl_rule_add(sw, rule); if (!prestera_acl_ruleset_is_offload(ruleset)) {
err = prestera_acl_ruleset_offload(ruleset);
if (err)
goto err_ruleset_offload;
}
err = prestera_acl_rule_add(block->sw, rule);
if (err) if (err)
goto err_rule_add; goto err_rule_add;
prestera_acl_ruleset_put(ruleset);
return 0; return 0;
err_ruleset_offload:
err_rule_add: err_rule_add:
err_flower_parse:
prestera_acl_rule_destroy(rule); prestera_acl_rule_destroy(rule);
err_rule_create:
prestera_acl_ruleset_put(ruleset);
return err; return err;
} }
void prestera_flower_destroy(struct prestera_flow_block *block, void prestera_flower_destroy(struct prestera_flow_block *block,
struct flow_cls_offload *f) struct flow_cls_offload *f)
{ {
struct prestera_acl_ruleset *ruleset;
struct prestera_acl_rule *rule; struct prestera_acl_rule *rule;
struct prestera_switch *sw;
rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block), ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block);
f->cookie); if (IS_ERR(ruleset))
return;
rule = prestera_acl_rule_lookup(ruleset, f->cookie);
if (rule) { if (rule) {
sw = prestera_acl_block_sw(block); prestera_acl_rule_del(block->sw, rule);
prestera_acl_rule_del(sw, rule);
prestera_acl_rule_destroy(rule); prestera_acl_rule_destroy(rule);
} }
prestera_acl_ruleset_put(ruleset);
} }
int prestera_flower_stats(struct prestera_flow_block *block, int prestera_flower_stats(struct prestera_flow_block *block,
struct flow_cls_offload *f) struct flow_cls_offload *f)
{ {
struct prestera_switch *sw = prestera_acl_block_sw(block); struct prestera_acl_ruleset *ruleset;
struct prestera_acl_rule *rule; struct prestera_acl_rule *rule;
u64 packets; u64 packets;
u64 lastuse; u64 lastuse;
u64 bytes; u64 bytes;
int err; int err;
rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block), ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block);
f->cookie); if (IS_ERR(ruleset))
if (!rule) return PTR_ERR(ruleset);
return -EINVAL;
rule = prestera_acl_rule_lookup(ruleset, f->cookie);
if (!rule) {
err = -EINVAL;
goto err_rule_get_stats;
}
err = prestera_acl_rule_get_stats(sw, rule, &packets, &bytes, &lastuse); err = prestera_acl_rule_get_stats(block->sw->acl, rule, &packets,
&bytes, &lastuse);
if (err) if (err)
return err; goto err_rule_get_stats;
flow_stats_update(&f->stats, bytes, packets, 0, lastuse, flow_stats_update(&f->stats, bytes, packets, 0, lastuse,
FLOW_ACTION_HW_STATS_IMMEDIATE); FLOW_ACTION_HW_STATS_DELAYED);
return 0;
err_rule_get_stats:
prestera_acl_ruleset_put(ruleset);
return err;
} }
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
/* Copyright (c) 2020 Marvell International Ltd. All rights reserved. */ /* Copyright (c) 2020-2021 Marvell International Ltd. All rights reserved. */
#ifndef _PRESTERA_FLOWER_H_ #ifndef _PRESTERA_FLOWER_H_
#define _PRESTERA_FLOWER_H_ #define _PRESTERA_FLOWER_H_
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
struct prestera_switch;
struct prestera_flow_block; struct prestera_flow_block;
int prestera_flower_replace(struct prestera_flow_block *block, int prestera_flower_replace(struct prestera_flow_block *block,
......
...@@ -38,13 +38,12 @@ enum prestera_cmd_type_t { ...@@ -38,13 +38,12 @@ enum prestera_cmd_type_t {
PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402, PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402,
PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403, PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403,
PRESTERA_CMD_TYPE_ACL_RULE_ADD = 0x500, PRESTERA_CMD_TYPE_VTCAM_CREATE = 0x540,
PRESTERA_CMD_TYPE_ACL_RULE_DELETE = 0x501, PRESTERA_CMD_TYPE_VTCAM_DESTROY = 0x541,
PRESTERA_CMD_TYPE_ACL_RULE_STATS_GET = 0x510, PRESTERA_CMD_TYPE_VTCAM_RULE_ADD = 0x550,
PRESTERA_CMD_TYPE_ACL_RULESET_CREATE = 0x520, PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE = 0x551,
PRESTERA_CMD_TYPE_ACL_RULESET_DELETE = 0x521, PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND = 0x560,
PRESTERA_CMD_TYPE_ACL_PORT_BIND = 0x530, PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND = 0x561,
PRESTERA_CMD_TYPE_ACL_PORT_UNBIND = 0x531,
PRESTERA_CMD_TYPE_RXTX_INIT = 0x800, PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,
...@@ -359,76 +358,57 @@ struct prestera_msg_bridge_resp { ...@@ -359,76 +358,57 @@ struct prestera_msg_bridge_resp {
u8 pad[2]; u8 pad[2];
}; };
struct prestera_msg_acl_action { struct prestera_msg_vtcam_create_req {
__le32 id; struct prestera_msg_cmd cmd;
__le32 reserved[5]; __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];
u8 direction;
u8 lookup;
u8 pad[2];
}; };
struct prestera_msg_acl_match { struct prestera_msg_vtcam_destroy_req {
__le32 type; struct prestera_msg_cmd cmd;
__le32 __reserved; __le32 vtcam_id;
union {
struct {
u8 key;
u8 mask;
} u8;
struct {
__le16 key;
__le16 mask;
} u16;
struct {
__le32 key;
__le32 mask;
} u32;
struct {
__le64 key;
__le64 mask;
} u64;
struct {
u8 key[ETH_ALEN];
u8 mask[ETH_ALEN];
} mac;
} keymask;
}; };
struct prestera_msg_acl_rule_req { struct prestera_msg_vtcam_rule_add_req {
struct prestera_msg_cmd cmd; struct prestera_msg_cmd cmd;
__le32 id; __le32 key[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];
__le32 priority; __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];
__le16 ruleset_id; __le32 vtcam_id;
u8 n_actions; __le32 prio;
u8 n_matches; __le32 n_act;
}; };
struct prestera_msg_acl_rule_resp { struct prestera_msg_vtcam_rule_del_req {
struct prestera_msg_ret ret; struct prestera_msg_cmd cmd;
__le32 vtcam_id;
__le32 id; __le32 id;
}; };
struct prestera_msg_acl_rule_stats_resp { struct prestera_msg_vtcam_bind_req {
struct prestera_msg_ret ret;
__le64 packets;
__le64 bytes;
};
struct prestera_msg_acl_ruleset_bind_req {
struct prestera_msg_cmd cmd; struct prestera_msg_cmd cmd;
__le32 port; union {
__le32 dev; struct {
__le16 ruleset_id; __le32 hw_id;
u8 pad[2]; __le32 dev_id;
} port;
__le32 index;
};
__le32 vtcam_id;
__le16 pcl_id;
__le16 type;
}; };
struct prestera_msg_acl_ruleset_req { struct prestera_msg_vtcam_resp {
struct prestera_msg_cmd cmd; struct prestera_msg_ret ret;
__le16 id; __le32 vtcam_id;
u8 pad[2]; __le32 rule_id;
}; };
struct prestera_msg_acl_ruleset_resp { struct prestera_msg_acl_action {
struct prestera_msg_ret ret; __le32 id;
__le16 id; __le32 __reserved[7];
u8 pad[2];
}; };
struct prestera_msg_span_req { struct prestera_msg_span_req {
...@@ -521,14 +501,17 @@ static void prestera_hw_build_tests(void) ...@@ -521,14 +501,17 @@ static void prestera_hw_build_tests(void)
BUILD_BUG_ON(sizeof(struct prestera_msg_vlan_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_vlan_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_fdb_req) != 28); BUILD_BUG_ON(sizeof(struct prestera_msg_fdb_req) != 28);
BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_rule_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_ruleset_bind_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_ruleset_req) != 8);
BUILD_BUG_ON(sizeof(struct prestera_msg_span_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_span_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_stp_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_stp_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_req) != 8); BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_req) != 8);
BUILD_BUG_ON(sizeof(struct prestera_msg_lag_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_lag_req) != 16);
BUILD_BUG_ON(sizeof(struct prestera_msg_cpu_code_counter_req) != 8); BUILD_BUG_ON(sizeof(struct prestera_msg_cpu_code_counter_req) != 8);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_create_req) != 84);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_destroy_req) != 8);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_add_req) != 168);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_del_req) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_bind_req) != 20);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_action) != 32);
/* check responses */ /* check responses */
BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8); BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8);
...@@ -537,11 +520,9 @@ static void prestera_hw_build_tests(void) ...@@ -537,11 +520,9 @@ static void prestera_hw_build_tests(void)
BUILD_BUG_ON(sizeof(struct prestera_msg_port_stats_resp) != 248); BUILD_BUG_ON(sizeof(struct prestera_msg_port_stats_resp) != 248);
BUILD_BUG_ON(sizeof(struct prestera_msg_port_info_resp) != 20); BUILD_BUG_ON(sizeof(struct prestera_msg_port_info_resp) != 20);
BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_resp) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_resp) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_rule_resp) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_rule_stats_resp) != 24);
BUILD_BUG_ON(sizeof(struct prestera_msg_acl_ruleset_resp) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_span_resp) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_span_resp) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12);
BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_resp) != 16);
/* check events */ /* check events */
BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20); BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20);
...@@ -1044,43 +1025,48 @@ static void prestera_hw_remote_fc_to_eth(u8 fc, bool *pause, bool *asym_pause) ...@@ -1044,43 +1025,48 @@ static void prestera_hw_remote_fc_to_eth(u8 fc, bool *pause, bool *asym_pause)
} }
} }
int prestera_hw_acl_ruleset_create(struct prestera_switch *sw, u16 *ruleset_id) int prestera_hw_vtcam_create(struct prestera_switch *sw,
u8 lookup, const u32 *keymask, u32 *vtcam_id,
enum prestera_hw_vtcam_direction_t dir)
{ {
struct prestera_msg_acl_ruleset_resp resp;
struct prestera_msg_acl_ruleset_req req;
int err; int err;
struct prestera_msg_vtcam_resp resp;
struct prestera_msg_vtcam_create_req req = {
.lookup = lookup,
.direction = dir,
};
if (keymask)
memcpy(req.keymask, keymask, sizeof(req.keymask));
else
memset(req.keymask, 0, sizeof(req.keymask));
err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULESET_CREATE, err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_VTCAM_CREATE,
&req.cmd, sizeof(req), &resp.ret, sizeof(resp)); &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
if (err) if (err)
return err; return err;
*ruleset_id = __le16_to_cpu(resp.id); *vtcam_id = __le32_to_cpu(resp.vtcam_id);
return 0; return 0;
} }
int prestera_hw_acl_ruleset_del(struct prestera_switch *sw, u16 ruleset_id) int prestera_hw_vtcam_destroy(struct prestera_switch *sw, u32 vtcam_id)
{ {
struct prestera_msg_acl_ruleset_req req = { struct prestera_msg_vtcam_destroy_req req = {
.id = __cpu_to_le16(ruleset_id), .vtcam_id = __cpu_to_le32(vtcam_id),
}; };
return prestera_cmd(sw, PRESTERA_CMD_TYPE_ACL_RULESET_DELETE, return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_DESTROY,
&req.cmd, sizeof(req)); &req.cmd, sizeof(req));
} }
static int prestera_hw_acl_actions_put(struct prestera_msg_acl_action *action, static int
struct prestera_acl_rule *rule) prestera_acl_rule_add_put_action(struct prestera_msg_acl_action *action,
struct prestera_acl_hw_action_info *info)
{ {
struct list_head *a_list = prestera_acl_rule_action_list_get(rule); action->id = __cpu_to_le32(info->id);
struct prestera_acl_rule_action_entry *a_entry;
int i = 0;
list_for_each_entry(a_entry, a_list, list) {
action[i].id = __cpu_to_le32(a_entry->id);
switch (a_entry->id) { switch (info->id) {
case PRESTERA_ACL_RULE_ACTION_ACCEPT: case PRESTERA_ACL_RULE_ACTION_ACCEPT:
case PRESTERA_ACL_RULE_ACTION_DROP: case PRESTERA_ACL_RULE_ACTION_DROP:
case PRESTERA_ACL_RULE_ACTION_TRAP: case PRESTERA_ACL_RULE_ACTION_TRAP:
...@@ -1090,179 +1076,108 @@ static int prestera_hw_acl_actions_put(struct prestera_msg_acl_action *action, ...@@ -1090,179 +1076,108 @@ static int prestera_hw_acl_actions_put(struct prestera_msg_acl_action *action,
return -EINVAL; return -EINVAL;
} }
i++;
}
return 0;
}
static int prestera_hw_acl_matches_put(struct prestera_msg_acl_match *match,
struct prestera_acl_rule *rule)
{
struct list_head *m_list = prestera_acl_rule_match_list_get(rule);
struct prestera_acl_rule_match_entry *m_entry;
int i = 0;
list_for_each_entry(m_entry, m_list, list) {
match[i].type = __cpu_to_le32(m_entry->type);
switch (m_entry->type) {
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID:
match[i].keymask.u16.key =
__cpu_to_le16(m_entry->keymask.u16.key);
match[i].keymask.u16.mask =
__cpu_to_le16(m_entry->keymask.u16.mask);
break;
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO:
match[i].keymask.u8.key = m_entry->keymask.u8.key;
match[i].keymask.u8.mask = m_entry->keymask.u8.mask;
break;
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC:
memcpy(match[i].keymask.mac.key,
m_entry->keymask.mac.key,
sizeof(match[i].keymask.mac.key));
memcpy(match[i].keymask.mac.mask,
m_entry->keymask.mac.mask,
sizeof(match[i].keymask.mac.mask));
break;
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_SRC:
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_DST:
match[i].keymask.u32.key =
__cpu_to_le32(m_entry->keymask.u32.key);
match[i].keymask.u32.mask =
__cpu_to_le32(m_entry->keymask.u32.mask);
break;
case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT:
match[i].keymask.u64.key =
__cpu_to_le64(m_entry->keymask.u64.key);
match[i].keymask.u64.mask =
__cpu_to_le64(m_entry->keymask.u64.mask);
break;
default:
return -EINVAL;
}
i++;
}
return 0; return 0;
} }
int prestera_hw_acl_rule_add(struct prestera_switch *sw, int prestera_hw_vtcam_rule_add(struct prestera_switch *sw,
struct prestera_acl_rule *rule, u32 vtcam_id, u32 prio, void *key, void *keymask,
u32 *rule_id) struct prestera_acl_hw_action_info *act,
u8 n_act, u32 *rule_id)
{ {
struct prestera_msg_acl_action *actions; struct prestera_msg_acl_action *actions_msg;
struct prestera_msg_acl_match *matches; struct prestera_msg_vtcam_rule_add_req *req;
struct prestera_msg_acl_rule_resp resp; struct prestera_msg_vtcam_resp resp;
struct prestera_msg_acl_rule_req *req;
u8 n_actions;
u8 n_matches;
void *buff; void *buff;
u32 size; u32 size;
int err; int err;
u8 i;
n_actions = prestera_acl_rule_action_len(rule); size = sizeof(*req) + sizeof(*actions_msg) * n_act;
n_matches = prestera_acl_rule_match_len(rule);
size = sizeof(*req) + sizeof(*actions) * n_actions +
sizeof(*matches) * n_matches;
buff = kzalloc(size, GFP_KERNEL); buff = kzalloc(size, GFP_KERNEL);
if (!buff) if (!buff)
return -ENOMEM; return -ENOMEM;
req = buff; req = buff;
actions = buff + sizeof(*req); req->n_act = __cpu_to_le32(n_act);
matches = buff + sizeof(*req) + sizeof(*actions) * n_actions; actions_msg = buff + sizeof(*req);
/* put acl actions into the message */
err = prestera_hw_acl_actions_put(actions, rule);
if (err)
goto free_buff;
/* put acl matches into the message */ /* put acl matches into the message */
err = prestera_hw_acl_matches_put(matches, rule); memcpy(req->key, key, sizeof(req->key));
memcpy(req->keymask, keymask, sizeof(req->keymask));
/* put acl actions into the message */
for (i = 0; i < n_act; i++) {
err = prestera_acl_rule_add_put_action(&actions_msg[i],
&act[i]);
if (err) if (err)
goto free_buff; goto free_buff;
}
req->ruleset_id = __cpu_to_le16(prestera_acl_rule_ruleset_id_get(rule)); req->vtcam_id = __cpu_to_le32(vtcam_id);
req->priority = __cpu_to_le32(prestera_acl_rule_priority_get(rule)); req->prio = __cpu_to_le32(prio);
req->n_actions = prestera_acl_rule_action_len(rule);
req->n_matches = prestera_acl_rule_match_len(rule);
err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULE_ADD, err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_VTCAM_RULE_ADD,
&req->cmd, size, &resp.ret, sizeof(resp)); &req->cmd, size, &resp.ret, sizeof(resp));
if (err) if (err)
goto free_buff; goto free_buff;
*rule_id = __le32_to_cpu(resp.id); *rule_id = __le32_to_cpu(resp.rule_id);
free_buff: free_buff:
kfree(buff); kfree(buff);
return err; return err;
} }
int prestera_hw_acl_rule_del(struct prestera_switch *sw, u32 rule_id) int prestera_hw_vtcam_rule_del(struct prestera_switch *sw,
u32 vtcam_id, u32 rule_id)
{ {
struct prestera_msg_acl_rule_req req = { struct prestera_msg_vtcam_rule_del_req req = {
.vtcam_id = __cpu_to_le32(vtcam_id),
.id = __cpu_to_le32(rule_id) .id = __cpu_to_le32(rule_id)
}; };
return prestera_cmd(sw, PRESTERA_CMD_TYPE_ACL_RULE_DELETE, return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE,
&req.cmd, sizeof(req)); &req.cmd, sizeof(req));
} }
int prestera_hw_acl_rule_stats_get(struct prestera_switch *sw, u32 rule_id, int prestera_hw_vtcam_iface_bind(struct prestera_switch *sw,
u64 *packets, u64 *bytes) struct prestera_acl_iface *iface,
u32 vtcam_id, u16 pcl_id)
{ {
struct prestera_msg_acl_rule_stats_resp resp; struct prestera_msg_vtcam_bind_req req = {
struct prestera_msg_acl_rule_req req = { .vtcam_id = __cpu_to_le32(vtcam_id),
.id = __cpu_to_le32(rule_id) .type = __cpu_to_le16(iface->type),
.pcl_id = __cpu_to_le16(pcl_id)
}; };
int err;
err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULE_STATS_GET,
&req.cmd, sizeof(req), &resp.ret, sizeof(resp));
if (err)
return err;
*packets = __le64_to_cpu(resp.packets);
*bytes = __le64_to_cpu(resp.bytes);
return 0;
}
int prestera_hw_acl_port_bind(const struct prestera_port *port, u16 ruleset_id) if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) {
{ req.port.dev_id = __cpu_to_le32(iface->port->dev_id);
struct prestera_msg_acl_ruleset_bind_req req = { req.port.hw_id = __cpu_to_le32(iface->port->hw_id);
.port = __cpu_to_le32(port->hw_id), } else {
.dev = __cpu_to_le32(port->dev_id), req.index = __cpu_to_le32(iface->index);
.ruleset_id = __cpu_to_le16(ruleset_id), }
};
return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_ACL_PORT_BIND, return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND,
&req.cmd, sizeof(req)); &req.cmd, sizeof(req));
} }
int prestera_hw_acl_port_unbind(const struct prestera_port *port, int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw,
u16 ruleset_id) struct prestera_acl_iface *iface,
u32 vtcam_id)
{ {
struct prestera_msg_acl_ruleset_bind_req req = { struct prestera_msg_vtcam_bind_req req = {
.port = __cpu_to_le32(port->hw_id), .vtcam_id = __cpu_to_le32(vtcam_id),
.dev = __cpu_to_le32(port->dev_id), .type = __cpu_to_le16(iface->type)
.ruleset_id = __cpu_to_le16(ruleset_id),
}; };
return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_ACL_PORT_UNBIND, if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) {
req.port.dev_id = __cpu_to_le32(iface->port->dev_id);
req.port.hw_id = __cpu_to_le32(iface->port->hw_id);
} else {
req.index = __cpu_to_le32(iface->index);
}
return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND,
&req.cmd, sizeof(req)); &req.cmd, sizeof(req));
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#define _PRESTERA_HW_H_ #define _PRESTERA_HW_H_
#include <linux/types.h> #include <linux/types.h>
#include "prestera_acl.h"
enum prestera_accept_frm_type { enum prestera_accept_frm_type {
PRESTERA_ACCEPT_FRAME_TYPE_TAGGED, PRESTERA_ACCEPT_FRAME_TYPE_TAGGED,
...@@ -111,18 +112,24 @@ enum prestera_hw_cpu_code_cnt_t { ...@@ -111,18 +112,24 @@ enum prestera_hw_cpu_code_cnt_t {
PRESTERA_HW_CPU_CODE_CNT_TYPE_TRAP = 1, PRESTERA_HW_CPU_CODE_CNT_TYPE_TRAP = 1,
}; };
enum prestera_hw_vtcam_direction_t {
PRESTERA_HW_VTCAM_DIR_INGRESS = 0,
PRESTERA_HW_VTCAM_DIR_EGRESS = 1,
};
struct prestera_switch; struct prestera_switch;
struct prestera_port; struct prestera_port;
struct prestera_port_stats; struct prestera_port_stats;
struct prestera_port_caps; struct prestera_port_caps;
enum prestera_event_type; enum prestera_event_type;
struct prestera_event; struct prestera_event;
struct prestera_acl_rule;
typedef void (*prestera_event_cb_t) typedef void (*prestera_event_cb_t)
(struct prestera_switch *sw, struct prestera_event *evt, void *arg); (struct prestera_switch *sw, struct prestera_event *evt, void *arg);
struct prestera_rxtx_params; struct prestera_rxtx_params;
struct prestera_acl_hw_action_info;
struct prestera_acl_iface;
/* Switch API */ /* Switch API */
int prestera_hw_switch_init(struct prestera_switch *sw); int prestera_hw_switch_init(struct prestera_switch *sw);
...@@ -186,21 +193,23 @@ int prestera_hw_bridge_delete(struct prestera_switch *sw, u16 bridge_id); ...@@ -186,21 +193,23 @@ int prestera_hw_bridge_delete(struct prestera_switch *sw, u16 bridge_id);
int prestera_hw_bridge_port_add(struct prestera_port *port, u16 bridge_id); int prestera_hw_bridge_port_add(struct prestera_port *port, u16 bridge_id);
int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id); int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id);
/* ACL API */ /* vTCAM API */
int prestera_hw_acl_ruleset_create(struct prestera_switch *sw, int prestera_hw_vtcam_create(struct prestera_switch *sw,
u16 *ruleset_id); u8 lookup, const u32 *keymask, u32 *vtcam_id,
int prestera_hw_acl_ruleset_del(struct prestera_switch *sw, enum prestera_hw_vtcam_direction_t direction);
u16 ruleset_id); int prestera_hw_vtcam_rule_add(struct prestera_switch *sw, u32 vtcam_id,
int prestera_hw_acl_rule_add(struct prestera_switch *sw, u32 prio, void *key, void *keymask,
struct prestera_acl_rule *rule, struct prestera_acl_hw_action_info *act,
u32 *rule_id); u8 n_act, u32 *rule_id);
int prestera_hw_acl_rule_del(struct prestera_switch *sw, u32 rule_id); int prestera_hw_vtcam_rule_del(struct prestera_switch *sw,
int prestera_hw_acl_rule_stats_get(struct prestera_switch *sw, u32 vtcam_id, u32 rule_id);
u32 rule_id, u64 *packets, u64 *bytes); int prestera_hw_vtcam_destroy(struct prestera_switch *sw, u32 vtcam_id);
int prestera_hw_acl_port_bind(const struct prestera_port *port, int prestera_hw_vtcam_iface_bind(struct prestera_switch *sw,
u16 ruleset_id); struct prestera_acl_iface *iface,
int prestera_hw_acl_port_unbind(const struct prestera_port *port, u32 vtcam_id, u16 pcl_id);
u16 ruleset_id); int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw,
struct prestera_acl_iface *iface,
u32 vtcam_id);
/* SPAN API */ /* SPAN API */
int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id); int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "prestera.h" #include "prestera.h"
#include "prestera_hw.h" #include "prestera_hw.h"
#include "prestera_acl.h" #include "prestera_acl.h"
#include "prestera_flow.h"
#include "prestera_span.h" #include "prestera_span.h"
struct prestera_span_entry { struct prestera_span_entry {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册