netdevsim: add ACL trap reporting cookie as a metadata
authorJiri Pirko <jiri@mellanox.com>
Tue, 25 Feb 2020 10:45:26 +0000 (11:45 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 25 Feb 2020 19:05:55 +0000 (11:05 -0800)
Add new trap ACL which reports flow action cookie in a metadata. Allow
used to setup the cookie using debugfs file.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/netdevsim/dev.c
drivers/net/netdevsim/netdevsim.h

index aa17533..f81c473 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/workqueue.h>
 #include <net/devlink.h>
 #include <net/ip.h>
+#include <net/flow_offload.h>
 #include <uapi/linux/devlink.h>
 #include <uapi/linux/ip.h>
 #include <uapi/linux/udp.h>
@@ -71,6 +72,98 @@ static const struct file_operations nsim_dev_take_snapshot_fops = {
        .llseek = generic_file_llseek,
 };
 
+static ssize_t nsim_dev_trap_fa_cookie_read(struct file *file,
+                                           char __user *data,
+                                           size_t count, loff_t *ppos)
+{
+       struct nsim_dev *nsim_dev = file->private_data;
+       struct flow_action_cookie *fa_cookie;
+       unsigned int buf_len;
+       ssize_t ret;
+       char *buf;
+
+       spin_lock(&nsim_dev->fa_cookie_lock);
+       fa_cookie = nsim_dev->fa_cookie;
+       if (!fa_cookie) {
+               ret = -EINVAL;
+               goto errout;
+       }
+       buf_len = fa_cookie->cookie_len * 2;
+       buf = kmalloc(buf_len, GFP_ATOMIC);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto errout;
+       }
+       bin2hex(buf, fa_cookie->cookie, fa_cookie->cookie_len);
+       spin_unlock(&nsim_dev->fa_cookie_lock);
+
+       ret = simple_read_from_buffer(data, count, ppos, buf, buf_len);
+
+       kfree(buf);
+       return ret;
+
+errout:
+       spin_unlock(&nsim_dev->fa_cookie_lock);
+       return ret;
+}
+
+static ssize_t nsim_dev_trap_fa_cookie_write(struct file *file,
+                                            const char __user *data,
+                                            size_t count, loff_t *ppos)
+{
+       struct nsim_dev *nsim_dev = file->private_data;
+       struct flow_action_cookie *fa_cookie;
+       size_t cookie_len;
+       ssize_t ret;
+       char *buf;
+
+       if (*ppos != 0)
+               return -EINVAL;
+       cookie_len = (count - 1) / 2;
+       if ((count - 1) % 2)
+               return -EINVAL;
+       buf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = simple_write_to_buffer(buf, count, ppos, data, count);
+       if (ret < 0)
+               goto free_buf;
+
+       fa_cookie = kmalloc(sizeof(*fa_cookie) + cookie_len,
+                           GFP_KERNEL | __GFP_NOWARN);
+       if (!fa_cookie) {
+               ret = -ENOMEM;
+               goto free_buf;
+       }
+
+       fa_cookie->cookie_len = cookie_len;
+       ret = hex2bin(fa_cookie->cookie, buf, cookie_len);
+       if (ret)
+               goto free_fa_cookie;
+       kfree(buf);
+
+       spin_lock(&nsim_dev->fa_cookie_lock);
+       kfree(nsim_dev->fa_cookie);
+       nsim_dev->fa_cookie = fa_cookie;
+       spin_unlock(&nsim_dev->fa_cookie_lock);
+
+       return count;
+
+free_fa_cookie:
+       kfree(fa_cookie);
+free_buf:
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations nsim_dev_trap_fa_cookie_fops = {
+       .open = simple_open,
+       .read = nsim_dev_trap_fa_cookie_read,
+       .write = nsim_dev_trap_fa_cookie_write,
+       .llseek = generic_file_llseek,
+};
+
 static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
 {
        char dev_ddir_name[sizeof(DRV_NAME) + 10];
@@ -97,6 +190,8 @@ static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
                            &nsim_dev->dont_allow_reload);
        debugfs_create_bool("fail_reload", 0600, nsim_dev->ddir,
                            &nsim_dev->fail_reload);
+       debugfs_create_file("trap_flow_action_cookie", 0600, nsim_dev->ddir,
+                           nsim_dev, &nsim_dev_trap_fa_cookie_fops);
        return 0;
 }
 
@@ -288,6 +383,10 @@ enum {
        DEVLINK_TRAP_GENERIC(DROP, DROP, _id,                                 \
                             DEVLINK_TRAP_GROUP_GENERIC(_group_id),           \
                             NSIM_TRAP_METADATA)
+#define NSIM_TRAP_DROP_EXT(_id, _group_id, _metadata)                        \
+       DEVLINK_TRAP_GENERIC(DROP, DROP, _id,                                 \
+                            DEVLINK_TRAP_GROUP_GENERIC(_group_id),           \
+                            NSIM_TRAP_METADATA | (_metadata))
 #define NSIM_TRAP_EXCEPTION(_id, _group_id)                                  \
        DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,                            \
                             DEVLINK_TRAP_GROUP_GENERIC(_group_id),           \
@@ -309,6 +408,10 @@ static const struct devlink_trap nsim_traps_arr[] = {
        NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
        NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS),
        NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS),
+       NSIM_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS,
+                          DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
+       NSIM_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS,
+                          DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
 };
 
 #define NSIM_TRAP_L4_DATA_LEN 100
@@ -366,8 +469,13 @@ static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port)
 
        spin_lock(&nsim_trap_data->trap_lock);
        for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {
+               struct flow_action_cookie *fa_cookie = NULL;
                struct nsim_trap_item *nsim_trap_item;
                struct sk_buff *skb;
+               bool has_fa_cookie;
+
+               has_fa_cookie = nsim_traps_arr[i].metadata_cap &
+                               DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE;
 
                nsim_trap_item = &nsim_trap_data->trap_items_arr[i];
                if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP)
@@ -383,10 +491,12 @@ static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port)
                 * softIRQs to prevent lockdep from complaining about
                 * "incosistent lock state".
                 */
-               local_bh_disable();
+
+               spin_lock_bh(&nsim_dev->fa_cookie_lock);
+               fa_cookie = has_fa_cookie ? nsim_dev->fa_cookie : NULL;
                devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx,
-                                   &nsim_dev_port->devlink_port, NULL);
-               local_bh_enable();
+                                   &nsim_dev_port->devlink_port, fa_cookie);
+               spin_unlock_bh(&nsim_dev->fa_cookie_lock);
                consume_skb(skb);
        }
        spin_unlock(&nsim_trap_data->trap_lock);
@@ -780,6 +890,7 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
        nsim_dev->fw_update_status = true;
        nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT;
        nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT;
+       spin_lock_init(&nsim_dev->fa_cookie_lock);
 
        dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev);
 
index 2eb7b0d..e46fc56 100644 (file)
@@ -178,6 +178,8 @@ struct nsim_dev {
        bool fail_reload;
        struct devlink_region *dummy_region;
        struct nsim_dev_health health;
+       struct flow_action_cookie *fa_cookie;
+       spinlock_t fa_cookie_lock; /* protects fa_cookie */
 };
 
 static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev)