Add ILA_CMD_FLUSH netlink command to clear the ILA translation table.

Signed-off-by: Tom Herbert <t...@quantonium.net>
---
 include/uapi/linux/ila.h |  1 +
 net/ipv6/ila/ila.h       |  1 +
 net/ipv6/ila/ila_main.c  |  6 +++++
 net/ipv6/ila/ila_xlat.c  | 62 ++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/ila.h b/include/uapi/linux/ila.h
index 483b77af4eb8..db45d3e49a12 100644
--- a/include/uapi/linux/ila.h
+++ b/include/uapi/linux/ila.h
@@ -30,6 +30,7 @@ enum {
        ILA_CMD_ADD,
        ILA_CMD_DEL,
        ILA_CMD_GET,
+       ILA_CMD_FLUSH,
 
        __ILA_CMD_MAX,
 };
diff --git a/net/ipv6/ila/ila.h b/net/ipv6/ila/ila.h
index faba7824ea56..1f747bcbec29 100644
--- a/net/ipv6/ila/ila.h
+++ b/net/ipv6/ila/ila.h
@@ -123,6 +123,7 @@ void ila_xlat_exit_net(struct net *net);
 int ila_xlat_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info);
+int ila_xlat_nl_cmd_flush(struct sk_buff *skb, struct genl_info *info);
 int ila_xlat_nl_dump_start(struct netlink_callback *cb);
 int ila_xlat_nl_dump_done(struct netlink_callback *cb);
 int ila_xlat_nl_dump(struct sk_buff *skb, struct netlink_callback *cb);
diff --git a/net/ipv6/ila/ila_main.c b/net/ipv6/ila/ila_main.c
index f6ac6b14577e..18fac76b9520 100644
--- a/net/ipv6/ila/ila_main.c
+++ b/net/ipv6/ila/ila_main.c
@@ -27,6 +27,12 @@ static const struct genl_ops ila_nl_ops[] = {
                .flags = GENL_ADMIN_PERM,
        },
        {
+               .cmd = ILA_CMD_FLUSH,
+               .doit = ila_xlat_nl_cmd_flush,
+               .policy = ila_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
                .cmd = ILA_CMD_GET,
                .doit = ila_xlat_nl_cmd_get_mapping,
                .start = ila_xlat_nl_dump_start,
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index d05de891dfb6..51a15ce50a64 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -164,9 +164,9 @@ static inline void ila_release(struct ila_map *ila)
        kfree_rcu(ila, rcu);
 }
 
-static void ila_free_cb(void *ptr, void *arg)
+static void ila_free_node(struct ila_map *ila)
 {
-       struct ila_map *ila = (struct ila_map *)ptr, *next;
+       struct ila_map *next;
 
        /* Assume rcu_readlock held */
        while (ila) {
@@ -176,6 +176,11 @@ static void ila_free_cb(void *ptr, void *arg)
        }
 }
 
+static void ila_free_cb(void *ptr, void *arg)
+{
+       ila_free_node((struct ila_map *)ptr);
+}
+
 static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila);
 
 static unsigned int
@@ -365,6 +370,59 @@ int ila_xlat_nl_cmd_del_mapping(struct sk_buff *skb, 
struct genl_info *info)
        return 0;
 }
 
+static inline spinlock_t *lock_from_ila_map(struct ila_net *ilan,
+                                           struct ila_map *ila)
+{
+       return ila_get_lock(ilan, ila->xp.ip.locator_match);
+}
+
+int ila_xlat_nl_cmd_flush(struct sk_buff *skb, struct genl_info *info)
+{
+       struct net *net = genl_info_net(info);
+       struct ila_net *ilan = net_generic(net, ila_net_id);
+       struct rhashtable_iter iter;
+       struct ila_map *ila;
+       spinlock_t *lock;
+       int ret;
+
+       ret = rhashtable_walk_init(&ilan->xlat.rhash_table, &iter, GFP_KERNEL);
+       if (ret)
+               goto done;
+
+       rhashtable_walk_start(&iter);
+
+       for (;;) {
+               ila = rhashtable_walk_next(&iter);
+
+               if (IS_ERR(ila)) {
+                       if (PTR_ERR(ila) == -EAGAIN)
+                               continue;
+                       ret = PTR_ERR(ila);
+                       goto done;
+               } else if (!ila) {
+                       break;
+               }
+
+               lock = lock_from_ila_map(ilan, ila);
+
+               spin_lock(lock);
+
+               ret = rhashtable_remove_fast(&ilan->xlat.rhash_table,
+                                            &ila->node, rht_params);
+               if (!ret)
+                       ila_free_node(ila);
+
+               spin_unlock(lock);
+
+               if (ret)
+                       break;
+       }
+
+done:
+       rhashtable_walk_stop(&iter);
+       return ret;
+}
+
 static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
 {
        if (nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR,
-- 
2.11.0

Reply via email to