net: dsa: add port policers
The approach taken to pass the port policer methods on to drivers is pragmatic. It is similar to the port mirroring implementation (in that the DSA core does all of the filter block interaction and only passes simple operations for the driver to implement) and dissimilar to how flow-based policers are going to be implemented (where the driver has full control over the flow_cls_offload data structure). Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e13c207528
commit
342971766c
@ -130,9 +130,10 @@ struct dsa_switch_tree {
|
||||
struct list_head rtable;
|
||||
};
|
||||
|
||||
/* TC matchall action types, only mirroring for now */
|
||||
/* TC matchall action types */
|
||||
enum dsa_port_mall_action_type {
|
||||
DSA_PORT_MALL_MIRROR,
|
||||
DSA_PORT_MALL_POLICER,
|
||||
};
|
||||
|
||||
/* TC mirroring entry */
|
||||
@ -141,6 +142,12 @@ struct dsa_mall_mirror_tc_entry {
|
||||
bool ingress;
|
||||
};
|
||||
|
||||
/* TC port policer entry */
|
||||
struct dsa_mall_policer_tc_entry {
|
||||
s64 burst;
|
||||
u64 rate_bytes_per_sec;
|
||||
};
|
||||
|
||||
/* TC matchall entry */
|
||||
struct dsa_mall_tc_entry {
|
||||
struct list_head list;
|
||||
@ -148,6 +155,7 @@ struct dsa_mall_tc_entry {
|
||||
enum dsa_port_mall_action_type type;
|
||||
union {
|
||||
struct dsa_mall_mirror_tc_entry mirror;
|
||||
struct dsa_mall_policer_tc_entry policer;
|
||||
};
|
||||
};
|
||||
|
||||
@ -557,6 +565,9 @@ struct dsa_switch_ops {
|
||||
bool ingress);
|
||||
void (*port_mirror_del)(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror);
|
||||
int (*port_policer_add)(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_policer_tc_entry *policer);
|
||||
void (*port_policer_del)(struct dsa_switch *ds, int port);
|
||||
int (*port_setup_tc)(struct dsa_switch *ds, int port,
|
||||
enum tc_setup_type type, void *type_data);
|
||||
|
||||
|
@ -859,14 +859,14 @@ dsa_slave_add_cls_matchall_mirred(struct net_device *dev,
|
||||
act = &cls->rule->action.entries[0];
|
||||
|
||||
if (!ds->ops->port_mirror_add)
|
||||
return err;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!act->dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (!flow_action_basic_hw_stats_check(&cls->rule->action,
|
||||
cls->common.extack))
|
||||
return err;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
act = &cls->rule->action.entries[0];
|
||||
|
||||
@ -897,6 +897,67 @@ dsa_slave_add_cls_matchall_mirred(struct net_device *dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
dsa_slave_add_cls_matchall_police(struct net_device *dev,
|
||||
struct tc_cls_matchall_offload *cls,
|
||||
bool ingress)
|
||||
{
|
||||
struct netlink_ext_ack *extack = cls->common.extack;
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
struct dsa_slave_priv *p = netdev_priv(dev);
|
||||
struct dsa_mall_policer_tc_entry *policer;
|
||||
struct dsa_mall_tc_entry *mall_tc_entry;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
struct flow_action_entry *act;
|
||||
int err;
|
||||
|
||||
if (!ds->ops->port_policer_add) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Policing offload not implemented\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!ingress) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Only supported on ingress qdisc\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!flow_action_basic_hw_stats_check(&cls->rule->action,
|
||||
cls->common.extack))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
list_for_each_entry(mall_tc_entry, &p->mall_tc_list, list) {
|
||||
if (mall_tc_entry->type == DSA_PORT_MALL_POLICER) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Only one port policer allowed\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
act = &cls->rule->action.entries[0];
|
||||
|
||||
mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
|
||||
if (!mall_tc_entry)
|
||||
return -ENOMEM;
|
||||
|
||||
mall_tc_entry->cookie = cls->cookie;
|
||||
mall_tc_entry->type = DSA_PORT_MALL_POLICER;
|
||||
policer = &mall_tc_entry->policer;
|
||||
policer->rate_bytes_per_sec = act->police.rate_bytes_ps;
|
||||
policer->burst = act->police.burst;
|
||||
|
||||
err = ds->ops->port_policer_add(ds, dp->index, policer);
|
||||
if (err) {
|
||||
kfree(mall_tc_entry);
|
||||
return err;
|
||||
}
|
||||
|
||||
list_add_tail(&mall_tc_entry->list, &p->mall_tc_list);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dsa_slave_add_cls_matchall(struct net_device *dev,
|
||||
struct tc_cls_matchall_offload *cls,
|
||||
bool ingress)
|
||||
@ -907,6 +968,9 @@ static int dsa_slave_add_cls_matchall(struct net_device *dev,
|
||||
flow_offload_has_one_action(&cls->rule->action) &&
|
||||
cls->rule->action.entries[0].id == FLOW_ACTION_MIRRED)
|
||||
err = dsa_slave_add_cls_matchall_mirred(dev, cls, ingress);
|
||||
else if (flow_offload_has_one_action(&cls->rule->action) &&
|
||||
cls->rule->action.entries[0].id == FLOW_ACTION_POLICE)
|
||||
err = dsa_slave_add_cls_matchall_police(dev, cls, ingress);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -918,9 +982,6 @@ static void dsa_slave_del_cls_matchall(struct net_device *dev,
|
||||
struct dsa_mall_tc_entry *mall_tc_entry;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
|
||||
if (!ds->ops->port_mirror_del)
|
||||
return;
|
||||
|
||||
mall_tc_entry = dsa_slave_mall_tc_entry_find(dev, cls->cookie);
|
||||
if (!mall_tc_entry)
|
||||
return;
|
||||
@ -929,7 +990,13 @@ static void dsa_slave_del_cls_matchall(struct net_device *dev,
|
||||
|
||||
switch (mall_tc_entry->type) {
|
||||
case DSA_PORT_MALL_MIRROR:
|
||||
ds->ops->port_mirror_del(ds, dp->index, &mall_tc_entry->mirror);
|
||||
if (ds->ops->port_mirror_del)
|
||||
ds->ops->port_mirror_del(ds, dp->index,
|
||||
&mall_tc_entry->mirror);
|
||||
break;
|
||||
case DSA_PORT_MALL_POLICER:
|
||||
if (ds->ops->port_policer_del)
|
||||
ds->ops->port_policer_del(ds, dp->index);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
|
Loading…
Reference in New Issue
Block a user