diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2018-05-29 17:33:00 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-29 17:33:00 +0200 |
commit | 68542a6da651a4a3f5d280482313f14508618c43 (patch) | |
tree | dbbc3aa2f4b76ceb345df7896cbb1277e2e6372c /zebra | |
parent | Merge pull request #2307 from opensourcerouting/master-isis-tlv-copy-fix (diff) | |
parent | bgpd: attributes presence checked when mpreach is present (diff) | |
download | frr-68542a6da651a4a3f5d280482313f14508618c43.tar.xz frr-68542a6da651a4a3f5d280482313f14508618c43.zip |
Merge pull request #2142 from pguibert6WIND/fs_zebra_complement
Flowspec complement : port support and policy routing per interface and plugin wrapper
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/debug.c | 3 | ||||
-rw-r--r-- | zebra/debug.h | 2 | ||||
-rw-r--r-- | zebra/rule_netlink.c | 6 | ||||
-rw-r--r-- | zebra/zapi_msg.c | 20 | ||||
-rw-r--r-- | zebra/zebra_ns.c | 4 | ||||
-rw-r--r-- | zebra/zebra_pbr.c | 485 | ||||
-rw-r--r-- | zebra/zebra_pbr.h | 44 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 35 |
8 files changed, 562 insertions, 37 deletions
diff --git a/zebra/debug.c b/zebra/debug.c index 14b36cb5f..85be620bf 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -34,6 +34,8 @@ unsigned long zebra_debug_mpls; unsigned long zebra_debug_vxlan; unsigned long zebra_debug_pw; +DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty)); + DEFUN_NOSH (show_debugging_zebra, show_debugging_zebra_cmd, "show debugging [zebra]", @@ -88,6 +90,7 @@ DEFUN_NOSH (show_debugging_zebra, if (IS_ZEBRA_DEBUG_PW) vty_out(vty, " Zebra pseudowire debugging is on\n"); + hook_call(zebra_debug_show_debugging, vty); return CMD_SUCCESS; } diff --git a/zebra/debug.h b/zebra/debug.h index 987f9d012..1c08459e2 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -82,4 +82,6 @@ extern unsigned long zebra_debug_pw; extern void zebra_debug_init(void); +DECLARE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty)); + #endif /* _ZEBRA_DEBUG_H */ diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 5f7354585..f0ed8f2f5 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -98,6 +98,12 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) &rule->rule.filter.dst_ip.u.prefix, bytelen); } + /* fwmark, if specified */ + if (IS_RULE_FILTERING_ON_FWMARK(rule)) { + addattr32(&req.n, sizeof(req), FRA_FWMARK, + rule->rule.filter.fwmark); + } + /* Route table to use to forward, if filter criteria matches. */ if (rule->rule.action.table < 256) req.frh.table = rule->rule.action.table; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 9a18cc22f..943329b19 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2847,6 +2847,7 @@ static inline void zread_ipset(ZAPI_HANDLER_ARGS) memset(&zpi, 0, sizeof(zpi)); zpi.sock = client->sock; + zpi.vrf_id = zvrf->vrf->vrf_id; STREAM_GETL(s, zpi.unique); STREAM_GETL(s, zpi.type); STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE); @@ -2885,11 +2886,26 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS) STREAM_GETC(s, zpi.dst.prefixlen); STREAM_GET(&zpi.dst.u.prefix, s, prefix_blen(&zpi.dst)); + STREAM_GETW(s, zpi.src_port_min); + STREAM_GETW(s, zpi.src_port_max); + STREAM_GETW(s, zpi.dst_port_min); + STREAM_GETW(s, zpi.dst_port_max); + STREAM_GETC(s, zpi.proto); if (!is_default_prefix(&zpi.src)) zpi.filter_bm |= PBR_FILTER_SRC_IP; if (!is_default_prefix(&zpi.dst)) zpi.filter_bm |= PBR_FILTER_DST_IP; + if (zpi.dst_port_min != 0) + zpi.filter_bm |= PBR_FILTER_DST_PORT; + if (zpi.src_port_min != 0) + zpi.filter_bm |= PBR_FILTER_SRC_PORT; + if (zpi.dst_port_max != 0) + zpi.filter_bm |= PBR_FILTER_DST_PORT_RANGE; + if (zpi.src_port_max != 0) + zpi.filter_bm |= PBR_FILTER_SRC_PORT_RANGE; + if (zpi.proto != 0) + zpi.filter_bm |= PBR_FILTER_PROTO; /* calculate backpointer */ zpi.backpointer = zebra_pbr_lookup_ipset_pername( @@ -2913,13 +2929,17 @@ static inline void zread_iptable(ZAPI_HANDLER_ARGS) memset(&zpi, 0, sizeof(zpi)); + zpi.interface_name_list = list_new(); zpi.sock = client->sock; + zpi.vrf_id = zvrf->vrf->vrf_id; STREAM_GETL(s, zpi.unique); STREAM_GETL(s, zpi.type); STREAM_GETL(s, zpi.filter_bm); STREAM_GETL(s, zpi.action); STREAM_GETL(s, zpi.fwmark); STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE); + STREAM_GETL(s, zpi.nb_interface); + zebra_pbr_iptable_update_interfacelist(s, &zpi); if (hdr->command == ZEBRA_IPTABLE_ADD) zebra_pbr_add_iptable(zvrf->zns, &zpi); diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 5c62e366a..4526a1487 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -262,10 +262,10 @@ int zebra_ns_disable(ns_id_t ns_id, void **info) hash_clean(zns->rules_hash, zebra_pbr_rules_free); hash_free(zns->rules_hash); - hash_clean(zns->ipset_hash, zebra_pbr_ipset_free); - hash_free(zns->ipset_hash); hash_clean(zns->ipset_entry_hash, zebra_pbr_ipset_entry_free), + hash_clean(zns->ipset_hash, zebra_pbr_ipset_free); + hash_free(zns->ipset_hash); hash_free(zns->ipset_entry_hash); hash_clean(zns->iptable_hash, zebra_pbr_iptable_free); diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 54a9cdbc5..6a42aaecb 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -23,14 +23,51 @@ #include <jhash.h> #include <hash.h> +#include <memory.h> +#include <hook.h> #include "zebra/zebra_pbr.h" #include "zebra/rt.h" #include "zebra/zapi_msg.h" +#include "zebra/zebra_memory.h" /* definitions */ +DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list") + +/* definitions */ +static const struct message ipset_type_msg[] = { + {IPSET_NET_PORT_NET, "net,port,net"}, + {IPSET_NET_PORT, "net,port"}, + {IPSET_NET_NET, "net,net"}, + {IPSET_NET, "net"}, + {0} +}; /* static function declarations */ +DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns, + struct zebra_pbr_ipset_entry *ipset, + uint64_t *pkts, uint64_t *bytes), + (zns, ipset, pkts, bytes)) + +DEFINE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns, + struct zebra_pbr_iptable *iptable, + uint64_t *pkts, uint64_t *bytes), + (zns, iptable, pkts, bytes)) + +DEFINE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns, + int cmd, + struct zebra_pbr_iptable *iptable), + (zns, cmd, iptable)); + +DEFINE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns, + int cmd, + struct zebra_pbr_ipset_entry *ipset), + (zns, cmd, ipset)); + +DEFINE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns, + int cmd, + struct zebra_pbr_ipset *ipset), + (zns, cmd, ipset)); /* Private functions */ @@ -145,9 +182,15 @@ static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns, void zebra_pbr_ipset_free(void *arg) { struct zebra_pbr_ipset *ipset; + struct zebra_ns *zns; ipset = (struct zebra_pbr_ipset *)arg; - + if (vrf_is_backend_netns()) + zns = zebra_ns_lookup(ipset->vrf_id); + else + zns = zebra_ns_lookup(NS_DEFAULT); + hook_call(zebra_pbr_ipset_wrap_script_update, + zns, 0, ipset); XFREE(MTYPE_TMP, ipset); } @@ -179,8 +222,17 @@ int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2) void zebra_pbr_ipset_entry_free(void *arg) { struct zebra_pbr_ipset_entry *ipset; + struct zebra_ns *zns; ipset = (struct zebra_pbr_ipset_entry *)arg; + if (ipset->backpointer && vrf_is_backend_netns()) { + struct zebra_pbr_ipset *ips = ipset->backpointer; + + zns = zebra_ns_lookup((ns_id_t)ips->vrf_id); + } else + zns = zebra_ns_lookup(NS_DEFAULT); + hook_call(zebra_pbr_ipset_entry_wrap_script_update, + zns, 0, ipset); XFREE(MTYPE_TMP, ipset); } @@ -194,6 +246,11 @@ uint32_t zebra_pbr_ipset_entry_hash_key(void *arg) key = prefix_hash_key(&ipset->src); key = jhash_1word(ipset->unique, key); key = jhash_1word(prefix_hash_key(&ipset->dst), key); + key = jhash(&ipset->dst_port_min, 2, key); + key = jhash(&ipset->dst_port_max, 2, key); + key = jhash(&ipset->src_port_min, 2, key); + key = jhash(&ipset->src_port_max, 2, key); + key = jhash(&ipset->proto, 1, key); return key; } @@ -214,15 +271,44 @@ int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2) if (!prefix_same(&r1->dst, &r2->dst)) return 0; + if (r1->src_port_min != r2->src_port_min) + return 0; + + if (r1->src_port_max != r2->src_port_max) + return 0; + + if (r1->dst_port_min != r2->dst_port_min) + return 0; + + if (r1->dst_port_max != r2->dst_port_max) + return 0; + + if (r1->proto != r2->proto) + return 0; return 1; } void zebra_pbr_iptable_free(void *arg) { struct zebra_pbr_iptable *iptable; + struct listnode *node, *nnode; + char *name; + struct zebra_ns *zns; iptable = (struct zebra_pbr_iptable *)arg; - + if (vrf_is_backend_netns()) + zns = zebra_ns_lookup((ns_id_t)iptable->vrf_id); + else + zns = zebra_ns_lookup(NS_DEFAULT); + hook_call(zebra_pbr_iptable_wrap_script_update, + zns, 0, iptable); + + for (ALL_LIST_ELEMENTS(iptable->interface_name_list, + node, nnode, name)) { + XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); + list_delete_node(iptable->interface_name_list, + node); + } XFREE(MTYPE_TMP, iptable); } @@ -283,7 +369,6 @@ void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern); kernel_add_pbr_rule(rule); - /* * Rule Replace semantics, if we have an old, install the * new rule, look above, and then delete the old @@ -320,6 +405,45 @@ static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) } } +static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) +{ + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct zebra_pbr_ipset *ipset = b->data; + int *sock = data; + + if (ipset->sock == *sock) { + hook_call(zebra_pbr_ipset_wrap_script_update, + zns, 0, ipset); + hash_release(zns->ipset_hash, ipset); + } +} + +static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) +{ + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct zebra_pbr_ipset_entry *ipset = b->data; + int *sock = data; + + if (ipset->sock == *sock) { + hook_call(zebra_pbr_ipset_entry_wrap_script_update, + zns, 0, ipset); + hash_release(zns->ipset_entry_hash, ipset); + } +} + +static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data) +{ + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct zebra_pbr_iptable *iptable = b->data; + int *sock = data; + + if (iptable->sock == *sock) { + hook_call(zebra_pbr_iptable_wrap_script_update, + zns, 0, iptable); + hash_release(zns->iptable_hash, iptable); + } +} + static int zebra_pbr_client_close_cleanup(struct zserv *client) { int sock = client->sock; @@ -328,6 +452,12 @@ static int zebra_pbr_client_close_cleanup(struct zserv *client) if (!sock) return 0; hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock); + hash_iterate(zns->iptable_hash, + zebra_pbr_cleanup_iptable, &sock); + hash_iterate(zns->ipset_entry_hash, + zebra_pbr_cleanup_ipset_entry, &sock); + hash_iterate(zns->ipset_hash, + zebra_pbr_cleanup_ipset, &sock); return 1; } @@ -353,10 +483,14 @@ static void *pbr_ipset_alloc_intern(void *arg) void zebra_pbr_create_ipset(struct zebra_ns *zns, struct zebra_pbr_ipset *ipset) { + int ret; + (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern); - /* TODO: - * - Netlink call - */ + ret = hook_call(zebra_pbr_ipset_wrap_script_update, + zns, 1, ipset); + kernel_pbr_ipset_add_del_status(ipset, + ret ? SOUTHBOUND_INSTALL_SUCCESS + : SOUTHBOUND_INSTALL_FAILURE); } void zebra_pbr_destroy_ipset(struct zebra_ns *zns, @@ -365,13 +499,12 @@ void zebra_pbr_destroy_ipset(struct zebra_ns *zns, struct zebra_pbr_ipset *lookup; lookup = hash_lookup(zns->ipset_hash, ipset); - /* TODO: - * - Netlink destroy from kernel - * - ?? destroy ipset entries before - */ - if (lookup) + hook_call(zebra_pbr_ipset_wrap_script_update, + zns, 0, ipset); + if (lookup) { + hash_release(zns->ipset_hash, lookup); XFREE(MTYPE_TMP, lookup); - else + } else zlog_warn("%s: IPSet Entry being deleted we know nothing about", __PRETTY_FUNCTION__); } @@ -381,6 +514,12 @@ struct pbr_ipset_name_lookup { char ipset_name[ZEBRA_IPSET_NAME_SIZE]; }; +static const char *zebra_pbr_ipset_type2str(uint32_t type) +{ + return lookup_msg(ipset_type_msg, type, + "Unrecognized IPset Type"); +} + static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg) { struct pbr_ipset_name_lookup *pinl = @@ -427,12 +566,15 @@ static void *pbr_ipset_entry_alloc_intern(void *arg) void zebra_pbr_add_ipset_entry(struct zebra_ns *zns, struct zebra_pbr_ipset_entry *ipset) { + int ret; + (void)hash_get(zns->ipset_entry_hash, ipset, pbr_ipset_entry_alloc_intern); - /* TODO: - * - attach to ipset list - * - Netlink add to kernel - */ + ret = hook_call(zebra_pbr_ipset_entry_wrap_script_update, + zns, 1, ipset); + kernel_pbr_ipset_entry_add_del_status(ipset, + ret ? SOUTHBOUND_INSTALL_SUCCESS + : SOUTHBOUND_INSTALL_FAILURE); } void zebra_pbr_del_ipset_entry(struct zebra_ns *zns, @@ -441,14 +583,12 @@ void zebra_pbr_del_ipset_entry(struct zebra_ns *zns, struct zebra_pbr_ipset_entry *lookup; lookup = hash_lookup(zns->ipset_entry_hash, ipset); - /* TODO: - * - Netlink destroy - * - detach from ipset list - * - ?? if no more entres, delete ipset - */ - if (lookup) + hook_call(zebra_pbr_ipset_entry_wrap_script_update, + zns, 0, ipset); + if (lookup) { + hash_release(zns->ipset_entry_hash, lookup); XFREE(MTYPE_TMP, lookup); - else + } else zlog_warn("%s: IPSet being deleted we know nothing about", __PRETTY_FUNCTION__); } @@ -470,24 +610,36 @@ static void *pbr_iptable_alloc_intern(void *arg) void zebra_pbr_add_iptable(struct zebra_ns *zns, struct zebra_pbr_iptable *iptable) { + int ret; + (void)hash_get(zns->iptable_hash, iptable, pbr_iptable_alloc_intern); - /* TODO call netlink layer */ + ret = hook_call(zebra_pbr_iptable_wrap_script_update, zns, 1, iptable); + kernel_pbr_iptable_add_del_status(iptable, + ret ? SOUTHBOUND_INSTALL_SUCCESS + : SOUTHBOUND_INSTALL_FAILURE); } void zebra_pbr_del_iptable(struct zebra_ns *zns, struct zebra_pbr_iptable *iptable) { - struct zebra_pbr_ipset_entry *lookup; + struct zebra_pbr_iptable *lookup; lookup = hash_lookup(zns->iptable_hash, iptable); - /* TODO: - * - call netlink layer - * - detach from iptable list - */ - if (lookup) + hook_call(zebra_pbr_iptable_wrap_script_update, zns, 0, iptable); + if (lookup) { + struct listnode *node, *nnode; + char *name; + + hash_release(zns->iptable_hash, lookup); + for (ALL_LIST_ELEMENTS(iptable->interface_name_list, + node, nnode, name)) { + XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); + list_delete_node(iptable->interface_name_list, + node); + } XFREE(MTYPE_TMP, lookup); - else + } else zlog_warn("%s: IPTable being deleted we know nothing about", __PRETTY_FUNCTION__); } @@ -509,7 +661,7 @@ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED); break; case SOUTHBOUND_DELETE_FAILURE: - zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED); + zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_REMOVE); break; } } @@ -528,8 +680,10 @@ void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset, zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL); break; case SOUTHBOUND_DELETE_SUCCESS: + zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED); + break; case SOUTHBOUND_DELETE_FAILURE: - /* TODO : handling of delete event */ + zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE); break; } } @@ -551,8 +705,12 @@ void kernel_pbr_ipset_entry_add_del_status( ZAPI_IPSET_ENTRY_FAIL_INSTALL); break; case SOUTHBOUND_DELETE_SUCCESS: + zsend_ipset_entry_notify_owner(ipset, + ZAPI_IPSET_ENTRY_REMOVED); + break; case SOUTHBOUND_DELETE_FAILURE: - /* TODO : handling of delete event */ + zsend_ipset_entry_notify_owner(ipset, + ZAPI_IPSET_ENTRY_FAIL_REMOVE); break; } } @@ -571,8 +729,12 @@ void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL); break; case SOUTHBOUND_DELETE_SUCCESS: + zsend_iptable_notify_owner(iptable, + ZAPI_IPTABLE_REMOVED); + break; case SOUTHBOUND_DELETE_FAILURE: - /* TODO : handling of delete event */ + zsend_iptable_notify_owner(iptable, + ZAPI_IPTABLE_FAIL_REMOVE); break; } } @@ -584,3 +746,256 @@ int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) { return 0; } + +struct zebra_pbr_ipset_entry_unique_display { + struct zebra_pbr_ipset *zpi; + struct vty *vty; + struct zebra_ns *zns; +}; + +struct zebra_pbr_env_display { + struct zebra_ns *zns; + struct vty *vty; +}; + +static const char *zebra_pbr_prefix2str(union prefixconstptr pu, + char *str, int size) +{ + const struct prefix *p = pu.p; + char buf[PREFIX2STR_BUFFER]; + + if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) { + snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix, + buf, PREFIX2STR_BUFFER)); + return str; + } + return prefix2str(pu, str, size); +} + +static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, + uint16_t port_min, uint16_t port_max, + uint8_t proto) +{ + if (!(filter_bm & PBR_FILTER_PROTO)) { + if (port_max) + vty_out(vty, ":udp/tcp:%d-%d", + port_min, port_max); + else + vty_out(vty, ":udp/tcp:%d", + port_min); + } else { + if (port_max) + vty_out(vty, ":proto %d:%d-%d", + proto, port_min, port_max); + else + vty_out(vty, ":proto %d:%d", + proto, port_min); + } +} + +static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, + void *arg) +{ + struct zebra_pbr_ipset_entry_unique_display *unique = + (struct zebra_pbr_ipset_entry_unique_display *)arg; + struct zebra_pbr_ipset *zpi = unique->zpi; + struct vty *vty = unique->vty; + struct zebra_pbr_ipset_entry *zpie = + (struct zebra_pbr_ipset_entry *)backet->data; + uint64_t pkts = 0, bytes = 0; + struct zebra_ns *zns = unique->zns; + int ret = 0; + + if (zpie->backpointer != zpi) + return HASHWALK_CONTINUE; + + if ((zpi->type == IPSET_NET_NET) || + (zpi->type == IPSET_NET_PORT_NET)) { + char buf[PREFIX_STRLEN]; + + zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); + vty_out(vty, "\tfrom %s", buf); + if (zpie->filter_bm & PBR_FILTER_SRC_PORT) + zebra_pbr_display_port(vty, zpie->filter_bm, + zpie->src_port_min, + zpie->src_port_max, + zpie->proto); + vty_out(vty, " to "); + zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); + vty_out(vty, "%s", buf); + if (zpie->filter_bm & PBR_FILTER_DST_PORT) + zebra_pbr_display_port(vty, zpie->filter_bm, + zpie->dst_port_min, + zpie->dst_port_max, + zpie->proto); + } else if ((zpi->type == IPSET_NET) || + (zpi->type == IPSET_NET_PORT)) { + char buf[PREFIX_STRLEN]; + + if (zpie->filter_bm & PBR_FILTER_SRC_IP) { + zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); + vty_out(vty, "\tfrom %s", buf); + } + if (zpie->filter_bm & PBR_FILTER_SRC_PORT) + zebra_pbr_display_port(vty, zpie->filter_bm, + zpie->src_port_min, + zpie->src_port_max, + zpie->proto); + if (zpie->filter_bm & PBR_FILTER_DST_IP) { + zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); + vty_out(vty, "\tto %s", buf); + } + if (zpie->filter_bm & PBR_FILTER_DST_PORT) + zebra_pbr_display_port(vty, zpie->filter_bm, + zpie->dst_port_min, + zpie->dst_port_max, + zpie->proto); + } + vty_out(vty, " (%u)\n", zpie->unique); + + ret = hook_call(zebra_pbr_ipset_entry_wrap_script_get_stat, + zns, zpie, &pkts, &bytes); + if (ret && pkts > 0) + vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", + pkts, bytes); + return HASHWALK_CONTINUE; +} + +static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg) +{ + struct zebra_pbr_env_display *uniqueipset = + (struct zebra_pbr_env_display *)arg; + struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; + struct zebra_pbr_ipset_entry_unique_display unique; + struct vty *vty = uniqueipset->vty; + struct zebra_ns *zns = uniqueipset->zns; + + vty_out(vty, "IPset %s type %s\n", zpi->ipset_name, + zebra_pbr_ipset_type2str(zpi->type)); + unique.vty = vty; + unique.zpi = zpi; + unique.zns = zns; + hash_walk(zns->ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb, + &unique); + vty_out(vty, "\n"); + return HASHWALK_CONTINUE; +} + +/* + */ +void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname) +{ + struct zebra_pbr_ipset *zpi; + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct zebra_pbr_ipset_entry_unique_display unique; + struct zebra_pbr_env_display uniqueipset; + + if (ipsetname) { + zpi = zebra_pbr_lookup_ipset_pername(zns, ipsetname); + if (!zpi) { + vty_out(vty, "No IPset %s found\n", ipsetname); + return; + } + vty_out(vty, "IPset %s type %s\n", ipsetname, + zebra_pbr_ipset_type2str(zpi->type)); + + unique.vty = vty; + unique.zpi = zpi; + unique.zns = zns; + hash_walk(zns->ipset_entry_hash, + zebra_pbr_show_ipset_entry_walkcb, + &unique); + return; + } + uniqueipset.zns = zns; + uniqueipset.vty = vty; + hash_walk(zns->ipset_hash, zebra_pbr_show_ipset_walkcb, + &uniqueipset); +} + +struct pbr_rule_fwmark_lookup { + struct zebra_pbr_rule *ptr; + uint32_t fwmark; +}; + +static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet, + void *arg) +{ + struct pbr_rule_fwmark_lookup *iprule = + (struct pbr_rule_fwmark_lookup *)arg; + struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data; + + if (iprule->fwmark == zpr->rule.filter.fwmark) { + iprule->ptr = zpr; + return HASHWALK_ABORT; + } + return HASHWALK_CONTINUE; +} + +static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) +{ + struct zebra_pbr_iptable *iptable = + (struct zebra_pbr_iptable *)backet->data; + struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; + struct vty *vty = env->vty; + struct zebra_ns *zns = env->zns; + int ret; + uint64_t pkts = 0, bytes = 0; + + vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name, + iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect", + iptable->unique); + + ret = hook_call(zebra_pbr_iptable_wrap_script_get_stat, + zns, iptable, &pkts, &bytes); + if (ret && pkts > 0) + vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", + pkts, bytes); + if (iptable->action != ZEBRA_IPTABLES_DROP) { + struct pbr_rule_fwmark_lookup prfl; + + prfl.fwmark = iptable->fwmark; + prfl.ptr = NULL; + hash_walk(zns->rules_hash, + &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl); + if (prfl.ptr) { + struct zebra_pbr_rule *zpr = prfl.ptr; + + vty_out(vty, "\t table %u, fwmark %u\n", + zpr->rule.action.table, + prfl.fwmark); + } + } + return HASHWALK_CONTINUE; +} + +void zebra_pbr_show_iptable(struct vty *vty) +{ + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct zebra_pbr_env_display env; + + env.vty = vty; + env.zns = zns; + + hash_walk(zns->iptable_hash, zebra_pbr_show_iptable_walkcb, + &env); +} + +void zebra_pbr_iptable_update_interfacelist(struct stream *s, + struct zebra_pbr_iptable *zpi) +{ + uint32_t i = 0, index; + struct interface *ifp; + char *name; + + for (i = 0; i < zpi->nb_interface; i++) { + STREAM_GETL(s, index); + ifp = if_lookup_by_index(index, zpi->vrf_id); + if (!ifp) + continue; + name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name); + listnode_add(zpi->interface_name_list, name); + } +stream_failure: + return; +} diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 6b5cd1e8d..31fc55358 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -48,6 +48,8 @@ struct zebra_pbr_rule { (r->rule.filter.filter_bm & PBR_FILTER_SRC_PORT) #define IS_RULE_FILTERING_ON_DST_PORT(r) \ (r->rule.filter.filter_bm & PBR_FILTER_DST_PORT) +#define IS_RULE_FILTERING_ON_FWMARK(r) \ + (r->rule.filter.filter_bm & PBR_FILTER_FWMARK) /* * An IPSet Entry Filter @@ -61,6 +63,8 @@ struct zebra_pbr_ipset { */ int sock; + vrf_id_t vrf_id; + uint32_t unique; /* type is encoded as uint32_t @@ -87,6 +91,13 @@ struct zebra_pbr_ipset_entry { struct prefix src; struct prefix dst; + uint16_t src_port_min; + uint16_t src_port_max; + uint16_t dst_port_min; + uint16_t dst_port_max; + + uint8_t proto; + uint32_t filter_bm; struct zebra_pbr_ipset *backpointer; @@ -104,6 +115,8 @@ struct zebra_pbr_iptable { */ int sock; + vrf_id_t vrf_id; + uint32_t unique; /* include ipset type @@ -118,6 +131,10 @@ struct zebra_pbr_iptable { uint32_t action; + uint32_t nb_interface; + + struct list *interface_name_list; + char ipset_name[ZEBRA_IPSET_NAME_SIZE]; }; @@ -204,4 +221,31 @@ extern uint32_t zebra_pbr_iptable_hash_key(void *arg); extern int zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2); extern void zebra_pbr_init(void); +extern void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname); +extern void zebra_pbr_show_iptable(struct vty *vty); +extern void zebra_pbr_iptable_update_interfacelist(struct stream *s, + struct zebra_pbr_iptable *zpi); + +DECLARE_HOOK(zebra_pbr_ipset_entry_wrap_script_get_stat, (struct zebra_ns *zns, + struct zebra_pbr_ipset_entry *ipset, + uint64_t *pkts, uint64_t *bytes), + (zns, ipset, pkts, bytes)) +DECLARE_HOOK(zebra_pbr_iptable_wrap_script_get_stat, (struct zebra_ns *zns, + struct zebra_pbr_iptable *iptable, + uint64_t *pkts, uint64_t *bytes), + (zns, iptable, pkts, bytes)) +DECLARE_HOOK(zebra_pbr_iptable_wrap_script_update, (struct zebra_ns *zns, + int cmd, + struct zebra_pbr_iptable *iptable), + (zns, cmd, iptable)); + +DECLARE_HOOK(zebra_pbr_ipset_entry_wrap_script_update, (struct zebra_ns *zns, + int cmd, + struct zebra_pbr_ipset_entry *ipset), + (zns, cmd, ipset)); +DECLARE_HOOK(zebra_pbr_ipset_wrap_script_update, (struct zebra_ns *zns, + int cmd, + struct zebra_pbr_ipset *ipset), + (zns, cmd, ipset)); + #endif /* _ZEBRA_PBR_H */ diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e6f80f92a..a094ca585 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -51,6 +51,7 @@ #include "zebra/router-id.h" #include "zebra/ipforward.h" #include "zebra/zebra_vxlan_private.h" +#include "zebra/zebra_pbr.h" extern int allow_delete; @@ -3260,6 +3261,37 @@ DEFUN (show_evpn_neigh_vni_vtep, return CMD_SUCCESS; } +/* policy routing contexts */ +DEFUN (show_pbr_ipset, + show_pbr_ipset_cmd, + "show pbr ipset [WORD]", + SHOW_STR + "Policy-Based Routing\n" + "IPset Context information\n" + "IPset Name information\n") +{ + int idx = 0; + int found = 0; + found = argv_find(argv, argc, "WORD", &idx); + if (!found) + zebra_pbr_show_ipset_list(vty, NULL); + else + zebra_pbr_show_ipset_list(vty, argv[idx]->arg); + return CMD_SUCCESS; +} + +/* policy routing contexts */ +DEFUN (show_pbr_iptable, + show_pbr_iptable_cmd, + "show pbr iptable", + SHOW_STR + "Policy-Based Routing\n" + "IPtable Context information\n") +{ + zebra_pbr_show_iptable(vty); + return CMD_SUCCESS; +} + /* Static ip route configuration write function. */ static int zebra_ip_config(struct vty *vty) { @@ -3762,6 +3794,9 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd); install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd); + install_element(VIEW_NODE, &show_pbr_ipset_cmd); + install_element(VIEW_NODE, &show_pbr_iptable_cmd); + install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd); install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd); install_element(VRF_NODE, &vrf_vni_mapping_cmd); |