diff options
-rw-r--r-- | zebra/rule_netlink.c | 8 | ||||
-rw-r--r-- | zebra/zebra_ns.c | 7 | ||||
-rw-r--r-- | zebra/zebra_ns.h | 2 | ||||
-rw-r--r-- | zebra/zebra_pbr.c | 88 | ||||
-rw-r--r-- | zebra/zebra_pbr.h | 9 | ||||
-rw-r--r-- | zebra/zserv.c | 2 |
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: |