From e208c8f94392286aaf77c6d8f2a8b4d22fa3f1d7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 5 Feb 2018 10:40:09 -0500 Subject: [PATCH 01/11] bgpd, lib, zebra: Switch to work_queue_free_and_null The work_queue_free function free'd up the wq pointer but did not set it too NULL. This of course causes situations where we may use the work_queue after it is freed. Let's modify the work_queue to set the pointer for you. Signed-off-by: Donald Sharp --- bgpd/bgpd.c | 12 ++++-------- bgpd/rfapi/rfapi_import.c | 2 +- bgpd/rfapi/rfapi_rib.c | 6 ++---- lib/workqueue.c | 8 +++++++- lib/workqueue.h | 18 ++++++++++++++++-- zebra/main.c | 4 ++-- 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6034576935..fde72da4c8 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1079,10 +1079,8 @@ static void peer_free(struct peer *peer) XFREE(MTYPE_TMP, peer->notify.data); memset(&peer->notify, 0, sizeof(struct bgp_notify)); - if (peer->clear_node_queue) { - work_queue_free(peer->clear_node_queue); - peer->clear_node_queue = NULL; - } + if (peer->clear_node_queue) + work_queue_free_and_null(&peer->clear_node_queue); bgp_sync_delete(peer); @@ -7639,10 +7637,8 @@ void bgp_terminate(void) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); - if (bm->process_main_queue) { - work_queue_free(bm->process_main_queue); - bm->process_main_queue = NULL; - } + if (bm->process_main_queue) + work_queue_free_and_null(&bm->process_main_queue); if (bm->t_rmap_update) BGP_TIMER_OFF(bm->t_rmap_update); diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index c7d64bf1ed..348f1557e2 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -4336,7 +4336,7 @@ void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h) h->import_mac = NULL; } - work_queue_free(h->deferred_close_q); + work_queue_free_and_null(&h->deferred_close_q); if (h->rfp != NULL) rfp_stop(h->rfp); diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 2a8a465b70..c71f59563f 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -571,10 +571,8 @@ void rfapiRibClear(struct rfapi_descriptor *rfd) } } } - if (rfd->updated_responses_queue) { - work_queue_free(rfd->updated_responses_queue); - rfd->updated_responses_queue = NULL; - } + if (rfd->updated_responses_queue) + work_queue_free_and_null(&rfd->updated_responses_queue); } /* diff --git a/lib/workqueue.c b/lib/workqueue.c index d4ff3ee6ce..1af51c06c1 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -101,7 +101,7 @@ struct work_queue *work_queue_new(struct thread_master *m, return new; } -void work_queue_free(struct work_queue *wq) +void work_queue_free_original(struct work_queue *wq) { if (wq->thread != NULL) thread_cancel(wq->thread); @@ -119,6 +119,12 @@ void work_queue_free(struct work_queue *wq) return; } +void work_queue_free_and_null(struct work_queue **wq) +{ + work_queue_free_original(*wq); + *wq = NULL; +} + bool work_queue_is_scheduled(struct work_queue *wq) { return (wq->thread != NULL); diff --git a/lib/workqueue.h b/lib/workqueue.h index de49cb87fb..c9785de09a 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -28,7 +28,7 @@ DECLARE_MTYPE(WORK_QUEUE) /* Hold time for the initial schedule of a queue run, in millisec */ -#define WORK_QUEUE_DEFAULT_HOLD 50 +#define WORK_QUEUE_DEFAULT_HOLD 50 /* action value, for use by item processor and item error handlers */ typedef enum { @@ -148,8 +148,22 @@ static inline void work_queue_item_dequeue(struct work_queue *wq, * anything to it */ extern struct work_queue *work_queue_new(struct thread_master *, const char *); + /* destroy work queue */ -extern void work_queue_free(struct work_queue *); +/* + * The usage of work_queue_free is being transitioned to pass + * in the double pointer to remove use after free's. + */ +#if CONFDATE > 20190205 +CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup") +#endif +extern void work_queue_free_and_null(struct work_queue **); +extern void work_queue_free_original(struct work_queue *); +#define work_queue_free(X) \ + do { \ + work_queue_free_original((X)); \ + CPP_WARN("Please use work_queue_free_and_null"); \ + } while (0) /* Add the supplied data as an item onto the workqueue */ extern void work_queue_add(struct work_queue *, void *); diff --git a/zebra/main.c b/zebra/main.c index 6a08247f11..00d853ea26 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -140,7 +140,7 @@ static void sigint(void) SET_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN); } if (zebrad.lsp_process_q) - work_queue_free(zebrad.lsp_process_q); + work_queue_free_and_null(&zebrad.lsp_process_q); vrf_terminate(); ns_walk_func(zebra_ns_disabled); @@ -151,7 +151,7 @@ static void sigint(void) route_map_finish(); list_delete_and_null(&zebrad.client_list); - work_queue_free(zebrad.ribq); + work_queue_free_and_null(&zebrad.ribq); meta_queue_free(zebrad.mq); frr_fini(); From ba1849ef8c8560cff44008e06c5668b8261b033e Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 9 Feb 2018 18:38:02 -0500 Subject: [PATCH 02/11] lib, zebra: Allow zapi to send down the tableid Allow the calling daemon to pass down what table-id we want to use to install the route. Useful for PBR. The vrf id passed must be the VRF_DEFAULT else this value is ignored. Signed-off-by: Donald Sharp --- lib/zclient.c | 4 ++++ lib/zclient.h | 8 ++++++++ zebra/zserv.c | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index f853824bbb..3f2021a5b5 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1058,6 +1058,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api) stream_putl(s, api->tag); if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU)) stream_putl(s, api->mtu); + if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID)) + stream_putl(s, api->tableid); /* Put length at the first point of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -1207,6 +1209,8 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETL(s, api->tag); if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU)) STREAM_GETL(s, api->mtu); + if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID)) + STREAM_GETL(s, api->tableid); stream_failure: return 0; diff --git a/lib/zclient.h b/lib/zclient.h index 1848440db2..39566b1739 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -225,6 +225,12 @@ struct zclient { #define ZAPI_MESSAGE_MTU 0x10 #define ZAPI_MESSAGE_SRCPFX 0x20 #define ZAPI_MESSAGE_LABEL 0x40 +/* + * This should only be used by a DAEMON that needs to communicate + * the table being used is not in the VRF. You must pass the + * default vrf, else this will be ignored. + */ +#define ZAPI_MESSAGE_TABLEID 0x80 /* Zserv protocol message header */ struct zserv_header { @@ -289,6 +295,8 @@ struct zapi_route { vrf_id_t vrf_id; + uint32_t tableid; + struct ethaddr rmac; }; diff --git a/zebra/zserv.c b/zebra/zserv.c index 8275ee1a3c..d245e09724 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1164,7 +1164,10 @@ static int zread_route_add(struct zserv *client, u_short length, re->flags = api.flags; re->uptime = time(NULL); re->vrf_id = vrf_id; - re->table = zvrf->table_id; + if (api.tableid && vrf_id == VRF_DEFAULT) + re->table = api.tableid; + else + re->table = zvrf->table_id; if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { for (i = 0; i < api.nexthop_num; i++) { From 7ee30f288e9d572d971c2a36b68775c7d2fac299 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 26 Jan 2018 10:12:35 -0500 Subject: [PATCH 03/11] lib: Isolate nexthop_group functions to nexthop_group.c Also modify `struct route_entry` to use nexthop_groups. Move ALL_NEXTHOPS loop to nexthop_group.h Signed-off-by: Donald Sharp --- lib/nexthop.c | 43 --------------------- lib/nexthop.h | 16 -------- lib/nexthop_group.c | 66 +++++++++++++++++++++++++++++++ lib/nexthop_group.h | 52 +++++++++++++++++++++++++ lib/subdir.am | 2 + tests/lib/test_nexthop_iter.c | 10 ++--- zebra/redistribute.c | 10 ++--- zebra/rib.h | 3 +- zebra/rt_netlink.c | 6 +-- zebra/rt_socket.c | 4 +- zebra/zebra_fpm_netlink.c | 2 +- zebra/zebra_fpm_protobuf.c | 2 +- zebra/zebra_mpls.c | 12 +++--- zebra/zebra_pw.c | 2 +- zebra/zebra_rib.c | 73 ++++++++++++++++++----------------- zebra/zebra_rnh.c | 19 ++++----- zebra/zebra_snmp.c | 21 +++++----- zebra/zebra_static.c | 2 +- zebra/zebra_vty.c | 10 ++--- zebra/zserv.c | 22 +++++------ 20 files changed, 222 insertions(+), 155 deletions(-) create mode 100644 lib/nexthop_group.c create mode 100644 lib/nexthop_group.h diff --git a/lib/nexthop.c b/lib/nexthop.c index 6809a01469..cee34e85c7 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -143,49 +143,6 @@ struct nexthop *nexthop_new(void) return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop)); } -/* Add nexthop to the end of a nexthop list. */ -void nexthop_add(struct nexthop **target, struct nexthop *nexthop) -{ - struct nexthop *last; - - for (last = *target; last && last->next; last = last->next) - ; - if (last) - last->next = nexthop; - else - *target = nexthop; - nexthop->prev = last; -} - -void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, - struct nexthop *rparent) -{ - struct nexthop *nexthop; - struct nexthop *nh1; - - for (nh1 = nh; nh1; nh1 = nh1->next) { - nexthop = nexthop_new(); - nexthop->vrf_id = nh1->vrf_id; - nexthop->ifindex = nh1->ifindex; - nexthop->type = nh1->type; - nexthop->flags = nh1->flags; - memcpy(&nexthop->gate, &nh1->gate, sizeof(nh1->gate)); - memcpy(&nexthop->src, &nh1->src, sizeof(nh1->src)); - memcpy(&nexthop->rmap_src, &nh1->rmap_src, - sizeof(nh1->rmap_src)); - nexthop->rparent = rparent; - if (nh1->nh_label) - nexthop_add_labels(nexthop, nh1->nh_label_type, - nh1->nh_label->num_labels, - &nh1->nh_label->label[0]); - nexthop_add(tnh, nexthop); - - if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE)) - copy_nexthops(&nexthop->resolved, nh1->resolved, - nexthop); - } -} - /* Free nexthop. */ void nexthop_free(struct nexthop *nexthop) { diff --git a/lib/nexthop.h b/lib/nexthop.h index 0be949688f..0ca8a0063a 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -109,24 +109,8 @@ struct nexthop { struct mpls_label_stack *nh_label; }; -/* The following for loop allows to iterate over the nexthop - * structure of routes. - * - * head: The pointer to the first nexthop in the chain. - * - * nexthop: The pointer to the current nexthop, either in the - * top-level chain or in a resolved chain. - */ -#define ALL_NEXTHOPS(head, nexthop) \ - (nexthop) = (head); \ - (nexthop); \ - (nexthop) = nexthop_next(nexthop) - struct nexthop *nexthop_new(void); -void nexthop_add(struct nexthop **target, struct nexthop *nexthop); -void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, - struct nexthop *rparent); void nexthop_free(struct nexthop *nexthop); void nexthops_free(struct nexthop *nexthop); diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c new file mode 100644 index 0000000000..8bdc585405 --- /dev/null +++ b/lib/nexthop_group.c @@ -0,0 +1,66 @@ +/* + * Nexthop Group structure definition. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include +#include + +/* Add nexthop to the end of a nexthop list. */ +void nexthop_add(struct nexthop **target, struct nexthop *nexthop) +{ + struct nexthop *last; + + for (last = *target; last && last->next; last = last->next) + ; + if (last) + last->next = nexthop; + else + *target = nexthop; + nexthop->prev = last; +} + +void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, + struct nexthop *rparent) +{ + struct nexthop *nexthop; + struct nexthop *nh1; + + for (nh1 = nh; nh1; nh1 = nh1->next) { + nexthop = nexthop_new(); + nexthop->vrf_id = nh1->vrf_id; + nexthop->ifindex = nh1->ifindex; + nexthop->type = nh1->type; + nexthop->flags = nh1->flags; + memcpy(&nexthop->gate, &nh1->gate, sizeof(nh1->gate)); + memcpy(&nexthop->src, &nh1->src, sizeof(nh1->src)); + memcpy(&nexthop->rmap_src, &nh1->rmap_src, + sizeof(nh1->rmap_src)); + nexthop->rparent = rparent; + if (nh1->nh_label) + nexthop_add_labels(nexthop, nh1->nh_label_type, + nh1->nh_label->num_labels, + &nh1->nh_label->label[0]); + nexthop_add(tnh, nexthop); + + if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE)) + copy_nexthops(&nexthop->resolved, nh1->resolved, + nexthop); + } +} diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h new file mode 100644 index 0000000000..26900959cc --- /dev/null +++ b/lib/nexthop_group.h @@ -0,0 +1,52 @@ +/* + * Nexthop Group structure definition. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __NEXTHOP_GROUP__ +#define __NEXTHOP_GROUP__ + +/* + * What is a nexthop group? + * + * A nexthop group is a collection of nexthops that make up + * the ECMP path for the route. + * + * This module provides a proper abstraction to this idea. + */ +struct nexthop_group { + struct nexthop *nexthop; +}; + +void nexthop_add(struct nexthop **target, struct nexthop *nexthop); +void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, + struct nexthop *rparent); + +/* The following for loop allows to iterate over the nexthop + * structure of routes. + * + * head: The pointer to the first nexthop in the chain. + * + * nexthop: The pointer to the current nexthop, either in the + * top-level chain or in a resolved chain. + */ +#define ALL_NEXTHOPS(head, nhop) \ + (nhop) = (head.nexthop); \ + (nhop); \ + (nhop) = nexthop_next(nhop) +#endif diff --git a/lib/subdir.am b/lib/subdir.am index c8da5a2a8c..5001b3cecf 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -45,6 +45,7 @@ lib_libfrr_la_SOURCES = \ lib/nexthop.c \ lib/netns_linux.c \ lib/netns_other.c \ + lib/nexthop_group.c \ lib/openbsd-tree.c \ lib/pid_output.c \ lib/plist.c \ @@ -124,6 +125,7 @@ pkginclude_HEADERS += \ lib/mpls.h \ lib/network.h \ lib/nexthop.h \ + lib/nexthop_group.h \ lib/ns.h \ lib/openbsd-queue.h \ lib/openbsd-tree.h \ diff --git a/tests/lib/test_nexthop_iter.c b/tests/lib/test_nexthop_iter.c index 8d7353d4dc..f21f3bbb33 100644 --- a/tests/lib/test_nexthop_iter.c +++ b/tests/lib/test_nexthop_iter.c @@ -60,7 +60,7 @@ static void str_appendf(char **buf, const char *format, ...) * and its expected representation */ struct nexthop_chain { /* Head of the chain */ - struct nexthop *head; + struct nexthop_group head; /* Last nexthop in top chain */ struct nexthop *current_top; /* Last nexthop in current recursive chain */ @@ -85,12 +85,12 @@ static void nexthop_chain_add_top(struct nexthop_chain *nc) nh = calloc(sizeof(*nh), 1); assert(nh); - if (nc->head) { + if (nc->head.nexthop) { nc->current_top->next = nh; nh->prev = nc->current_top; nc->current_top = nh; } else { - nc->head = nc->current_top = nh; + nc->head.nexthop = nc->current_top = nh; } nc->current_recursive = NULL; str_appendf(&nc->repr, "%p\n", nh); @@ -166,8 +166,8 @@ static void nexthop_clear_recursive(struct nexthop *tcur) } static void nexthop_chain_clear(struct nexthop_chain *nc) { - nexthop_clear_recursive(nc->head); - nc->head = nc->current_top = nc->current_recursive = NULL; + nexthop_clear_recursive(nc->head.nexthop); + nc->head.nexthop = nc->current_top = nc->current_recursive = NULL; free(nc->repr); nc->repr = NULL; } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index c03d755b2a..a7b2361ac6 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -519,8 +519,8 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re, afi = family2afi(rn->p.family); if (rmap_name) ret = zebra_import_table_route_map_check( - afi, re->type, &rn->p, re->nexthop, re->vrf_id, re->tag, - rmap_name); + afi, re->type, &rn->p, re->ng.nexthop, re->vrf_id, + re->tag, rmap_name); if (ret != RMAP_MATCH) { zebra_del_import_table_entry(rn, re); @@ -552,7 +552,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re, newre->nexthop_num = 0; newre->uptime = time(NULL); newre->instance = re->table; - route_entry_copy_nexthops(newre, re->nexthop); + route_entry_copy_nexthops(newre, re->ng.nexthop); rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre); @@ -568,8 +568,8 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re) prefix_copy(&p, &rn->p); rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table, - re->flags, &p, NULL, re->nexthop, zebrad.rtm_table_default, - re->metric, false, NULL); + re->flags, &p, NULL, re->ng.nexthop, + zebrad.rtm_table_default, re->metric, false, NULL); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index 5f03f1a131..5dd444dce0 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -29,6 +29,7 @@ #include "table.h" #include "queue.h" #include "nexthop.h" +#include "nexthop_group.h" #include "vrf.h" #include "if.h" #include "mpls.h" @@ -43,7 +44,7 @@ struct route_entry { struct route_entry *prev; /* Nexthop structure */ - struct nexthop *nexthop; + struct nexthop_group ng; /* Tag */ route_tag_t tag; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e95665feb4..2b758c58d8 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1398,7 +1398,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p, /* Count overall nexthops so we can decide whether to use singlepath * or multipath case. */ nexthop_num = 0; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if (cmd == RTM_NEWROUTE && !NEXTHOP_IS_ACTIVE(nexthop->flags)) @@ -1413,7 +1413,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p, /* Singlepath case. */ if (nexthop_num == 1 || multipath_num == 1) { nexthop_num = 0; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { /* * So we want to cover 2 types of blackhole * routes here: @@ -1513,7 +1513,7 @@ static int netlink_route_multipath(int cmd, struct prefix *p, rtnh = RTA_DATA(rta); nexthop_num = 0; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (nexthop_num >= multipath_num) break; diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 1aa402672e..433faf789a 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -123,7 +123,7 @@ static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re) #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Make gateway. */ - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -303,7 +303,7 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Make gateway. */ - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 27c7891372..97a0e142fb 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -249,7 +249,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, ri->rtm_type = RTN_UNICAST; ri->metric = &re->metric; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (ri->num_nhs >= multipath_num) break; diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c index b850f1fb1e..e661b6efc7 100644 --- a/zebra/zebra_fpm_protobuf.c +++ b/zebra/zebra_fpm_protobuf.c @@ -170,7 +170,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, * Figure out the set of nexthops to be added to the message. */ num_nhs = 0; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (num_nhs >= multipath_num) break; diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 2dc98127f5..0af06806d3 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -182,7 +182,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, * the label advertised by the recursive nexthop (plus we don't have the * logic yet to push multiple labels). */ - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { /* Skip inactive and recursive entries. */ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -637,7 +637,7 @@ static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe, || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) continue; - for (match_nh = match->nexthop; match_nh; + for (match_nh = match->ng.nexthop; match_nh; match_nh = match_nh->next) { if (match->type == ZEBRA_ROUTE_CONNECT || nexthop->ifindex == match_nh->ifindex) { @@ -688,10 +688,10 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, break; } - if (!match || !match->nexthop) + if (!match || !match->ng.nexthop) return 0; - nexthop->ifindex = match->nexthop->ifindex; + nexthop->ifindex = match->ng.nexthop->ifindex; return 1; } @@ -2286,7 +2286,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, if (re == NULL) return -1; - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -2504,7 +2504,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) for (rn = route_top(table); rn; rn = route_next(rn)) { update = 0; RNODE_FOREACH_RE (rn, re) { - for (nexthop = re->nexthop; nexthop; + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { if (nexthop->nh_label_type != ZEBRA_LSP_LDP) continue; diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 96bee36be6..68ad69397f 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -256,7 +256,7 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw) * Need to ensure that there's a label binding for all nexthops. * Otherwise, ECMP for this route could render the pseudowire unusable. */ - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (!nexthop->nh_label) { if (IS_ZEBRA_DEBUG_PW) zlog_warn("%s: unlabeled route for %s", diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c5906f5829..1204da92fb 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -183,7 +183,7 @@ int zebra_check_addr(struct prefix *p) /* Add nexthop to the end of a rib node's nexthop list */ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) { - nexthop_add(&re->nexthop, nexthop); + nexthop_add(&re->ng.nexthop, nexthop); re->nexthop_num++; } @@ -193,8 +193,8 @@ void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) */ void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh) { - assert(!re->nexthop); - copy_nexthops(&re->nexthop, nh, NULL); + assert(!re->ng.nexthop); + copy_nexthops(&re->ng.nexthop, nh, NULL); for (struct nexthop *nexthop = nh; nexthop; nexthop = nexthop->next) re->nexthop_num++; } @@ -207,7 +207,7 @@ void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop) if (nexthop->prev) nexthop->prev->next = nexthop->next; else - re->nexthop = nexthop->next; + re->ng.nexthop = nexthop->next; re->nexthop_num--; } @@ -507,7 +507,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ - newhop = match->nexthop; + newhop = match->ng.nexthop; if (newhop) { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV6) @@ -516,7 +516,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return 1; } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; - for (ALL_NEXTHOPS(match->nexthop, newhop)) { + for (ALL_NEXTHOPS(match->ng, newhop)) { if (!CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_FIB)) continue; @@ -539,7 +539,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return resolved; } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; - for (ALL_NEXTHOPS(match->nexthop, newhop)) { + for (ALL_NEXTHOPS(match->ng, newhop)) { if (!CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_FIB)) continue; @@ -610,7 +610,7 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, } else { if (match->type != ZEBRA_ROUTE_CONNECT) { int found = 0; - for (ALL_NEXTHOPS(match->nexthop, newhop)) + for (ALL_NEXTHOPS(match->ng, newhop)) if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_FIB)) { found = 1; @@ -733,7 +733,7 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) if (match->type == ZEBRA_ROUTE_CONNECT) return match; - for (ALL_NEXTHOPS(match->nexthop, nexthop)) + for (ALL_NEXTHOPS(match->ng, nexthop)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) return match; @@ -793,7 +793,7 @@ int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate, /* Ok, we have a cood candidate, let's check it's nexthop list... */ nexthops_active = 0; - for (ALL_NEXTHOPS(match->nexthop, nexthop)) + for (ALL_NEXTHOPS(match->ng, nexthop)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { nexthops_active = 1; if (nexthop->gate.ipv4.s_addr == sockunion2ip(qgate)) @@ -959,7 +959,7 @@ static int nexthop_active_update(struct route_node *rn, struct route_entry *re, re->nexthop_active_num = 0; UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { /* No protocol daemon provides src and so we're skipping * tracking it */ prev_src = nexthop->rmap_src; @@ -1003,7 +1003,7 @@ int zebra_rib_labeled_unicast(struct route_entry *re) if (re->type != ZEBRA_ROUTE_BGP) return 0; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) + for (ALL_NEXTHOPS(re->ng, nexthop)) if (!nexthop->nh_label || !nexthop->nh_label->num_labels) return 0; @@ -1023,7 +1023,7 @@ void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p, switch (res) { case SOUTHBOUND_INSTALL_SUCCESS: dest->selected_fib = re; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1056,7 +1056,7 @@ void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p, */ if (dest->selected_fib == re) dest->selected_fib = NULL; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) + for (ALL_NEXTHOPS(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); zsend_route_notify_owner(re, p, ZAPI_ROUTE_REMOVED); @@ -1089,15 +1089,15 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode_prefixes(rn, &p, &src_p); if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS(re->nexthop, nexthop)) + for (ALL_NEXTHOPS(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } else { struct nexthop *prev; - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE); - for (ALL_NEXTHOPS(re->nexthop, prev)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_DUPLICATE); + for (ALL_NEXTHOPS(re->ng, prev)) { if (prev == nexthop) break; if (nexthop_same_firsthop(nexthop, prev)) { @@ -1138,7 +1138,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) srcdest_rnode_prefixes(rn, &p, &src_p); if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS(re->nexthop, nexthop)) + for (ALL_NEXTHOPS(re->ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } @@ -1388,7 +1388,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (!RIB_SYSTEM_ROUTE(old)) rib_uninstall_kernel(rn, old); } else { - for (nexthop = old->nexthop; nexthop; + for (nexthop = old->ng.nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); @@ -1444,7 +1444,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (!RIB_SYSTEM_ROUTE(new)) { bool in_fib = false; - for (ALL_NEXTHOPS(new->nexthop, nexthop)) + for (ALL_NEXTHOPS(new->ng, nexthop)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { in_fib = true; @@ -1676,13 +1676,16 @@ static void rib_process(struct route_node *rn) /* Redistribute SELECTED entry */ if (old_selected != new_selected || selected_changed) { - struct nexthop *nexthop; + struct nexthop *nexthop = NULL; /* Check if we have a FIB route for the destination, otherwise, * don't redistribute it */ - for (ALL_NEXTHOPS(new_fib ? new_fib->nexthop : NULL, nexthop)) { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { - break; + if (new_fib) { + for (ALL_NEXTHOPS(new_fib->ng, nexthop)) { + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB)) { + break; + } } } if (!nexthop) @@ -2116,9 +2119,9 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) /* free RE and nexthops */ if (re->type == ZEBRA_ROUTE_STATIC) - zebra_deregister_rnh_static_nexthops(re->vrf_id, re->nexthop, + zebra_deregister_rnh_static_nexthops(re->vrf_id, re->ng.nexthop, rn); - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); } @@ -2182,7 +2185,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", func, re->nexthop_num, re->nexthop_active_num); - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { inet_ntop(p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN); zlog_debug("%s: %s %s[%u] with flags %s%s%s", func, (nexthop->rparent ? " NH" : "NH"), straddr, @@ -2357,7 +2360,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* If this route is kernel route, set FIB flag to the route. */ if (RIB_SYSTEM_ROUTE(re)) - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); /* Link new re to node.*/ @@ -2443,7 +2446,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, continue; if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) continue; - if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->nexthop) + if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng.nexthop) && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { if (rtnh->ifindex != nh->ifindex) continue; @@ -2456,7 +2459,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, same = re; break; } - for (ALL_NEXTHOPS(re->nexthop, rtnh)) + for (ALL_NEXTHOPS(re->ng, rtnh)) if (nexthop_same_no_recurse(rtnh, nh)) { same = re; break; @@ -2493,7 +2496,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, } if (allow_delete) { /* Unset flags. */ - for (rtnh = fib->nexthop; rtnh; + for (rtnh = fib->ng.nexthop; rtnh; rtnh = rtnh->next) UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); @@ -2547,7 +2550,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; - for (ALL_NEXTHOPS(re->nexthop, tmp_nh)) { + for (ALL_NEXTHOPS(re->ng, tmp_nh)) { struct ipaddr vtep_ip; memset(&vtep_ip, 0, sizeof(struct ipaddr)); @@ -2642,7 +2645,7 @@ static void rib_update_table(struct route_table *table, continue; } - for (nh = re->nexthop; nh; nh = nh->next) + for (nh = re->ng.nexthop; nh; nh = nh->next) if (!(nh->type == NEXTHOP_TYPE_IPV4 || nh->type == NEXTHOP_TYPE_IPV6)) break; @@ -2759,7 +2762,7 @@ static void rib_sweep_table(struct route_table *table) * to a different spot (ie startup ) * this decision needs to be revisited */ - for (ALL_NEXTHOPS(re->nexthop, nexthop)) + for (ALL_NEXTHOPS(re->ng, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); rib_uninstall_kernel(rn, re); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 1e9fe875e1..dd3fe17702 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -355,7 +355,8 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn, rmap_family = (family == AF_INET) ? AFI_IP : AFI_IP6; if (prn && re) { - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng.nexthop; nexthop; + nexthop = nexthop->next) { ret = zebra_nht_route_map_check(rmap_family, proto, &prn->p, re, nexthop); if (ret != RMAP_DENYMATCH) { @@ -428,7 +429,7 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, int family, struct nexthop *nexthop; if (re && (rnh->state == NULL)) { - for (ALL_NEXTHOPS(re->nexthop, nexthop)) + for (ALL_NEXTHOPS(re->ng, nexthop)) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { state_changed = 1; break; @@ -559,7 +560,7 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family, * be having multiple. We care here only about * registered nexthops. */ - for (nexthop = sre->nexthop; nexthop; + for (nexthop = sre->ng.nexthop; nexthop; nexthop = nexthop->next) { switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: @@ -673,7 +674,7 @@ zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid, int family, if (re->type == ZEBRA_ROUTE_NHRP) { struct nexthop *nexthop; - for (nexthop = re->nexthop; nexthop; + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) if (nexthop->type == NEXTHOP_TYPE_IFINDEX) @@ -925,8 +926,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, return; /* free RE and nexthops */ - zebra_deregister_rnh_static_nexthops(vrf_id, re->nexthop, rn); - nexthops_free(re->nexthop); + zebra_deregister_rnh_static_nexthops(vrf_id, re->ng.nexthop, rn); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); } @@ -949,7 +950,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state->metric = re->metric; state->vrf_id = re->vrf_id; - route_entry_copy_nexthops(state, re->nexthop); + route_entry_copy_nexthops(state, re->ng.nexthop); rnh->state = state; } @@ -1022,7 +1023,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, num = 0; nump = stream_get_endp(s); stream_putc(s, 0); - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) if ((CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) || CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -1115,7 +1116,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) if (rnh->state) { vty_out(vty, " resolved via %s\n", zebra_route_string(rnh->state->type)); - for (nexthop = rnh->state->nexthop; nexthop; + for (nexthop = rnh->state->ng.nexthop; nexthop; nexthop = nexthop->next) print_nh(nexthop, vty); } else diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 48218effd1..3ab208d30b 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -285,8 +285,8 @@ static void check_replace(struct route_node *np2, struct route_entry *re2, return; } - if (in_addr_cmp((u_char *)&(*re)->nexthop->gate.ipv4, - (u_char *)&re2->nexthop->gate.ipv4) + if (in_addr_cmp((u_char *)&(*re)->ng.nexthop->gate.ipv4, + (u_char *)&re2->ng.nexthop->gate.ipv4) <= 0) return; @@ -370,9 +370,9 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], for (*np = route_top(table); *np; *np = route_next(*np)) { if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest)) { RNODE_FOREACH_RE (*np, *re) { - if (!in_addr_cmp((u_char *)&(*re) - ->nexthop->gate - .ipv4, + if (!in_addr_cmp( + (u_char *)&(*re) + ->ng.nexthop->gate.ipv4, (u_char *)&nexthop)) if (proto == proto_trans((*re)->type)) @@ -404,9 +404,10 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], if ((policy < policy2) || ((policy == policy2) && (proto < proto2)) || ((policy == policy2) && (proto == proto2) - && (in_addr_cmp((u_char *)&re2->nexthop - ->gate.ipv4, - (u_char *)&nexthop) + && (in_addr_cmp( + (u_char *)&re2->ng.nexthop + ->gate.ipv4, + (u_char *)&nexthop) >= 0))) check_replace(np2, re2, np, re); } @@ -430,7 +431,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], { struct nexthop *nexthop; - nexthop = (*re)->nexthop; + nexthop = (*re)->ng.nexthop; if (nexthop) { pnt = (u_char *)&nexthop->gate.ipv4; for (i = 0; i < 4; i++) @@ -459,7 +460,7 @@ static u_char *ipFwTable(struct variable *v, oid objid[], size_t *objid_len, if (!np) return NULL; - nexthop = re->nexthop; + nexthop = re->ng.nexthop; if (!nexthop) return NULL; diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index b4c5b70da0..f3921790a6 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -300,7 +300,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, } /* Lookup nexthop. */ - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) if (static_nexthop_same(nexthop, si)) break; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 582ff3110b..9fe3c707bb 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -743,7 +743,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, tm->tm_hour); vty_out(vty, " ago\n"); - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { char addrstr[32]; vty_out(vty, " %c%s", @@ -922,7 +922,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_string_add(json_route, "uptime", buf); - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { json_nexthop = json_object_new_object(); if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) @@ -1088,8 +1088,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, } /* Nexthop information. */ - for (ALL_NEXTHOPS(re->nexthop, nexthop)) { - if (nexthop == re->nexthop) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { + if (nexthop == re->ng.nexthop) { /* Prefix information. */ len = vty_out(vty, "%c", zebra_route_char(re->type)); if (re->instance) @@ -1842,7 +1842,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, * In case of ECMP, count only once. */ cnt = 0; - for (nexthop = re->nexthop; (!cnt && nexthop); + for (nexthop = re->ng.nexthop; (!cnt && nexthop); nexthop = nexthop->next) { cnt++; rib_cnt[ZEBRA_ROUTE_TOTAL]++; diff --git a/zebra/zserv.c b/zebra/zserv.c index d245e09724..0485aadde1 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -616,7 +616,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p, SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = re->nexthop_active_num; } - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -978,7 +978,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, * we * are looking up. Therefore, we will just iterate over the top * chain of nexthops. */ - for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) + for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) num += zsend_write_nexthop(s, nexthop); @@ -1236,7 +1236,7 @@ static int zread_route_add(struct zserv *client, u_short length, zlog_warn( "%s: Nexthops Specified: %d but we failed to properly create one", __PRETTY_FUNCTION__, api.nexthop_num); - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; } @@ -1268,7 +1268,7 @@ static int zread_route_add(struct zserv *client, u_short length, if (afi != AFI_IP6 && CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) { zlog_warn("%s: Received SRC Prefix but afi is not v6", __PRETTY_FUNCTION__); - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; } @@ -1437,7 +1437,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, zlog_warn( "%s: Please use ZEBRA_ROUTE_ADD if you want to pass v6 nexthops", __PRETTY_FUNCTION__); - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; break; @@ -1448,7 +1448,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, zlog_warn( "%s: Specified nexthop type: %d does not exist", __PRETTY_FUNCTION__, nexthop_type); - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; } @@ -1488,7 +1488,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, return 0; stream_failure: - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; } @@ -1654,7 +1654,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, zlog_warn( "%s: Please use ZEBRA_ROUTE_ADD if you want to pass non v6 nexthops", __PRETTY_FUNCTION__); - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; } @@ -1717,7 +1717,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, return 0; stream_failure: - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; } @@ -1850,7 +1850,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, zlog_warn( "%s: Please use ZEBRA_ROUTE_ADD if you want to pass non v6 nexthops", __PRETTY_FUNCTION__); - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; } @@ -1911,7 +1911,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, return 0; stream_failure: - nexthops_free(re->nexthop); + nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); return -1; From dba32923eb4198bb17e2cdbcd9e88c7decde81c4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 26 Jan 2018 10:59:15 -0500 Subject: [PATCH 04/11] lib, vtysh: Start cli for nexthop-group Signed-off-by: Donald Sharp --- lib/command.c | 3 +++ lib/command.h | 1 + lib/nexthop_group.c | 34 ++++++++++++++++++++++++++++++++++ lib/nexthop_group.h | 2 ++ lib/subdir.am | 2 ++ vtysh/vtysh.c | 1 + 6 files changed, 43 insertions(+) diff --git a/lib/command.c b/lib/command.c index 6d04ad83c0..5697c1d812 100644 --- a/lib/command.c +++ b/lib/command.c @@ -65,6 +65,7 @@ const char *node_names[] = { "logical-router", // LOGICALROUTER_NODE, "vrf", // VRF_NODE, "interface", // INTERFACE_NODE, + "nexthop-group", // NH_GROUP_NODE, "zebra", // ZEBRA_NODE, "table", // TABLE_NODE, "rip", // RIP_NODE, @@ -1294,6 +1295,7 @@ void cmd_exit(struct vty *vty) case PW_NODE: case LOGICALROUTER_NODE: case VRF_NODE: + case NH_GROUP_NODE: case ZEBRA_NODE: case BGP_NODE: case RIP_NODE: @@ -1379,6 +1381,7 @@ DEFUN (config_end, case PW_NODE: case LOGICALROUTER_NODE: case VRF_NODE: + case NH_GROUP_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: diff --git a/lib/command.h b/lib/command.h index 56e70abf6f..0febf903a3 100644 --- a/lib/command.h +++ b/lib/command.h @@ -88,6 +88,7 @@ enum node_type { LOGICALROUTER_NODE, /* Logical-Router node. */ VRF_NODE, /* VRF mode node. */ INTERFACE_NODE, /* Interface mode node. */ + NH_GROUP_NODE, /* Nexthop-Group mode node. */ ZEBRA_NODE, /* zebra connection node. */ TABLE_NODE, /* rtm_table selection node. */ RIP_NODE, /* RIP protocol mode node. */ diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 8bdc585405..e7f10487d1 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -21,6 +21,12 @@ #include #include +#include +#include + +#ifndef VTYSH_EXTRACT_PL +#include "lib/nexthop_group_clippy.c" +#endif /* Add nexthop to the end of a nexthop list. */ void nexthop_add(struct nexthop **target, struct nexthop *nexthop) @@ -64,3 +70,31 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, nexthop); } } + +DEFPY (nexthop_group, + nexthop_group_cmd, + "nexthop-group NAME", + "Enter into the nexthop-group submode\n" + "Specify the NAME of the nexthop-group\n") +{ + return CMD_SUCCESS; +} + +struct cmd_node nexthop_group_node = { + NH_GROUP_NODE, + "%s(config-nh-group)# ", + 1 +}; + +static int nexthop_group_write(struct vty *vty) +{ + vty_out(vty, "!\n"); + + return 1; +} + +void nexthop_group_init(void) +{ + install_node(&nexthop_group_node, nexthop_group_write); + install_element(CONFIG_NODE, &nexthop_group_cmd); +} diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 26900959cc..561fe96425 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -33,6 +33,8 @@ struct nexthop_group { struct nexthop *nexthop; }; +void nexthop_group_init(void); + void nexthop_add(struct nexthop **target, struct nexthop *nexthop); void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, struct nexthop *rparent); diff --git a/lib/subdir.am b/lib/subdir.am index 5001b3cecf..7d85b7a24d 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -82,6 +82,8 @@ lib_libfrr_la_SOURCES = \ lib/plist_clippy.c: $(CLIPPY_DEPS) lib/plist.lo: lib/plist_clippy.c +lib/nexthop_group_clippy.c: $(CLIPPY_DEPS) +lib/nexthop_group.lo: lib/nexthop_group_clippy.c pkginclude_HEADERS += \ lib/bfd.h \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 5f87d4c7f5..7dfe7753cf 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1499,6 +1499,7 @@ static int vtysh_exit(struct vty *vty) case PW_NODE: case LOGICALROUTER_NODE: case VRF_NODE: + case NH_GROUP_NODE: case ZEBRA_NODE: case BGP_NODE: case RIP_NODE: From 942bf97b13223ac5645f613a2f00ab18f3716c59 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 4 Feb 2018 12:33:33 +0000 Subject: [PATCH 05/11] *: PBR - netlink interaction and basic definitions Implement netlink interactions for Policy Based Routing. This includes APIs to install and uninstall rules and handle notifications from the kernel related to rule addition or deletion. Various definitions are added to facilitate this. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp --- include/linux/fib_rules.h | 74 +++++++++++ include/subdir.am | 1 + zebra/kernel_netlink.c | 19 +-- zebra/rtread_getmsg.c | 4 + zebra/rtread_netlink.c | 7 + zebra/rtread_sysctl.c | 5 + zebra/rule_netlink.c | 273 ++++++++++++++++++++++++++++++++++++++ zebra/rule_netlink.h | 42 ++++++ zebra/rule_socket.c | 51 +++++++ zebra/subdir.am | 5 + zebra/zebra_ns.h | 1 + zebra/zebra_pbr.c | 54 ++++++++ zebra/zebra_pbr.h | 128 ++++++++++++++++++ 13 files changed, 655 insertions(+), 9 deletions(-) create mode 100644 include/linux/fib_rules.h create mode 100644 zebra/rule_netlink.c create mode 100644 zebra/rule_netlink.h create mode 100644 zebra/rule_socket.c create mode 100644 zebra/zebra_pbr.c create mode 100644 zebra/zebra_pbr.h diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h new file mode 100644 index 0000000000..bc6688012c --- /dev/null +++ b/include/linux/fib_rules.h @@ -0,0 +1,74 @@ +#ifndef __LINUX_FIB_RULES_H +#define __LINUX_FIB_RULES_H + +#include +#include + +/* rule is permanent, and cannot be deleted */ +#define FIB_RULE_PERMANENT 0x00000001 +#define FIB_RULE_INVERT 0x00000002 +#define FIB_RULE_UNRESOLVED 0x00000004 +#define FIB_RULE_IIF_DETACHED 0x00000008 +#define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED +#define FIB_RULE_OIF_DETACHED 0x00000010 + +/* try to find source address in routing lookups */ +#define FIB_RULE_FIND_SADDR 0x00010000 + +struct fib_rule_hdr { + __u8 family; + __u8 dst_len; + __u8 src_len; + __u8 tos; + + __u8 table; + __u8 res1; /* reserved */ + __u8 res2; /* reserved */ + __u8 action; + + __u32 flags; +}; + +enum { + FRA_UNSPEC, + FRA_DST, /* destination address */ + FRA_SRC, /* source address */ + FRA_IIFNAME, /* interface name */ +#define FRA_IFNAME FRA_IIFNAME + FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */ + FRA_UNUSED2, + FRA_PRIORITY, /* priority/preference */ + FRA_UNUSED3, + FRA_UNUSED4, + FRA_UNUSED5, + FRA_FWMARK, /* mark */ + FRA_FLOW, /* flow/class id */ + FRA_UNUSED6, + FRA_SUPPRESS_IFGROUP, + FRA_SUPPRESS_PREFIXLEN, + FRA_TABLE, /* Extended table id */ + FRA_FWMASK, /* mask for netfilter mark */ + FRA_OIFNAME, + FRA_PAD, + FRA_L3MDEV, /* iif or oif is l3mdev goto its table */ + __FRA_MAX +}; + +#define FRA_MAX (__FRA_MAX - 1) + +enum { + FR_ACT_UNSPEC, + FR_ACT_TO_TBL, /* Pass to fixed table */ + FR_ACT_GOTO, /* Jump to another rule */ + FR_ACT_NOP, /* No operation */ + FR_ACT_RES3, + FR_ACT_RES4, + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ + __FR_ACT_MAX, +}; + +#define FR_ACT_MAX (__FR_ACT_MAX - 1) + +#endif diff --git a/include/subdir.am b/include/subdir.am index 7a12b2ffae..db5ed06c61 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -7,4 +7,5 @@ noinst_HEADERS += \ include/linux/rtnetlink.h \ include/linux/socket.h \ include/linux/net_namespace.h \ + include/linux/fib_rules.h \ # end diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 0b3b6eed45..52b2692090 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -45,6 +45,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" +#include "zebra/rule_netlink.h" #ifndef SO_RCVBUFFORCE #define SO_RCVBUFFORCE (33) @@ -85,6 +86,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_NEWNEIGH, "RTM_NEWNEIGH"}, {RTM_DELNEIGH, "RTM_DELNEIGH"}, {RTM_GETNEIGH, "RTM_GETNEIGH"}, + {RTM_NEWRULE, "RTM_NEWRULE"}, + {RTM_DELRULE, "RTM_DELRULE"}, + {RTM_GETRULE, "RTM_GETRULE"}, {0}}; static const struct message rtproto_str[] = { @@ -240,28 +244,24 @@ static int netlink_information_fetch(struct sockaddr_nl *snl, switch (h->nlmsg_type) { case RTM_NEWROUTE: return netlink_route_change(snl, h, ns_id, startup); - break; case RTM_DELROUTE: return netlink_route_change(snl, h, ns_id, startup); - break; case RTM_NEWLINK: return netlink_link_change(snl, h, ns_id, startup); - break; case RTM_DELLINK: return netlink_link_change(snl, h, ns_id, startup); - break; case RTM_NEWADDR: return netlink_interface_addr(snl, h, ns_id, startup); - break; case RTM_DELADDR: return netlink_interface_addr(snl, h, ns_id, startup); - break; case RTM_NEWNEIGH: return netlink_neigh_change(snl, h, ns_id); - break; case RTM_DELNEIGH: return netlink_neigh_change(snl, h, ns_id); - break; + case RTM_NEWRULE: + return netlink_rule_change(snl, h, ns_id, startup); + case RTM_DELRULE: + return netlink_rule_change(snl, h, ns_id, startup); default: if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Unknown netlink nlmsg_type %d vrf %u\n", @@ -788,7 +788,8 @@ void kernel_init(struct zebra_ns *zns) /* Initialize netlink sockets */ groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_MROUTE - | RTMGRP_NEIGH; + | RTMGRP_NEIGH + | RTNLGRP_IPV4_RULE | RTNLGRP_IPV6_RULE; snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 95bc8db1c9..38321bc416 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -263,4 +263,8 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void kernel_read_pbr_rules(struct zebra_ns *zns) +{ +} + #endif /* SUNOS_5 */ diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index ec29d1820e..e992046078 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -25,7 +25,9 @@ #include "vty.h" #include "zebra/rt.h" +#include "zebra/zebra_pbr.h" #include "zebra/rt_netlink.h" +#include "zebra/rule_netlink.h" void route_read(struct zebra_ns *zns) { @@ -53,4 +55,9 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) netlink_neigh_read_for_vlan(zns, vlan_if); } +void kernel_read_pbr_rules(struct zebra_ns *zns) +{ + netlink_rules_read(zns); +} + #endif /* GNU_LINUX */ diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index 4f5a80612e..fba67e3d0c 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -30,6 +30,7 @@ #include "zebra/rt.h" #include "zebra/kernel_socket.h" +#include "zebra/zebra_pbr.h" /* Kernel routing table read up by sysctl function. */ void route_read(struct zebra_ns *zns) @@ -92,4 +93,8 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void kernel_read_pbr_rules(struct zebra_ns *zns) +{ +} + #endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */ diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c new file mode 100644 index 0000000000..4b8791ee2f --- /dev/null +++ b/zebra/rule_netlink.c @@ -0,0 +1,273 @@ +/* + * Zebra Policy Based Routing (PBR) interaction with the kernel using + * netlink. + * Copyright (C) 2018 Cumulus Networks, Inc. + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifdef HAVE_NETLINK + +#include "if.h" +#include "prefix.h" +#include "vrf.h" + +#include +#include "zebra/zserv.h" +#include "zebra/zebra_ns.h" +#include "zebra/zebra_vrf.h" +#include "zebra/rt.h" +#include "zebra/interface.h" +#include "zebra/debug.h" +#include "zebra/rtadv.h" +#include "zebra/kernel_netlink.h" +#include "zebra/rule_netlink.h" +#include "zebra/zebra_pbr.h" + +/* definitions */ + +/* static function declarations */ + +/* Private functions */ + +/* Install or uninstall specified rule for a specific interface. + * Form netlink message and ship it. Currently, notify status after + * waiting for netlink status. + */ +static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, + struct interface *ifp, u_int32_t rule_pri) +{ + int family; + int bytelen; + struct { + struct nlmsghdr n; + struct fib_rule_hdr frh; + char buf[NL_PKT_BUF_SIZE]; + } req; + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct sockaddr_nl snl; + char buf1[PREFIX_STRLEN]; + char buf2[PREFIX_STRLEN]; + + memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE); + family = PREFIX_FAMILY(&rule->filter.src_ip); + bytelen = (family == AF_INET ? 4 : 16); + + req.n.nlmsg_type = cmd; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + + req.frh.family = family; + req.frh.action = FR_ACT_TO_TBL; + + if (cmd == RTM_NEWRULE) + req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + + /* rule's pref # */ + addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule_pri); + + /* interface on which applied */ + 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)) { + req.frh.src_len = rule->filter.src_ip.prefixlen; + addattr_l(&req.n, sizeof(req), FRA_SRC, + &rule->filter.src_ip.u.prefix, bytelen); + } + /* destination IP, if specified */ + if (IS_RULE_FILTERING_ON_DST_IP(rule)) { + req.frh.dst_len = rule->filter.dst_ip.prefixlen; + addattr_l(&req.n, sizeof(req), FRA_DST, + &rule->filter.dst_ip.u.prefix, bytelen); + } + + /* Route table to use to forward, if filter criteria matches. */ + if (rule->action.table < 256) + req.frh.table = rule->action.table; + else { + req.frh.table = RT_TABLE_UNSPEC; + addattr32(&req.n, sizeof(req), FRA_TABLE, + rule->action.table); + } + + if (IS_ZEBRA_DEBUG_KERNEL) + 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_pri, + prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)), + prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)), + rule->action.table); + + /* Ship off the message. + * Note: Currently, netlink_talk() is a blocking call which returns + * back the status. + */ + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + return netlink_talk(netlink_talk_filter, &req.n, + &zns->netlink_cmd, zns, 0); +} + + +/* Public functions */ +/* + * Install specified rule for a specific interface. The preference is what + * goes in the rule to denote relative ordering; it may or may not be the + * same as the rule's user-defined sequence number. + */ +void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, + struct interface *ifp, u_int32_t rule_pri) +{ + int ret = 0; + + ret = netlink_rule_update(RTM_NEWRULE, rule, ifp, rule_pri); + kernel_pbr_rule_add_del_status(rule, ifp, rule_pri, + (!ret) ? + SOUTHBOUND_INSTALL_SUCCESS : + SOUTHBOUND_INSTALL_FAILURE); +} + +/* + * Uninstall specified rule for a specific interface. + */ +void kernel_del_pbr_rule(struct zebra_pbr_rule *rule, + struct interface *ifp, u_int32_t rule_pri) +{ + int ret = 0; + + ret = netlink_rule_update(RTM_DELRULE, rule, ifp, rule_pri); + kernel_pbr_rule_add_del_status(rule, ifp, rule_pri, + (!ret) ? + SOUTHBOUND_DELETE_SUCCESS : + SOUTHBOUND_DELETE_FAILURE); +} + +/* + * Handle netlink notification informing a rule add or delete. + * Handling of an ADD is TBD. + * DELs are notified up, if other attributes indicate it may be a + * notification of interest. The expectation is that if this corresponds + * to a PBR rule added by FRR, it will be readded. + */ +int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id, int startup) +{ + struct zebra_ns *zns; + struct fib_rule_hdr *frh; + struct rtattr *tb[FRA_MAX + 1]; + int len; + char *ifname; + struct interface *ifp; + u_int32_t rule_pri = 0; + struct zebra_pbr_rule rule; + char buf1[PREFIX_STRLEN]; + char buf2[PREFIX_STRLEN]; + + /* Basic validation followed by extracting attributes. */ + if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE) + return 0; + + /* TBD */ + if (h->nlmsg_type == RTM_NEWRULE) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr)); + if (len < 0) + return -1; + + frh = NLMSG_DATA(h); + if (frh->family != AF_INET && frh->family != AF_INET6) + return 0; + if (frh->action != FR_ACT_TO_TBL) + return 0; + + memset(tb, 0, sizeof(tb)); + netlink_parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len); + + /* TBD: We don't care about rules not specifying an IIF. */ + if (tb[FRA_IFNAME] == NULL) + return 0; + + /* If we don't know the interface, we don't care. */ + ifname = (char *)RTA_DATA(tb[FRA_IFNAME]); + zns = zebra_ns_lookup(ns_id); + ifp = if_lookup_by_name_per_ns(zns, ifname); + if (!ifp) + return 0; + + memset(&rule, 0, sizeof(rule)); + if (tb[FRA_PRIORITY]) + rule_pri = *(u_int32_t *)RTA_DATA(tb[FRA_PRIORITY]); + + if (tb[FRA_SRC]) { + if (frh->family == AF_INET) + memcpy(&rule.filter.src_ip.u.prefix4, + RTA_DATA(tb[FRA_SRC]), 4); + else + memcpy(&rule.filter.src_ip.u.prefix6, + RTA_DATA(tb[FRA_SRC]), 16); + rule.filter.src_ip.prefixlen = frh->src_len; + rule.filter.filter_bm |= PBR_FILTER_SRC_IP; + } + + if (tb[FRA_DST]) { + if (frh->family == AF_INET) + memcpy(&rule.filter.dst_ip.u.prefix4, + RTA_DATA(tb[FRA_DST]), 4); + else + memcpy(&rule.filter.dst_ip.u.prefix6, + RTA_DATA(tb[FRA_DST]), 16); + rule.filter.dst_ip.prefixlen = frh->dst_len; + rule.filter.filter_bm |= PBR_FILTER_DST_IP; + } + + if (tb[FRA_TABLE]) + rule.action.table = *(u_int32_t *)RTA_DATA(tb[FRA_TABLE]); + else + rule.action.table = frh->table; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Rx %s family %s IF %s(%u) Pref %u Src %s " + "Dst %s Table %u", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(frh->family), + ifp->name, ifp->ifindex, rule_pri, + prefix2str(&rule.filter.src_ip, buf1, sizeof(buf1)), + prefix2str(&rule.filter.dst_ip, buf2, sizeof(buf2)), + rule.action.table); + + return kernel_pbr_rule_del(&rule, ifp, rule_pri); +} + +/* + * Get to know existing PBR rules in the kernel - typically called at startup. + * TBD. + */ +int netlink_rules_read(struct zebra_ns *zns) +{ + return 0; +} + +#endif /* HAVE_NETLINK */ diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h new file mode 100644 index 0000000000..034068b899 --- /dev/null +++ b/zebra/rule_netlink.h @@ -0,0 +1,42 @@ +/* + * Zebra Policy Based Routing (PBR) interaction with the kernel using + * netlink - public definitions and function declarations. + * Copyright (C) 2018 Cumulus Networks, Inc. + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_RULE_NETLINK_H +#define _ZEBRA_RULE_NETLINK_H + +#ifdef HAVE_NETLINK + +/* + * Handle netlink notification informing a rule add or delete. + */ +extern int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id, int startup); + +/* + * Get to know existing PBR rules in the kernel - typically called at startup. + */ +extern int netlink_rules_read(struct zebra_ns *zns); + +#endif /* HAVE_NETLINK */ + +#endif /* _ZEBRA_RULE_NETLINK_H */ diff --git a/zebra/rule_socket.c b/zebra/rule_socket.c new file mode 100644 index 0000000000..46c53f9e02 --- /dev/null +++ b/zebra/rule_socket.c @@ -0,0 +1,51 @@ +/* + * Zebra Policy Based Routing (PBR) interaction with the kernel using + * netlink. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#ifndef HAVE_NETLINK + +#include "if.h" +#include "prefix.h" +#include "vrf.h" + +#include "zebra/zserv.h" +#include "zebra/zebra_ns.h" +#include "zebra/zebra_vrf.h" +#include "zebra/rt.h" +#include "zebra/interface.h" +#include "zebra/debug.h" +#include "zebra/rtadv.h" +#include "zebra/kernel_netlink.h" +#include "zebra/rule_netlink.h" +#include "zebra/zebra_pbr.h" + +void kernel_add_pbr_rule(struct zebra_pbr_rule *rule) +{ +} +void kernel_del_pbr_rule(struct zebra_pbr_rule *rule) +{ +} + +#endif diff --git a/zebra/subdir.am b/zebra/subdir.am index bb7439c0f6..ef157b7539 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -45,6 +45,8 @@ zebra_zebra_SOURCES = \ zebra/rtread_getmsg.c \ zebra/rtread_netlink.c \ zebra/rtread_sysctl.c \ + zebra/rule_netlink.c \ + zebra/rule_socket.c \ zebra/zebra_l2.c \ zebra/zebra_memory.c \ zebra/zebra_mpls.c \ @@ -54,6 +56,7 @@ zebra_zebra_SOURCES = \ zebra/zebra_mpls_vty.c \ zebra/zebra_mroute.c \ zebra/zebra_ns.c \ + zebra/zebra_pbr.c \ zebra/zebra_ptm.c \ zebra/zebra_ptm_redistribute.c \ zebra/zebra_pw.c \ @@ -90,12 +93,14 @@ noinst_HEADERS += \ zebra/rt.h \ zebra/rt_netlink.h \ zebra/rtadv.h \ + zebra/rule_netlink.h \ zebra/zebra_fpm_private.h \ zebra/zebra_l2.h \ zebra/zebra_memory.h \ zebra/zebra_mpls.h \ zebra/zebra_mroute.h \ zebra/zebra_ns.h \ + zebra/zebra_pbr.h \ zebra/zebra_ptm.h \ zebra/zebra_ptm_redistribute.h \ zebra/zebra_pw.h \ diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 3a998a49ff..1d7b6f725e 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -23,6 +23,7 @@ #define __ZEBRA_NS_H__ #include +#include #ifdef HAVE_NETLINK /* Socket interface to kernel */ diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c new file mode 100644 index 0000000000..6e521be39e --- /dev/null +++ b/zebra/zebra_pbr.c @@ -0,0 +1,54 @@ +/* Zebra Policy Based Routing (PBR) main handling. + * Copyright (C) 2018 Cumulus Networks, Inc. + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "zebra/zebra_pbr.h" +#include "zebra/rt.h" + +/* definitions */ + +/* static function declarations */ + +/* Private functions */ + +/* Public functions */ +/* + * Handle success or failure of rule (un)install in the kernel. + */ +void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, + struct interface *ifp, + u_int32_t rule_pri, + enum southbound_results res) +{ +} + +/* + * Handle rule delete notification from kernel. + */ +int kernel_pbr_rule_del(struct zebra_pbr_rule *rule, + struct interface *ifp, + u_int32_t rule_pri) +{ + return 0; +} + + diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h new file mode 100644 index 0000000000..2e80aeb8a3 --- /dev/null +++ b/zebra/zebra_pbr.h @@ -0,0 +1,128 @@ +/* + * Zebra Policy Based Routing (PBR) Data structures and definitions + * These are public definitions referenced by multiple files. + * Copyright (C) 2018 Cumulus Networks, Inc. + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_PBR_H +#define _ZEBRA_PBR_H + +#include + +#include "prefix.h" +#include "if.h" +#include "rt.h" + +/* + * A PBR filter + * + * The filter or match criteria in a PBR rule. + * For simplicity, all supported filters are grouped into a structure rather + * than delineating further. A bitmask denotes which filters are actually + * specified. + */ +struct zebra_pbr_filter { + u_int32_t filter_bm; +#define PBR_FILTER_SRC_IP (1 << 0) +#define PBR_FILTER_DST_IP (1 << 1) +#define PBR_FILTER_SRC_PORT (1 << 2) +#define PBR_FILTER_DST_PORT (1 << 3) + + /* Source and Destination IP address with masks. */ + struct prefix src_ip; + struct prefix dst_ip; + + /* Source and Destination higher-layer (TCP/UDP) port numbers. */ + u_int16_t src_port; + u_int16_t dst_port; +}; + +#define IS_RULE_FILTERING_ON_SRC_IP(r) \ + (r->filter.filter_bm & PBR_FILTER_SRC_IP) +#define IS_RULE_FILTERING_ON_DST_IP(r) \ + (r->filter.filter_bm & PBR_FILTER_DST_IP) +#define IS_RULE_FILTERING_ON_SRC_PORT(r) \ + (r->filter.filter_bm & PBR_FILTER_SRC_PORT) +#define IS_RULE_FILTERING_ON_DST_PORT(r) \ + (r->filter.filter_bm & PBR_FILTER_DST_PORT) + +/* + * A PBR action + * + * The action corresponding to a PBR rule. + * While the user specifies the action in a particular way, the forwarding + * plane implementation (Linux only) requires that to be encoded into a + * route table and the rule then point to that route table; in some cases, + * the user criteria may directly point to a table too. + */ +struct zebra_pbr_action { + u_int32_t table; +}; + +/* + * A PBR rule + * + * This is a combination of the filter criteria and corresponding action. + * Rules also have a user-defined sequence number which defines the relative + * order amongst rules. + */ +struct zebra_pbr_rule { + u_int32_t seq; + struct zebra_pbr_filter filter; + struct zebra_pbr_action action; +}; + + +/* + * Install specified rule for a specific interface. + * It is possible that the user-defined sequence number and the one in the + * forwarding plane may not coincide, hence the API requires a separate + * rule priority - maps to preference/FRA_PRIORITY on Linux. + */ +extern void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, + struct interface *ifp, u_int32_t rule_pri); + +/* + * Uninstall specified rule for a specific interface. + */ +extern void kernel_del_pbr_rule(struct zebra_pbr_rule *rule, + struct interface *ifp, u_int32_t rule_pri); + +/* + * Get to know existing PBR rules in the kernel - typically called at startup. + */ +extern void kernel_read_pbr_rules(struct zebra_ns *zns); + +/* + * Handle success or failure of rule (un)install in the kernel. + */ +extern void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, + struct interface *ifp, + u_int32_t rule_pri, + enum southbound_results res); + +/* + * Handle rule delete notification from kernel. + */ +extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule, + struct interface *ifp, + u_int32_t rule_pri); + +#endif /* _ZEBRA_PBR_H */ From e16abbb303a4b2ce8d0959729a2c43dcf49ee44c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 14 Feb 2018 19:52:01 -0500 Subject: [PATCH 06/11] lib, zebra: Add rule encoding Add some code to pass the rule we want installed into the kernel. Signed-off-by: Donald Sharp --- lib/log.c | 3 +++ lib/zclient.h | 3 +++ zebra/zserv.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/lib/log.c b/lib/log.c index 6330c53702..9e33ef9102 100644 --- a/lib/log.c +++ b/lib/log.c @@ -961,6 +961,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_PW_SET), DESC_ENTRY(ZEBRA_PW_UNSET), DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE), + DESC_ENTRY(ZEBRA_RULE_ADD), + DESC_ENTRY(ZEBRA_RULE_DELETE), + DESC_ENTRY(ZEBRA_RULE_NOTIFY_OWNER), }; #undef DESC_ENTRY diff --git a/lib/zclient.h b/lib/zclient.h index 39566b1739..a315a7ed5a 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -129,6 +129,9 @@ typedef enum { ZEBRA_PW_SET, ZEBRA_PW_UNSET, ZEBRA_PW_STATUS_UPDATE, + ZEBRA_RULE_ADD, + ZEBRA_RULE_DELETE, + ZEBRA_RULE_NOTIFY_OWNER, } zebra_message_types_t; struct redist_proto { diff --git a/zebra/zserv.c b/zebra/zserv.c index 0485aadde1..13936e5366 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -60,6 +60,7 @@ #include "zebra/label_manager.h" #include "zebra/zebra_vxlan.h" #include "zebra/rt.h" +#include "zebra/zebra_pbr.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -2587,6 +2588,62 @@ stream_failure: return; } +static inline void zread_rule(uint16_t command, struct zserv *client, + uint16_t length, struct zebra_vrf *zvrf) +{ + struct zebra_pbr_rule zpr; + struct interface *ifp; + struct stream *s; + uint32_t total, i; + uint32_t priority; + ifindex_t ifindex; + + s = client->ibuf; + STREAM_GETL(s, total); + + for (i = 0; i < total; i++) { + memset(&zpr, 0, sizeof(zpr)); + + STREAM_GETL(s, zpr.seq); + STREAM_GETL(s, priority); + STREAM_GETC(s, zpr.filter.src_ip.family); + STREAM_GETC(s, zpr.filter.src_ip.prefixlen); + STREAM_GET(&zpr.filter.src_ip.u.prefix, s, + prefix_blen(&zpr.filter.src_ip)); + STREAM_GETW(s, zpr.filter.src_port); + STREAM_GETC(s, zpr.filter.dst_ip.family); + STREAM_GETC(s, zpr.filter.dst_ip.prefixlen); + STREAM_GET(&zpr.filter.dst_ip.u.prefix, s, + prefix_blen(&zpr.filter.dst_ip)); + STREAM_GETW(s, zpr.filter.dst_port); + STREAM_GETL(s, zpr.action.table); + STREAM_GETL(s, ifindex); + + ifp = if_lookup_by_index(ifindex, VRF_UNKNOWN); + if (!ifp) { + zlog_debug("FAiled to lookup ifindex: %u", ifindex); + return; + } + + if (!is_default_prefix(&zpr.filter.src_ip)) + zpr.filter.filter_bm |= PBR_FILTER_SRC_IP; + + if (!is_default_prefix(&zpr.filter.dst_ip)) + zpr.filter.filter_bm |= PBR_FILTER_DST_IP; + + if (zpr.filter.src_port) + zpr.filter.filter_bm |= PBR_FILTER_SRC_PORT; + + if (zpr.filter.dst_port) + zpr.filter.filter_bm |= PBR_FILTER_DST_PORT; + + kernel_add_pbr_rule(&zpr, ifp, priority); + } + +stream_failure: + return; +} + static inline void zserv_handle_commands(struct zserv *client, uint16_t command, uint16_t length, struct zebra_vrf *zvrf) @@ -2731,6 +2788,10 @@ static inline void zserv_handle_commands(struct zserv *client, uint16_t command, case ZEBRA_PW_UNSET: zread_pseudowire(command, client, length, zvrf); break; + case ZEBRA_RULE_ADD: + case ZEBRA_RULE_DELETE: + zread_rule(command, client, length, zvrf); + break; default: zlog_info("Zebra received unknown command %d", command); break; From fd71d73eb307096d9f14804fdac9123742d868b1 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 15 Feb 2018 19:55:56 -0500 Subject: [PATCH 07/11] zebra: Cleanup a couple of api issues 1) use uint32_t instead of u_int32_t as we are supposed to 2) Consolidate priority into the rule. 3) Cleanup the api from this. Signed-off-by: Donald Sharp --- zebra/rule_netlink.c | 68 ++++++++++++++++++++------------------------ zebra/rule_netlink.h | 2 +- zebra/zebra_pbr.c | 5 +--- zebra/zebra_pbr.h | 19 ++++++------- zebra/zserv.c | 5 ++-- 5 files changed, 44 insertions(+), 55 deletions(-) diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 4b8791ee2f..3228d0e4bd 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -52,7 +52,7 @@ * waiting for netlink status. */ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, - struct interface *ifp, u_int32_t rule_pri) + struct interface *ifp) { int family; int bytelen; @@ -66,7 +66,7 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; - memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE); + memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE); family = PREFIX_FAMILY(&rule->filter.src_ip); bytelen = (family == AF_INET ? 4 : 16); @@ -82,7 +82,7 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; /* rule's pref # */ - addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule_pri); + addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->priority); /* interface on which applied */ addattr_l(&req.n, sizeof(req), FRA_IFNAME, ifp->name, @@ -111,14 +111,13 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, } if (IS_ZEBRA_DEBUG_KERNEL) - 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_pri, - prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)), - prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)), - rule->action.table); + 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, + prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)), + prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)), + rule->action.table); /* Ship off the message. * Note: Currently, netlink_talk() is a blocking call which returns @@ -137,31 +136,27 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, * goes in the rule to denote relative ordering; it may or may not be the * same as the rule's user-defined sequence number. */ -void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, - struct interface *ifp, u_int32_t rule_pri) +void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, struct interface *ifp) { int ret = 0; - ret = netlink_rule_update(RTM_NEWRULE, rule, ifp, rule_pri); - kernel_pbr_rule_add_del_status(rule, ifp, rule_pri, - (!ret) ? - SOUTHBOUND_INSTALL_SUCCESS : - SOUTHBOUND_INSTALL_FAILURE); + ret = netlink_rule_update(RTM_NEWRULE, rule, ifp); + kernel_pbr_rule_add_del_status(rule, ifp, + (!ret) ? SOUTHBOUND_INSTALL_SUCCESS + : SOUTHBOUND_INSTALL_FAILURE); } /* * Uninstall specified rule for a specific interface. */ -void kernel_del_pbr_rule(struct zebra_pbr_rule *rule, - struct interface *ifp, u_int32_t rule_pri) +void kernel_del_pbr_rule(struct zebra_pbr_rule *rule, struct interface *ifp) { int ret = 0; - ret = netlink_rule_update(RTM_DELRULE, rule, ifp, rule_pri); - kernel_pbr_rule_add_del_status(rule, ifp, rule_pri, - (!ret) ? - SOUTHBOUND_DELETE_SUCCESS : - SOUTHBOUND_DELETE_FAILURE); + ret = netlink_rule_update(RTM_DELRULE, rule, ifp); + kernel_pbr_rule_add_del_status(rule, ifp, + (!ret) ? SOUTHBOUND_DELETE_SUCCESS + : SOUTHBOUND_DELETE_FAILURE); } /* @@ -180,7 +175,6 @@ int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, int len; char *ifname; struct interface *ifp; - u_int32_t rule_pri = 0; struct zebra_pbr_rule rule; char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; @@ -219,7 +213,7 @@ int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, memset(&rule, 0, sizeof(rule)); if (tb[FRA_PRIORITY]) - rule_pri = *(u_int32_t *)RTA_DATA(tb[FRA_PRIORITY]); + rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]); if (tb[FRA_SRC]) { if (frh->family == AF_INET) @@ -244,21 +238,21 @@ int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, } if (tb[FRA_TABLE]) - rule.action.table = *(u_int32_t *)RTA_DATA(tb[FRA_TABLE]); + rule.action.table = *(uint32_t *)RTA_DATA(tb[FRA_TABLE]); else rule.action.table = frh->table; if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Rx %s family %s IF %s(%u) Pref %u Src %s " - "Dst %s Table %u", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(frh->family), - ifp->name, ifp->ifindex, rule_pri, - prefix2str(&rule.filter.src_ip, buf1, sizeof(buf1)), - prefix2str(&rule.filter.dst_ip, buf2, sizeof(buf2)), - rule.action.table); + zlog_debug( + "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(frh->family), ifp->name, ifp->ifindex, + rule.priority, + prefix2str(&rule.filter.src_ip, buf1, sizeof(buf1)), + prefix2str(&rule.filter.dst_ip, buf2, sizeof(buf2)), + rule.action.table); - return kernel_pbr_rule_del(&rule, ifp, rule_pri); + return kernel_pbr_rule_del(&rule, ifp); } /* diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h index 034068b899..3a9b51309e 100644 --- a/zebra/rule_netlink.h +++ b/zebra/rule_netlink.h @@ -1,4 +1,4 @@ -/* +/* * Zebra Policy Based Routing (PBR) interaction with the kernel using * netlink - public definitions and function declarations. * Copyright (C) 2018 Cumulus Networks, Inc. diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 6e521be39e..827005b3a1 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -36,7 +36,6 @@ */ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, struct interface *ifp, - u_int32_t rule_pri, enum southbound_results res) { } @@ -44,9 +43,7 @@ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, /* * Handle rule delete notification from kernel. */ -int kernel_pbr_rule_del(struct zebra_pbr_rule *rule, - struct interface *ifp, - u_int32_t rule_pri) +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 2e80aeb8a3..b87388afc5 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -39,7 +39,7 @@ * specified. */ struct zebra_pbr_filter { - u_int32_t filter_bm; + uint32_t filter_bm; #define PBR_FILTER_SRC_IP (1 << 0) #define PBR_FILTER_DST_IP (1 << 1) #define PBR_FILTER_SRC_PORT (1 << 2) @@ -50,8 +50,8 @@ struct zebra_pbr_filter { struct prefix dst_ip; /* Source and Destination higher-layer (TCP/UDP) port numbers. */ - u_int16_t src_port; - u_int16_t dst_port; + uint16_t src_port; + uint16_t dst_port; }; #define IS_RULE_FILTERING_ON_SRC_IP(r) \ @@ -73,7 +73,7 @@ struct zebra_pbr_filter { * the user criteria may directly point to a table too. */ struct zebra_pbr_action { - u_int32_t table; + uint32_t table; }; /* @@ -84,7 +84,8 @@ struct zebra_pbr_action { * order amongst rules. */ struct zebra_pbr_rule { - u_int32_t seq; + uint32_t seq; + uint32_t priority; struct zebra_pbr_filter filter; struct zebra_pbr_action action; }; @@ -97,13 +98,13 @@ struct zebra_pbr_rule { * rule priority - maps to preference/FRA_PRIORITY on Linux. */ extern void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, - struct interface *ifp, u_int32_t rule_pri); + struct interface *ifp); /* * Uninstall specified rule for a specific interface. */ extern void kernel_del_pbr_rule(struct zebra_pbr_rule *rule, - struct interface *ifp, u_int32_t rule_pri); + struct interface *ifp); /* * Get to know existing PBR rules in the kernel - typically called at startup. @@ -115,14 +116,12 @@ extern void kernel_read_pbr_rules(struct zebra_ns *zns); */ extern void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, struct interface *ifp, - u_int32_t rule_pri, enum southbound_results res); /* * Handle rule delete notification from kernel. */ extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule, - struct interface *ifp, - u_int32_t rule_pri); + struct interface *ifp); #endif /* _ZEBRA_PBR_H */ diff --git a/zebra/zserv.c b/zebra/zserv.c index 13936e5366..007a02cedf 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -2595,7 +2595,6 @@ static inline void zread_rule(uint16_t command, struct zserv *client, struct interface *ifp; struct stream *s; uint32_t total, i; - uint32_t priority; ifindex_t ifindex; s = client->ibuf; @@ -2605,7 +2604,7 @@ static inline void zread_rule(uint16_t command, struct zserv *client, memset(&zpr, 0, sizeof(zpr)); STREAM_GETL(s, zpr.seq); - STREAM_GETL(s, priority); + STREAM_GETL(s, zpr.priority); STREAM_GETC(s, zpr.filter.src_ip.family); STREAM_GETC(s, zpr.filter.src_ip.prefixlen); STREAM_GET(&zpr.filter.src_ip.u.prefix, s, @@ -2637,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; - kernel_add_pbr_rule(&zpr, ifp, priority); + kernel_add_pbr_rule(&zpr, ifp); } stream_failure: From 1fbfe5a57249d907b44b31f9031b27eb59a606d4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 15 Feb 2018 20:11:12 -0500 Subject: [PATCH 08/11] zebra: Cleanup api Allow the add/delete to go through a intermediary function in zebra_pbr.c instead of directly to the underlying os call. This will allow future refinements to track the data a bit better so that on shutdown we can delete the rules. Signed-off-by: Donald Sharp --- zebra/zebra_pbr.c | 10 ++++++++++ zebra/zebra_pbr.h | 2 ++ zebra/zserv.c | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 827005b3a1..8a7e693bbf 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -31,6 +31,16 @@ /* Private functions */ /* Public functions */ +void zebra_pbr_add_rule(struct zebra_pbr_rule *rule, struct interface *ifp) +{ + kernel_add_pbr_rule(rule, ifp); +} + +void zebra_pbr_del_rule(struct zebra_pbr_rule *rule, struct interface *ifp) +{ + kernel_del_pbr_rule(rule, ifp); +} + /* * Handle success or failure of rule (un)install in the kernel. */ diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index b87388afc5..6a97ef55ed 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -90,6 +90,8 @@ 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); /* * Install specified rule for a specific interface. diff --git a/zebra/zserv.c b/zebra/zserv.c index 007a02cedf..7ec8525f49 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; - kernel_add_pbr_rule(&zpr, ifp); + zebra_pbr_add_rule(&zpr, ifp); } stream_failure: From 43fe6a2a7377d7a214bcc0afd599edd697a44e5d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 15 Feb 2018 21:34:04 -0500 Subject: [PATCH 09/11] zebra: Keep track of rules written Keep track of rules written into the kernel. This will allow us to delete them on shutdown if we are not cleaned up properly. Signed-off-by: Donald Sharp --- zebra/rule_netlink.c | 8 ++-- zebra/zebra_ns.c | 7 ++++ zebra/zebra_ns.h | 2 + zebra/zebra_pbr.c | 88 ++++++++++++++++++++++++++++++++++++++++++-- zebra/zebra_pbr.h | 9 ++++- zebra/zserv.c | 2 +- 6 files changed, 106 insertions(+), 10 deletions(-) diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 3228d0e4bd..c64d9f6ab2 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 580ff3eec1..192e8ad413 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 1d7b6f725e..19ecba1f0e 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 8a7e693bbf..3f8655552b 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -21,6 +21,9 @@ #include +#include +#include + #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 6a97ef55ed..f5f139cbda 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 7ec8525f49..a56b388ec9 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: From a03219780fb0efcc89853acc7c758a143a1157ae Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 23 Feb 2018 13:45:36 -0500 Subject: [PATCH 10/11] zebra: Make the ifp part of the rule structure Every place we need to pass around the rule structure we need to pass around the ifp as well. Move it into the structure. This will also allow us to notify up to higher level protocols that this worked properly or not better too. Signed-off-by: Donald Sharp --- zebra/rule_netlink.c | 36 +++++++++++++++++------------------- zebra/zebra_pbr.c | 23 ++++++++++++++--------- zebra/zebra_pbr.h | 17 ++++++----------- zebra/zserv.c | 10 ++++++---- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index c64d9f6ab2..2122f9f5fa 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -51,8 +51,7 @@ * Form netlink message and ship it. Currently, notify status after * waiting for netlink status. */ -static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, - struct interface *ifp) +static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) { int family; int bytelen; @@ -85,9 +84,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 */ - if (ifp) - addattr_l(&req.n, sizeof(req), FRA_IFNAME, ifp->name, - strlen(ifp->name) + 1); + if (rule->ifp) + addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifp->name, + strlen(rule->ifp->name) + 1); /* source IP, if specified */ if (IS_RULE_FILTERING_ON_SRC_IP(rule)) { @@ -115,8 +114,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 ? ifp->name : "Unknown", ifp ? ifp->ifindex : 0, - rule->priority, + rule->ifp ? rule->ifp->name : "Unknown", + rule->ifp ? rule->ifp->ifindex : 0, rule->priority, prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)), prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)), rule->action.table); @@ -138,12 +137,12 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule, * goes in the rule to denote relative ordering; it may or may not be the * same as the rule's user-defined sequence number. */ -void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, struct interface *ifp) +void kernel_add_pbr_rule(struct zebra_pbr_rule *rule) { int ret = 0; - ret = netlink_rule_update(RTM_NEWRULE, rule, ifp); - kernel_pbr_rule_add_del_status(rule, ifp, + ret = netlink_rule_update(RTM_NEWRULE, rule); + kernel_pbr_rule_add_del_status(rule, (!ret) ? SOUTHBOUND_INSTALL_SUCCESS : SOUTHBOUND_INSTALL_FAILURE); } @@ -151,12 +150,12 @@ void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, struct interface *ifp) /* * Uninstall specified rule for a specific interface. */ -void kernel_del_pbr_rule(struct zebra_pbr_rule *rule, struct interface *ifp) +void kernel_del_pbr_rule(struct zebra_pbr_rule *rule) { int ret = 0; - ret = netlink_rule_update(RTM_DELRULE, rule, ifp); - kernel_pbr_rule_add_del_status(rule, ifp, + ret = netlink_rule_update(RTM_DELRULE, rule); + kernel_pbr_rule_add_del_status(rule, (!ret) ? SOUTHBOUND_DELETE_SUCCESS : SOUTHBOUND_DELETE_FAILURE); } @@ -176,7 +175,6 @@ int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, struct rtattr *tb[FRA_MAX + 1]; int len; char *ifname; - struct interface *ifp; struct zebra_pbr_rule rule; char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; @@ -209,8 +207,8 @@ int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, /* If we don't know the interface, we don't care. */ ifname = (char *)RTA_DATA(tb[FRA_IFNAME]); zns = zebra_ns_lookup(ns_id); - ifp = if_lookup_by_name_per_ns(zns, ifname); - if (!ifp) + rule.ifp = if_lookup_by_name_per_ns(zns, ifname); + if (!rule.ifp) return 0; memset(&rule, 0, sizeof(rule)); @@ -248,13 +246,13 @@ int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h, zlog_debug( "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u", nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(frh->family), ifp->name, ifp->ifindex, - rule.priority, + nl_family_to_str(frh->family), rule.ifp->name, + rule.ifp->ifindex, rule.priority, prefix2str(&rule.filter.src_ip, buf1, sizeof(buf1)), prefix2str(&rule.filter.dst_ip, buf2, sizeof(buf2)), rule.action.table); - return kernel_pbr_rule_del(&rule, ifp); + return kernel_pbr_rule_del(&rule); } /* diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 3f8655552b..0096da942e 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -40,7 +40,7 @@ void zebra_pbr_rules_free(void *arg) rule = (struct zebra_pbr_rule *)arg; - kernel_del_pbr_rule(rule, NULL); + kernel_del_pbr_rule(rule); XFREE(MTYPE_TMP, rule); } @@ -52,6 +52,11 @@ uint32_t zebra_pbr_rules_hash_key(void *arg) rule = (struct zebra_pbr_rule *)arg; key = jhash_3words(rule->seq, rule->priority, rule->action.table, prefix_hash_key(&rule->filter.src_ip)); + if (rule->ifp) + key = jhash_1word(rule->ifp->ifindex, key); + else + key = jhash_1word(0, key); + return jhash_3words(rule->filter.src_port, rule->filter.dst_port, prefix_hash_key(&rule->filter.dst_ip), key); } @@ -84,6 +89,9 @@ int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) if (!prefix_same(&r1->filter.dst_ip, &r2->filter.dst_ip)) return 0; + if (r1->ifp != r2->ifp) + return 0; + return 1; } @@ -101,20 +109,18 @@ static void *pbr_rule_alloc_intern(void *arg) return new; } -void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule, - struct interface *ifp) +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, ifp); + kernel_add_pbr_rule(rule); } -void zebra_pbr_del_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 zebra_pbr_rule *lookup; lookup = hash_lookup(zns->rules_hash, rule); - kernel_del_pbr_rule(rule, ifp); + kernel_del_pbr_rule(rule); if (lookup) XFREE(MTYPE_TMP, lookup); @@ -127,7 +133,6 @@ void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule, * Handle success or failure of rule (un)install in the kernel. */ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, - struct interface *ifp, enum southbound_results res) { } @@ -135,7 +140,7 @@ void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, /* * Handle rule delete notification from kernel. */ -int kernel_pbr_rule_del(struct zebra_pbr_rule *rule, struct interface *ifp) +int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) { return 0; } diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index f5f139cbda..9983de4f22 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -86,14 +86,13 @@ struct zebra_pbr_action { struct zebra_pbr_rule { uint32_t seq; uint32_t priority; + struct interface *ifp; struct zebra_pbr_filter filter; struct zebra_pbr_action action; }; -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); +void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule); +void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule); /* * Install specified rule for a specific interface. @@ -101,14 +100,12 @@ void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule, * forwarding plane may not coincide, hence the API requires a separate * rule priority - maps to preference/FRA_PRIORITY on Linux. */ -extern void kernel_add_pbr_rule(struct zebra_pbr_rule *rule, - struct interface *ifp); +extern void kernel_add_pbr_rule(struct zebra_pbr_rule *rule); /* * Uninstall specified rule for a specific interface. */ -extern void kernel_del_pbr_rule(struct zebra_pbr_rule *rule, - struct interface *ifp); +extern void kernel_del_pbr_rule(struct zebra_pbr_rule *rule); /* * Get to know existing PBR rules in the kernel - typically called at startup. @@ -119,14 +116,12 @@ extern void kernel_read_pbr_rules(struct zebra_ns *zns); * Handle success or failure of rule (un)install in the kernel. */ extern void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, - struct interface *ifp, enum southbound_results res); /* * Handle rule delete notification from kernel. */ -extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule, - struct interface *ifp); +extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule); extern void zebra_pbr_rules_free(void *arg); extern uint32_t zebra_pbr_rules_hash_key(void *arg); diff --git a/zebra/zserv.c b/zebra/zserv.c index a56b388ec9..d05b058c7c 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -2592,7 +2592,6 @@ static inline void zread_rule(uint16_t command, struct zserv *client, uint16_t length, struct zebra_vrf *zvrf) { struct zebra_pbr_rule zpr; - struct interface *ifp; struct stream *s; uint32_t total, i; ifindex_t ifindex; @@ -2618,8 +2617,8 @@ static inline void zread_rule(uint16_t command, struct zserv *client, STREAM_GETL(s, zpr.action.table); STREAM_GETL(s, ifindex); - ifp = if_lookup_by_index(ifindex, VRF_UNKNOWN); - if (!ifp) { + zpr.ifp = if_lookup_by_index(ifindex, VRF_UNKNOWN); + if (!zpr.ifp) { zlog_debug("FAiled to lookup ifindex: %u", ifindex); return; } @@ -2636,7 +2635,10 @@ 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(zvrf->zns, &zpr, ifp); + if (command == ZEBRA_RULE_ADD) + zebra_pbr_add_rule(zvrf->zns, &zpr); + else + zebra_pbr_del_rule(zvrf->zns, &zpr); } stream_failure: From b6c5d34354c7153bebd2c51e89fd2e32f0dc343c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 23 Feb 2018 13:48:06 -0500 Subject: [PATCH 11/11] lib, zebra: Add Rule insertion success/failure messages Add code to allow rule insertion notifications to be sent back up the stack. Signed-off-by: Donald Sharp --- lib/zclient.c | 33 +++++++++++++++++++++++++++++++++ lib/zclient.h | 12 ++++++++++++ zebra/zebra_pbr.c | 18 +++++++++++++++++- zebra/zebra_pbr.h | 9 +++++++++ zebra/zserv.c | 40 ++++++++++++++++++++++++++++++++++++++++ zebra/zserv.h | 5 +++++ 6 files changed, 116 insertions(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index 3f2021a5b5..fa3a5f6691 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1237,6 +1237,35 @@ stream_failure: return false; } +bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, + uint32_t *priority, uint32_t *unique, + ifindex_t *ifindex, + enum zapi_rule_notify_owner *note) +{ + uint32_t prio, seq, uni; + ifindex_t ifi; + + STREAM_GET(note, s, sizeof(*note)); + + STREAM_GETL(s, seq); + STREAM_GETL(s, prio); + STREAM_GETL(s, uni); + STREAM_GETL(s, ifi); + + if (zclient_debug) + zlog_debug("%s: %u %u %u %u", __PRETTY_FUNCTION__, + seq, prio, uni, ifi); + *seqno = seq; + *priority = prio; + *unique = uni; + *ifindex = ifi; + + return true; + +stream_failure: + return false; +} + struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh) { struct nexthop *n = nexthop_new(); @@ -2381,6 +2410,10 @@ static int zclient_read(struct thread *thread) (*zclient->route_notify_owner)(command, zclient, length, vrf_id); break; + case ZEBRA_RULE_NOTIFY_OWNER: + if (zclient->rule_notify_owner) + (*zclient->rule_notify_owner)(command, zclient, length, + vrf_id); default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index a315a7ed5a..1aa94b641c 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -218,6 +218,8 @@ struct zclient { int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); int (*route_notify_owner)(int command, struct zclient *zclient, uint16_t length, vrf_id_t vrf_id); + int (*rule_notify_owner)(int command, struct zclient *zclient, + uint16_t length, vrf_id_t vrf_id); }; /* Zebra API message flag. */ @@ -361,6 +363,12 @@ enum zapi_route_notify_owner { ZAPI_ROUTE_REMOVE_FAIL, }; +enum zapi_rule_notify_owner { + ZAPI_RULE_FAIL_INSTALL, + ZAPI_RULE_INSTALLED, + ZAPI_RULE_REMOVED, +}; + /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ @@ -531,6 +539,10 @@ extern int zapi_route_decode(struct stream *, struct zapi_route *); bool zapi_route_notify_decode(struct stream *s, struct prefix *p, uint32_t *tableid, enum zapi_route_notify_owner *note); +bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, + uint32_t *priority, uint32_t *unique, + ifindex_t *ifindex, + enum zapi_rule_notify_owner *note); extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh); extern bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr); diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 0096da942e..4da09dc538 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -58,7 +58,8 @@ uint32_t zebra_pbr_rules_hash_key(void *arg) key = jhash_1word(0, key); return jhash_3words(rule->filter.src_port, rule->filter.dst_port, - prefix_hash_key(&rule->filter.dst_ip), key); + prefix_hash_key(&rule->filter.dst_ip), + jhash_1word(rule->unique, key)); } int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) @@ -74,6 +75,9 @@ int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) if (r1->priority != r2->priority) return 0; + if (r1->unique != r2->unique) + return 0; + if (r1->action.table != r2->action.table) return 0; @@ -135,6 +139,18 @@ void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, enum southbound_results res) { + switch (res) { + case SOUTHBOUND_INSTALL_SUCCESS: + zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED); + break; + case SOUTHBOUND_INSTALL_FAILURE: + zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL); + break; + case SOUTHBOUND_DELETE_SUCCESS: + break; + case SOUTHBOUND_DELETE_FAILURE: + break; + } } /* diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 9983de4f22..4b28b6ec35 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -28,6 +28,7 @@ #include "prefix.h" #include "if.h" + #include "rt.h" /* @@ -84,9 +85,16 @@ struct zebra_pbr_action { * order amongst rules. */ struct zebra_pbr_rule { + /* + * Originating zclient sock fd, so we can know who to send + * back to. + */ + int sock; + uint32_t seq; uint32_t priority; struct interface *ifp; + uint32_t unique; struct zebra_pbr_filter filter; struct zebra_pbr_action action; }; @@ -112,6 +120,7 @@ extern void kernel_del_pbr_rule(struct zebra_pbr_rule *rule); */ extern void kernel_read_pbr_rules(struct zebra_ns *zns); +enum southbound_results; /* * Handle success or failure of rule (un)install in the kernel. */ diff --git a/zebra/zserv.c b/zebra/zserv.c index d05b058c7c..1a2ad7f8b4 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1043,6 +1043,44 @@ int zsend_route_notify_owner(struct route_entry *re, struct prefix *p, return zebra_server_send_message(client); } +void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, + enum zapi_rule_notify_owner note) +{ + struct listnode *node; + struct zserv *client; + struct stream *s; + + if (IS_ZEBRA_DEBUG_PACKET) { + zlog_debug("%s: Notifying %u", + __PRETTY_FUNCTION__, rule->unique); + } + + for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) { + if (rule->sock == client->sock) + break; + } + + if (!client) + return; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT); + stream_put(s, ¬e, sizeof(note)); + stream_putl(s, rule->seq); + stream_putl(s, rule->priority); + stream_putl(s, rule->unique); + if (rule->ifp) + stream_putl(s, rule->ifp->ifindex); + else + stream_putl(s, 0); + + stream_putw_at(s, 0, stream_get_endp(s)); + + zebra_server_send_message(client); +} + /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */ int zsend_router_id_update(struct zserv *client, struct prefix *p, vrf_id_t vrf_id) @@ -2602,8 +2640,10 @@ static inline void zread_rule(uint16_t command, struct zserv *client, for (i = 0; i < total; i++) { memset(&zpr, 0, sizeof(zpr)); + zpr.sock = client->sock; STREAM_GETL(s, zpr.seq); STREAM_GETL(s, zpr.priority); + STREAM_GETL(s, zpr.unique); STREAM_GETC(s, zpr.filter.src_ip.family); STREAM_GETC(s, zpr.filter.src_ip.prefixlen); STREAM_GET(&zpr.filter.src_ip.u.prefix, s, diff --git a/zebra/zserv.h b/zebra/zserv.h index 4f0f5b0461..8519693726 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -31,6 +31,7 @@ #include "zebra/zebra_ns.h" #include "zebra/zebra_pw.h" +//#include "zebra/zebra_pbr.h" /* Default port information. */ #define ZEBRA_VTY_PORT 2601 @@ -178,6 +179,10 @@ extern int zsend_pw_update(struct zserv *, struct zebra_pw *); extern int zsend_route_notify_owner(struct route_entry *re, struct prefix *p, enum zapi_route_notify_owner note); +struct zebra_pbr_rule; +extern void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, + enum zapi_rule_notify_owner note); + extern void zserv_nexthop_num_warn(const char *, const struct prefix *, const unsigned int); extern int zebra_server_send_message(struct zserv *client);