summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--zebra/rule_netlink.c8
-rw-r--r--zebra/zebra_ns.c7
-rw-r--r--zebra/zebra_ns.h2
-rw-r--r--zebra/zebra_pbr.c88
-rw-r--r--zebra/zebra_pbr.h9
-rw-r--r--zebra/zserv.c2
6 files changed, 106 insertions, 10 deletions
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index 3228d0e4b..c64d9f6ab 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -85,8 +85,9 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule,
addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->priority);
/* interface on which applied */
- addattr_l(&req.n, sizeof(req), FRA_IFNAME, ifp->name,
- strlen(ifp->name)+1);
+ if (ifp)
+ addattr_l(&req.n, sizeof(req), FRA_IFNAME, ifp->name,
+ strlen(ifp->name) + 1);
/* source IP, if specified */
if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
@@ -114,7 +115,8 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule,
zlog_debug(
"Tx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
nl_msg_type_to_str(cmd), nl_family_to_str(family),
- ifp->name, ifp->ifindex, rule->priority,
+ ifp ? ifp->name : "Unknown", ifp ? ifp->ifindex : 0,
+ rule->priority,
prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)),
prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)),
rule->action.table);
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 580ff3eec..192e8ad41 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -36,6 +36,7 @@
#include "debug.h"
#include "zebra_netns_notify.h"
#include "zebra_netns_id.h"
+#include "zebra_pbr.h"
extern struct zebra_privs_t zserv_privs;
@@ -211,12 +212,15 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
struct zebra_ns_table *znst;
struct zebra_ns *zns = (struct zebra_ns *)(*info);
+ hash_clean(zns->rules_hash, zebra_pbr_rules_free);
+ hash_free(zns->rules_hash);
while (!RB_EMPTY(zebra_ns_table_head, &zns->ns_tables)) {
znst = RB_ROOT(zebra_ns_table_head, &zns->ns_tables);
RB_REMOVE(zebra_ns_table_head, &zns->ns_tables, znst);
zebra_ns_free_table(znst);
}
+
route_table_finish(zns->if_table);
zebra_vxlan_ns_disable(zns);
#if defined(HAVE_RTADV)
@@ -257,6 +261,9 @@ int zebra_ns_init(void)
/* Default NS is activated */
zebra_ns_enable(ns_id, (void **)&dzns);
+ dzns->rules_hash =
+ hash_create_size(8, zebra_pbr_rules_hash_key,
+ zebra_pbr_rules_hash_equal, "Rules Hash");
if (vrf_is_backend_netns()) {
ns_add_hook(NS_NEW_HOOK, zebra_ns_new);
ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled);
diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h
index 1d7b6f725..19ecba1f0 100644
--- a/zebra/zebra_ns.h
+++ b/zebra/zebra_ns.h
@@ -71,6 +71,8 @@ struct zebra_ns {
struct zebra_ns_table_head ns_tables;
+ struct hash *rules_hash;
+
/* Back pointer */
struct ns *ns;
};
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 8a7e693bb..3f8655552 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -21,6 +21,9 @@
#include <zebra.h>
+#include <jhash.h>
+#include <hash.h>
+
#include "zebra/zebra_pbr.h"
#include "zebra/rt.h"
@@ -31,14 +34,93 @@
/* Private functions */
/* Public functions */
-void zebra_pbr_add_rule(struct zebra_pbr_rule *rule, struct interface *ifp)
+void zebra_pbr_rules_free(void *arg)
{
+ struct zebra_pbr_rule *rule;
+
+ rule = (struct zebra_pbr_rule *)arg;
+
+ kernel_del_pbr_rule(rule, NULL);
+ XFREE(MTYPE_TMP, rule);
+}
+
+uint32_t zebra_pbr_rules_hash_key(void *arg)
+{
+ struct zebra_pbr_rule *rule;
+ uint32_t key;
+
+ rule = (struct zebra_pbr_rule *)arg;
+ key = jhash_3words(rule->seq, rule->priority, rule->action.table,
+ prefix_hash_key(&rule->filter.src_ip));
+ return jhash_3words(rule->filter.src_port, rule->filter.dst_port,
+ prefix_hash_key(&rule->filter.dst_ip), key);
+}
+
+int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
+{
+ const struct zebra_pbr_rule *r1, *r2;
+
+ r1 = (const struct zebra_pbr_rule *)arg1;
+ r2 = (const struct zebra_pbr_rule *)arg2;
+
+ if (r1->seq != r2->seq)
+ return 0;
+
+ if (r1->priority != r2->priority)
+ return 0;
+
+ if (r1->action.table != r2->action.table)
+ return 0;
+
+ if (r1->filter.src_port != r2->filter.src_port)
+ return 0;
+
+ if (r1->filter.dst_port != r2->filter.dst_port)
+ return 0;
+
+ if (!prefix_same(&r1->filter.src_ip, &r2->filter.src_ip))
+ return 0;
+
+ if (!prefix_same(&r1->filter.dst_ip, &r2->filter.dst_ip))
+ return 0;
+
+ return 1;
+}
+
+static void *pbr_rule_alloc_intern(void *arg)
+{
+ struct zebra_pbr_rule *zpr;
+ struct zebra_pbr_rule *new;
+
+ zpr = (struct zebra_pbr_rule *)arg;
+
+ new = XCALLOC(MTYPE_TMP, sizeof(*new));
+
+ memcpy(new, zpr, sizeof(*zpr));
+
+ return new;
+}
+
+void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule,
+ struct interface *ifp)
+{
+ (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern);
kernel_add_pbr_rule(rule, ifp);
}
-void zebra_pbr_del_rule(struct zebra_pbr_rule *rule, struct interface *ifp)
+void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule,
+ struct interface *ifp)
{
+ struct zebra_pbr_rule *lookup;
+
+ lookup = hash_lookup(zns->rules_hash, rule);
kernel_del_pbr_rule(rule, ifp);
+
+ if (lookup)
+ XFREE(MTYPE_TMP, lookup);
+ else
+ zlog_warn("%s: Rule being deleted we know nothing about",
+ __PRETTY_FUNCTION__);
}
/*
@@ -57,5 +139,3 @@ int kernel_pbr_rule_del(struct zebra_pbr_rule *rule, struct interface *ifp)
{
return 0;
}
-
-
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
index 6a97ef55e..f5f139cbd 100644
--- a/zebra/zebra_pbr.h
+++ b/zebra/zebra_pbr.h
@@ -90,8 +90,10 @@ struct zebra_pbr_rule {
struct zebra_pbr_action action;
};
-void zebra_pbr_add_rule(struct zebra_pbr_rule *rule, struct interface *ifp);
-void zebra_pbr_del_rule(struct zebra_pbr_rule *rule, struct interface *ifp);
+void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule,
+ struct interface *ifp);
+void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule,
+ struct interface *ifp);
/*
* Install specified rule for a specific interface.
@@ -126,4 +128,7 @@ extern void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule,
struct interface *ifp);
+extern void zebra_pbr_rules_free(void *arg);
+extern uint32_t zebra_pbr_rules_hash_key(void *arg);
+extern int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2);
#endif /* _ZEBRA_PBR_H */
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 7ec8525f4..a56b388ec 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -2636,7 +2636,7 @@ static inline void zread_rule(uint16_t command, struct zserv *client,
if (zpr.filter.dst_port)
zpr.filter.filter_bm |= PBR_FILTER_DST_PORT;
- zebra_pbr_add_rule(&zpr, ifp);
+ zebra_pbr_add_rule(zvrf->zns, &zpr, ifp);
}
stream_failure: