]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
net: dsa: add port policers
authorVladimir Oltean <vladimir.oltean@nxp.com>
Sun, 29 Mar 2020 11:51:59 +0000 (14:51 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 30 Mar 2020 18:44:00 +0000 (11:44 -0700)
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>
include/net/dsa.h
net/dsa/slave.c

index aeb411e77b9aeb26c23c95a6d4edd7920dde3d4f..fb3f9222f2a1e08d680da631995754c9e5b857b9 100644 (file)
@@ -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);
 
index e6040a11bd83a8d71c96ca16b2a5d39a119d9c6d..9692a726f2ed018dbefc9c20eeeeefe2e0b5c4d0 100644 (file)
@@ -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);