diff options
65 files changed, 1844 insertions, 516 deletions
diff --git a/Makefile.am b/Makefile.am index dfa9d7a175..2468dc733d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,6 +53,7 @@ include nhrpd/subdir.am include ldpd/subdir.am include babeld/subdir.am include eigrpd/subdir.am +include sharpd/subdir.am include pimd/subdir.am SUBDIRS = . @LIBRFP@ @RFPTEST@ \ diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index e7c27e8e21..8dea1431e2 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -237,7 +237,7 @@ babel_zebra_connected (struct zclient *zclient) void babelz_zebra_init(void) { - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_BABEL, 0, &babeld_privs); zclient->zebra_connected = babel_zebra_connected; diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 19cb1cf03a..fa1dcbb762 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -73,6 +73,8 @@ module_LTLIBRARIES = sbin_PROGRAMS = bgpd bin_PROGRAMS = bgp_btoa +BUILT_SOURCES = + libbgp_a_SOURCES = \ bgp_memory.c \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ @@ -116,13 +118,9 @@ bgpd_snmp_la_LIBADD = ../lib/libfrrsnmp.la if RPKI module_LTLIBRARIES += bgpd_rpki.la +BUILT_SOURCES += bgp_rpki_clippy.c endif -bgpd_rpki_la-bgp_rpki.o: bgp_rpki_clippy.c -bgp_rpki.la: bgp_rpki_clippy.c -bgp_rpki.lo: bgp_rpki_clippy.c -bgp_rpki.o: bgp_rpki_clippy.c - bgpd_rpki_la_SOURCES = bgp_rpki.c bgpd_rpki_la_CFLAGS = $(WERROR) $(RTRLIB_CFLAGS) bgpd_rpki_la_LDFLAGS = -avoid-version -module -shared -export-dynamic diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 76fc8f968e..6ddb2ec8a7 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -822,6 +822,32 @@ void bgp_attr_unintern_sub(struct attr *attr) #endif } +/* + * We have some show commands that let you experimentally + * apply a route-map. When we apply the route-map + * we are reseting values but not saving them for + * posterity via intern'ing( because route-maps don't + * do that) but at this point in time we need + * to compare the new attr to the old and if the + * routemap has changed it we need to, as Snoop Dog says, + * Drop it like it's hot + */ +void bgp_attr_undup(struct attr *new, struct attr *old) +{ + if (new->aspath != old->aspath) + aspath_free(new->aspath); + + if (new->community != old->community) + community_free(new->community); + + if (new->ecommunity != old->ecommunity) + ecommunity_free(&new->ecommunity); + + if (new->lcommunity != old->lcommunity) + lcommunity_free(&new->lcommunity); + +} + /* Free bgp attribute and aspath. */ void bgp_attr_unintern(struct attr **pattr) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 80ff36b59f..f694f01adb 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -239,6 +239,7 @@ extern bgp_attr_parse_ret_t bgp_attr_parse(struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); extern void bgp_attr_dup(struct attr *, struct attr *); +extern void bgp_attr_undup(struct attr *new, struct attr *old); extern struct attr *bgp_attr_intern(struct attr *attr); extern void bgp_attr_unintern_sub(struct attr *); extern void bgp_attr_unintern(struct attr **); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a5f9c5f2ab..a655bd0b6f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1157,49 +1157,52 @@ static int bgp_output_modifier(struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name) { - struct bgp_filter *filter; struct bgp_info info; route_map_result_t ret; struct route_map *rmap = NULL; + u_char rmap_type; - filter = &peer->filter[afi][safi]; + /* + * So if we get to this point and have no rmap_name + * we want to just show the output as it currently + * exists. + */ + if (!rmap_name) + return RMAP_PERMIT; /* Apply default weight value. */ if (peer->weight[afi][safi]) attr->weight = peer->weight[afi][safi]; - if (rmap_name) { - rmap = route_map_lookup_by_name(rmap_name); - - if (rmap == NULL) - return RMAP_DENY; - } else { - if (ROUTE_MAP_OUT_NAME(filter)) { - rmap = ROUTE_MAP_OUT(filter); + rmap = route_map_lookup_by_name(rmap_name); - if (rmap == NULL) - return RMAP_DENY; - } - } + /* + * If we have a route map name and we do not find + * the routemap that means we have an implicit + * deny. + */ + if (rmap == NULL) + return RMAP_DENY; /* Route map apply. */ - if (rmap) { - /* Duplicate current value to new strucutre for modification. */ - info.peer = peer; - info.attr = attr; + /* Duplicate current value to new strucutre for modification. */ + info.peer = peer; + info.attr = attr; - SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT); + rmap_type = peer->rmap_type; + SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_OUT); - /* Apply BGP route map to the attribute. */ - ret = route_map_apply(rmap, p, RMAP_BGP, &info); + /* Apply BGP route map to the attribute. */ + ret = route_map_apply(rmap, p, RMAP_BGP, &info); - peer->rmap_type = 0; + peer->rmap_type = rmap_type; + + if (ret == RMAP_DENYMATCH) + /* + * caller has multiple error paths with bgp_attr_flush() + */ + return RMAP_DENY; - if (ret == RMAP_DENYMATCH) - /* caller has multiple error paths with bgp_attr_flush() - */ - return RMAP_DENY; - } return RMAP_PERMIT; } @@ -10180,70 +10183,75 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, } } else { for (adj = rn->adj_out; adj; adj = adj->next) - SUBGRP_FOREACH_PEER (adj->subgroup, paf) - if (paf->peer == peer) { - if (header1) { - if (use_json) { - json_object_int_add( - json, - "bgpTableVersion", - table->version); - json_object_string_add( - json, - "bgpLocalRouterId", - inet_ntoa( - bgp->router_id)); - json_object_object_add( - json, - "bgpStatusCodes", - json_scode); - json_object_object_add( - json, - "bgpOriginCodes", - json_ocode); - } else { - vty_out(vty, - "BGP table version is %" PRIu64 - ", local router ID is %s\n", - table->version, - inet_ntoa( - bgp->router_id)); - vty_out(vty, - BGP_SHOW_SCODE_HEADER); - vty_out(vty, - BGP_SHOW_OCODE_HEADER); - } - header1 = 0; - } + SUBGRP_FOREACH_PEER (adj->subgroup, paf) { + if (paf->peer != peer) + continue; - if (header2) { - if (!use_json) - vty_out(vty, - BGP_SHOW_HEADER); - header2 = 0; + if (header1) { + if (use_json) { + json_object_int_add( + json, + "bgpTableVersion", + table->version); + json_object_string_add( + json, + "bgpLocalRouterId", + inet_ntoa( + bgp->router_id)); + json_object_object_add( + json, + "bgpStatusCodes", + json_scode); + json_object_object_add( + json, + "bgpOriginCodes", + json_ocode); + } else { + vty_out(vty, + "BGP table version is %" PRIu64 + ", local router ID is %s\n", + table->version, + inet_ntoa( + bgp->router_id)); + vty_out(vty, + BGP_SHOW_SCODE_HEADER); + vty_out(vty, + BGP_SHOW_OCODE_HEADER); } + header1 = 0; + } + + if (header2) { + if (!use_json) + vty_out(vty, + BGP_SHOW_HEADER); + header2 = 0; + } - if (adj->attr) { - bgp_attr_dup(&attr, - adj->attr); - ret = bgp_output_modifier( - peer, &rn->p, - &attr, afi, + if (adj->attr) { + bgp_attr_dup(&attr, + adj->attr); + ret = bgp_output_modifier( + peer, &rn->p, + &attr, afi, + safi, + rmap_name); + if (ret != RMAP_DENY) { + route_vty_out_tmp( + vty, + &rn->p, + &attr, safi, - rmap_name); - if (ret != RMAP_DENY) { - route_vty_out_tmp( - vty, - &rn->p, - &attr, - safi, - use_json, - json_ar); - output_count++; - } else - filtered_count++; - } + use_json, + json_ar); + output_count++; + } else + filtered_count++; + + bgp_attr_undup(&attr, + adj->attr); } + } } } if (use_json) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b0af5f2ced..9159bc683d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6313,7 +6313,7 @@ DEFUN (clear_ip_bgp_prefix, int idx = 0; /* [<view|vrf> VIEWVRFNAME] */ - if (argv_find(argv, argc, "WORD", &idx)) + if (argv_find(argv, argc, "VIEWVRFNAME", &idx)) vrf = argv[idx]->arg; prefix = argv[argc - 1]->arg; @@ -10461,60 +10461,39 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) return CMD_SUCCESS; } -/* Show BGP peer group's information. */ -enum show_group_type { show_all_groups, show_peer_group }; - -static int bgp_show_peer_group(struct vty *vty, struct bgp *bgp, - enum show_group_type type, - const char *group_name) +static int bgp_show_peer_group_vty(struct vty *vty, const char *name, + const char *group_name) { + struct bgp *bgp; struct listnode *node, *nnode; struct peer_group *group; - int find = 0; + bool found = false; + + bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); + + if (!bgp) { + vty_out(vty, "%% No such BGP instance exists\n"); + return CMD_WARNING; + } for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) { - switch (type) { - case show_all_groups: - bgp_show_one_peer_group(vty, group); - break; - case show_peer_group: - if (group_name - && (strcmp(group->name, group_name) == 0)) { - find = 1; + if (group_name) { + if (strmatch(group->name, group_name)) { bgp_show_one_peer_group(vty, group); + found = true; + break; } - break; + } else { + bgp_show_one_peer_group(vty, group); } } - if (type == show_peer_group && !find) + if (group_name && !found) vty_out(vty, "%% No such peer-group\n"); return CMD_SUCCESS; } -static int bgp_show_peer_group_vty(struct vty *vty, const char *name, - enum show_group_type type, - const char *group_name) -{ - struct bgp *bgp; - int ret = CMD_SUCCESS; - - if (name) - bgp = bgp_lookup_by_name(name); - else - bgp = bgp_get_default(); - - if (!bgp) { - vty_out(vty, "%% No such BGP instance exist\n"); - return CMD_WARNING; - } - - ret = bgp_show_peer_group(vty, bgp, type, group_name); - - return ret; -} - DEFUN (show_ip_bgp_peer_groups, show_ip_bgp_peer_groups_cmd, "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME]", @@ -10529,10 +10508,10 @@ DEFUN (show_ip_bgp_peer_groups, vrf = pg = NULL; int idx = 0; - vrf = argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL; + vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg : NULL; pg = argv_find(argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL; - return bgp_show_peer_group_vty(vty, vrf, show_all_groups, pg); + return bgp_show_peer_group_vty(vty, vrf, pg); } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index b6bf008bae..1cf04abfce 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1759,7 +1759,7 @@ void bgp_zebra_init(struct thread_master *master) zclient_num_connects = 0; /* Set default values. */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); zclient->zebra_connected = bgp_zebra_connected; zclient->router_id_update = bgp_router_id_update; diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index 478d3b5ac7..5c71df238f 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -892,7 +892,7 @@ extern struct zebra_privs_t bgpd_privs; void vnc_zebra_init(struct thread_master *master) { /* Set default values. */ - zclient_vnc = zclient_new(master); + zclient_vnc = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0, &bgpd_privs); zclient_vnc->redistribute_route_add = vnc_zebra_read_route; diff --git a/configure.ac b/configure.ac index cdbd48fe3c..16cc8901a3 100755 --- a/configure.ac +++ b/configure.ac @@ -201,6 +201,7 @@ else fi fi AM_CONDITIONAL([DEV_BUILD], [test "x$enable_dev_build" = "xyes"]) +AM_CONDITIONAL([SHARPD], [test "x$enable_dev_build" = "xyes"]) dnl always want these CFLAGS AC_C_FLAG([-fno-omit-frame-pointer]) diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 9076a50f57..00438f2f47 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -94,6 +94,18 @@ static int eigrp_router_id_update_zebra(int command, struct zclient *zclient, return 0; } +static int eigrp_zebra_notify_owner(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct prefix p; + enum zapi_route_notify_owner note; + + if (!zapi_route_notify_decode(zclient->ibuf, &p, ¬e)) + return -1; + + return 0; +} + static void eigrp_zebra_connected(struct zclient *zclient) { zclient_send_reg_requests(zclient, VRF_DEFAULT); @@ -101,7 +113,9 @@ static void eigrp_zebra_connected(struct zclient *zclient) void eigrp_zebra_init(void) { - zclient = zclient_new(master); + struct zclient_options opt = { .receive_notify = false }; + + zclient = zclient_new_notify(master, &opt); zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs); zclient->zebra_connected = eigrp_zebra_connected; @@ -114,6 +128,7 @@ void eigrp_zebra_init(void) zclient->interface_address_delete = eigrp_interface_address_delete; zclient->redistribute_route_add = eigrp_zebra_read_route; zclient->redistribute_route_del = eigrp_zebra_read_route; + zclient->notify_owner = eigrp_zebra_notify_owner; } diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index c186dd56ad..573b81591c 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -411,7 +411,7 @@ static void isis_zebra_connected(struct zclient *zclient) void isis_zebra_init(struct thread_master *master) { - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_ISIS, 0, &isisd_privs); zclient->zebra_connected = isis_zebra_connected; zclient->router_id_update = isis_router_id_update_zebra; diff --git a/ldpd/lde.c b/ldpd/lde.c index 8122b88cca..b597d967d7 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1618,7 +1618,7 @@ static void zclient_sync_init(u_short instance) { /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master); + zclient_sync = zclient_new_notify(master, &zclient_options_default); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_LDP; zclient_sync->instance = instance; diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 8fe51cb9d1..e703a9ff61 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -513,7 +513,7 @@ void ldp_zebra_init(struct thread_master *master) { /* Set default values. */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_LDP, 0, &ldpd_privs); /* set callbacks */ diff --git a/lib/json.h b/lib/json.h index e3e55ab962..675d852af7 100644 --- a/lib/json.h +++ b/lib/json.h @@ -52,4 +52,19 @@ extern void json_object_free(struct json_object *obj); #define JSON_STR "JavaScript Object Notation\n" +/* NOTE: json-c lib has following commit 316da85 which + * handles escape of forward slash. + * This allows prefix "20.0.14.0\/24":{ + * to "20.0.14.0/24":{ some platforms do not have + * latest copy of json-c where defining below macro. + */ + +#ifndef JSON_C_TO_STRING_NOSLASHESCAPE + +/** + * Don't escape forward slashes. + */ +#define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) +#endif + #endif /* _QUAGGA_JSON_H */ @@ -897,6 +897,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER), DESC_ENTRY(ZEBRA_ROUTE_ADD), DESC_ENTRY(ZEBRA_ROUTE_DELETE), + DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_OWNER), DESC_ENTRY(ZEBRA_IPV4_ROUTE_ADD), DESC_ENTRY(ZEBRA_IPV4_ROUTE_DELETE), DESC_ENTRY(ZEBRA_IPV6_ROUTE_ADD), @@ -1044,6 +1045,8 @@ int proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_NHRP; else if (strmatch(s, "babel")) return ZEBRA_ROUTE_BABEL; + else if (strmatch(s, "sharp")) + return ZEBRA_ROUTE_SHARP; } if (afi == AFI_IP6) { if (strmatch(s, "kernel")) @@ -1070,6 +1073,8 @@ int proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_NHRP; else if (strmatch(s, "babel")) return ZEBRA_ROUTE_BABEL; + else if (strmatch(s, "sharp")) + return ZEBRA_ROUTE_SHARP; } return -1; } diff --git a/lib/route_types.txt b/lib/route_types.txt index 386d9992f7..4e764a14c1 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -77,6 +77,7 @@ ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct" # bgp unicast -> vnc ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC" ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel" +ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, "SHARP" ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-" @@ -101,3 +102,4 @@ ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table" ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)" ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes" ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)" +ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)" diff --git a/lib/zclient.c b/lib/zclient.c index 6d6d44fb12..655e4e1a80 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -52,8 +52,11 @@ socklen_t zclient_addr_len; /* This file local debug flag. */ int zclient_debug = 0; +struct zclient_options zclient_options_default = { .receive_notify = false }; + /* Allocate zclient structure. */ -struct zclient *zclient_new(struct thread_master *master) +struct zclient *zclient_new_notify(struct thread_master *master, + struct zclient_options *opt) { struct zclient *zclient; zclient = XCALLOC(MTYPE_ZCLIENT, sizeof(struct zclient)); @@ -63,6 +66,8 @@ struct zclient *zclient_new(struct thread_master *master) zclient->wb = buffer_new(0); zclient->master = master; + zclient->receive_notify = opt->receive_notify; + return zclient; } @@ -190,7 +195,7 @@ void zclient_reset(struct zclient *zclient) * @param zclient a pointer to zclient structure * @return socket fd just to make sure that connection established * @see zclient_init - * @see zclient_new + * @see zclient_new_notify */ int zclient_socket_connect(struct zclient *zclient) { @@ -346,6 +351,11 @@ static int zebra_hello_send(struct zclient *zclient) zclient_create_header(s, ZEBRA_HELLO, VRF_DEFAULT); stream_putc(s, zclient->redist_default); stream_putw(s, zclient->instance); + if (zclient->receive_notify) + stream_putc(s, 1); + else + stream_putc(s, 0); + stream_putw_at(s, 0, stream_get_endp(s)); return zclient_send_message(zclient); } @@ -1144,6 +1154,22 @@ stream_failure: return 0; } +bool zapi_route_notify_decode(struct stream *s, struct prefix *p, + enum zapi_route_notify_owner *note) +{ + STREAM_GET(note, s, sizeof(*note)); + + STREAM_GETC(s, p->family); + STREAM_GETC(s, p->prefixlen); + STREAM_GET(&p->u.prefix, s, + PSIZE(p->prefixlen)); + + return true; + +stream_failure: + return false; +} + /* * send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE * for the route type (ZEBRA_ROUTE_KERNEL etc.). The zebra server will @@ -2194,6 +2220,11 @@ static int zclient_read(struct thread *thread) (*zclient->pw_status_update)(command, zclient, length, vrf_id); break; + case ZEBRA_ROUTE_NOTIFY_OWNER: + if (zclient->notify_owner) + (*zclient->notify_owner)(command, zclient, + length, vrf_id); + break; default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index e9b2cb8956..de58044671 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -61,6 +61,7 @@ typedef enum { ZEBRA_INTERFACE_SET_MASTER, ZEBRA_ROUTE_ADD, ZEBRA_ROUTE_DELETE, + ZEBRA_ROUTE_NOTIFY_OWNER, ZEBRA_IPV4_ROUTE_ADD, ZEBRA_IPV4_ROUTE_DELETE, ZEBRA_IPV6_ROUTE_ADD, @@ -137,6 +138,9 @@ struct zclient { /* Priviledges to change socket values */ struct zebra_privs_t *privs; + /* Do we care about failure events for route install? */ + bool receive_notify; + /* Socket to zebra daemon. */ int sock; @@ -199,6 +203,8 @@ struct zclient { int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); + int (*notify_owner)(int command, struct zclient *zclient, + uint16_t length, vrf_id_t vrf_id); }; /* Zebra API message flag. */ @@ -323,12 +329,35 @@ struct zapi_pw_status { uint32_t status; }; +enum zapi_route_notify_owner { + ZAPI_ROUTE_FAIL_INSTALL, + ZAPI_ROUTE_BETTER_ADMIN_WON, + ZAPI_ROUTE_INSTALLED, +}; + /* Zebra MAC types */ #define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/ +struct zclient_options { + bool receive_notify; +}; + /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new(struct thread_master *); + +#if CONFDATE > 20181101 +CPP_NOTICE("zclient_new_notify can take over or zclient_new now"); +#endif + +extern struct zclient_options zclient_options_default; + +extern struct zclient *zclient_new_notify(struct thread_master *m, + struct zclient_options *opt); + +#define zclient_new(A) zclient_new_notify((A), &zclient_options_default); \ + CPP_WARN("Please transition to using zclient_new_notify"); + extern void zclient_init(struct zclient *, int, u_short, struct zebra_privs_t *privs); extern int zclient_start(struct zclient *); extern void zclient_stop(struct zclient *); @@ -445,6 +474,8 @@ extern int zapi_ipv4_route_ipv6_nexthop(u_char, struct zclient *, extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *); extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *); extern int zapi_route_decode(struct stream *, struct zapi_route *); +bool zapi_route_notify_decode(struct stream *s, struct prefix *p, + enum zapi_route_notify_owner *note); static inline void zapi_route_set_blackhole(struct zapi_route *api, enum blackhole_type bh_type) diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 7701dcbb88..2612d8e045 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -314,7 +314,7 @@ void nhrp_zebra_init(void) zebra_rib[AFI_IP] = route_table_init(); zebra_rib[AFI_IP6] = route_table_init(); - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient->zebra_connected = nhrp_zebra_connected; zclient->interface_add = nhrp_interface_add; zclient->interface_delete = nhrp_interface_delete; diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 6bbab46ad8..bd5e2bd1d3 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -61,8 +61,8 @@ static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa) case OSPF6_LSTYPE_ROUTER: case OSPF6_LSTYPE_NETWORK: if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) { - zlog_debug("Examin %s", lsa->name); - zlog_debug("Schedule SPF Calculation for %s", + zlog_debug("%s Examin LSA %s", __PRETTY_FUNCTION__, lsa->name); + zlog_debug(" Schedule SPF Calculation for %s", OSPF6_AREA(lsa->lsdb->data)->name); } ospf6_spf_schedule( diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index b5a0a9209b..b1d940952c 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1316,7 +1316,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) return; if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) - zlog_debug("%s found", lsa->name); + zlog_debug("%s: LSA %s found", __PRETTY_FUNCTION__, lsa->name); oa = OSPF6_AREA(lsa->lsdb->data); @@ -1325,7 +1325,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) lsa->header); if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER)) ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router, - htonl(0), &ls_prefix); + intra_prefix_lsa->ref_id, &ls_prefix); else if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK)) ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router, intra_prefix_lsa->ref_id, &ls_prefix); @@ -1404,7 +1404,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug(" add %s", buf); + zlog_debug(" route %s add", buf); } ospf6_route_add(route, oa->route_table); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 4276f46c38..340d90159f 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -110,26 +110,30 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa) sizeof(struct ospf6_vertex)); /* type */ - if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) + if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) { v->type = OSPF6_VERTEX_TYPE_ROUTER; - else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_NETWORK) + /* Router LSA use Link ID 0 as base in vertex_id */ + ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), + &v->vertex_id); + } else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_NETWORK) { v->type = OSPF6_VERTEX_TYPE_NETWORK; - else - assert(0); - - /* vertex_id */ - ospf6_linkstate_prefix(lsa->header->adv_router, lsa->header->id, + /* vertex_id */ + ospf6_linkstate_prefix(lsa->header->adv_router, lsa->header->id, &v->vertex_id); + } else + assert(0); /* name */ ospf6_linkstate_prefix2str(&v->vertex_id, v->name, sizeof(v->name)); if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("%s: Creating vertex %s of type %s", __func__, - v->name, + zlog_debug("%s: Creating vertex %s of type %s (0x%04hx) lsa %s", + __func__, v->name, ((ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) ? "Router" - : "N/W")); + : "N/W"), ntohs(lsa->header->type), + lsa->name); + /* Associated LSA */ v->lsa = lsa; @@ -158,7 +162,8 @@ static void ospf6_vertex_delete(struct ospf6_vertex *v) } static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, - struct ospf6_vertex *v) + struct ospf6_vertex *v, + uint32_t link_id) { struct ospf6_lsa *lsa; u_int16_t type = 0; @@ -166,12 +171,12 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, if (VERTEX_IS_TYPE(NETWORK, v)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = htonl(0); + id = link_id; adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc); } else { if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = htonl(0); + id = link_id; adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc); } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) { type = htons(OSPF6_LSTYPE_NETWORK); @@ -187,10 +192,12 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf)); inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf)); if (lsa) - zlog_debug(" Link to: %s", lsa->name); + zlog_debug(" Link to: %s , V %s id %u", lsa->name, + v->name, link_id); else - zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA", - ospf6_lstype_name(type), ibuf, abuf); + zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s id %u", + ospf6_lstype_name(type), ibuf, abuf, + v->name, link_id); } return lsa; @@ -308,10 +315,11 @@ static int ospf6_spf_install(struct ospf6_vertex *v, { struct ospf6_route *route, *parent_route; struct ospf6_vertex *prev; + char pbuf[PREFIX2STR_BUFFER]; if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("SPF install %s hops %d cost %d", v->name, v->hops, - v->cost); + zlog_debug("SPF install %s (lsa %s) hops %d cost %d", v->name, + v->lsa->name, v->hops, v->cost); route = ospf6_route_lookup(&v->vertex_id, result_table); if (route && route->path.cost < v->cost) { @@ -322,16 +330,30 @@ static int ospf6_spf_install(struct ospf6_vertex *v, ospf6_vertex_delete(v); return -1; } else if (route && route->path.cost == v->cost) { - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug(" another path found, merge"); - + if (IS_OSPF6_DEBUG_SPF(PROCESS)) { + prefix2str(&route->prefix, pbuf, sizeof(pbuf)); + zlog_debug(" another path found to route %s lsa %s, merge", + pbuf, v->lsa->name); + } ospf6_spf_merge_nexthops_to_route(route, v); prev = (struct ospf6_vertex *)route->route_option; assert(prev->hops <= v->hops); - ospf6_vertex_delete(v); + if ((VERTEX_IS_TYPE(ROUTER, v) && + route->path.origin.id != v->lsa->header->id)) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) { + zlog_debug("%s: V lsa %s id %u, route id %u are different", + __PRETTY_FUNCTION__, v->lsa->name, + ntohl(v->lsa->header->id), + ntohl(route->path.origin.id)); + } + return 0; + } + + ospf6_vertex_delete(v); return -1; + } /* There should be no case where candidate being installed (variable @@ -438,8 +460,10 @@ void ospf6_spf_calculation(u_int32_t router_id, struct ospf6_vertex *root, *v, *w; int size; caddr_t lsdesc; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *self_rtr_lsa = NULL, *rtr_lsa = NULL; + const struct route_node *end = NULL; struct in6_addr address; + struct ospf6_lsdb *lsdb = NULL; ospf6_spf_table_finish(result_table); @@ -454,6 +478,8 @@ void ospf6_spf_calculation(u_int32_t router_id, return; } + self_rtr_lsa = lsa; + /* initialize */ candidate_list = pqueue_create(); candidate_list->cmp = ospf6_vertex_cmp; @@ -462,6 +488,7 @@ void ospf6_spf_calculation(u_int32_t router_id, root->area = oa; root->cost = 0; root->hops = 0; + root->link_id = lsa->header->id; inet_pton(AF_INET6, "::1", &address); /* Actually insert root to the candidate-list as the only candidate */ @@ -482,55 +509,134 @@ void ospf6_spf_calculation(u_int32_t router_id, && ospf6_router_is_stub_router(v->lsa))) continue; - /* For each LS description in the just-added vertex V's LSA */ - size = (VERTEX_IS_TYPE(ROUTER, v) - ? sizeof(struct ospf6_router_lsdesc) - : sizeof(struct ospf6_network_lsdesc)); - for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; - lsdesc + size <= OSPF6_LSA_END(v->lsa->header); - lsdesc += size) { - lsa = ospf6_lsdesc_lsa(lsdesc, v); - if (lsa == NULL) - continue; - - if (OSPF6_LSA_IS_MAXAGE(lsa)) - continue; - - if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) - continue; - - w = ospf6_vertex_create(lsa); - w->area = oa; - w->parent = v; - if (VERTEX_IS_TYPE(ROUTER, v)) { - w->cost = v->cost - + ROUTER_LSDESC_GET_METRIC(lsdesc); - w->hops = - v->hops - + (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1); - } else /* NETWORK */ - { - w->cost = v->cost; - w->hops = v->hops + 1; + if (VERTEX_IS_TYPE(ROUTER, v)) { + /* First fetch root Router LSAs from lsdb_self */ + if (v->lsa == self_rtr_lsa) + lsdb = oa->lsdb_self; + else + lsdb = v->area->lsdb; + + /* Iterating multiple ROUTER LSAs from same adv router + * with different Link State ID */ + end = ospf6_lsdb_head(lsdb, 2, + htons(OSPF6_LSTYPE_ROUTER), + v->lsa->header->adv_router, + &rtr_lsa); + while (rtr_lsa) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: Next LSA %s to process" + ,__PRETTY_FUNCTION__, + rtr_lsa->name); + size = sizeof(struct ospf6_router_lsdesc); + /* For each LS description in the just-added vertex V's LSA */ + for (lsdesc = OSPF6_LSA_HEADER_END( + rtr_lsa->header) + 4; + lsdesc + size <= OSPF6_LSA_END( + rtr_lsa->header); + lsdesc += size) { + lsa = ospf6_lsdesc_lsa(lsdesc, v, + rtr_lsa->header->id); + if (lsa == NULL) + continue; + + if (OSPF6_LSA_IS_MAXAGE(lsa)) + continue; + + if (!ospf6_lsdesc_backlink(lsa, + lsdesc, v)) + continue; + + w = ospf6_vertex_create(lsa); + w->area = oa; + w->parent = v; + w->link_id = rtr_lsa->header->id; + + if (VERTEX_IS_TYPE(ROUTER, v)) { + w->cost = v->cost + + ROUTER_LSDESC_GET_METRIC(lsdesc); + w->hops = + v->hops + + (VERTEX_IS_TYPE(NETWORK, w) + ? 0 : 1); + } else /* NETWORK */ { + w->cost = v->cost; + w->hops = v->hops + 1; + } + + /* nexthop calculation */ + if (w->hops == 0) + ospf6_add_nexthop(w->nh_list, + ROUTER_LSDESC_GET_IFID(lsdesc) + , NULL); + else if (w->hops == 1 && v->hops == 0) + ospf6_nexthop_calc(w, v, lsdesc); + else { + ospf6_copy_nexthops(w->nh_list, + v->nh_list); + } + + /* add new candidate to the candidate_list */ + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug( + " New candidate: %s hops %d cost %d", + w->name, w->hops, + w->cost); + pqueue_enqueue(w, candidate_list); + } + /* Fetch next Link state ID Router LSA */ + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); } - - /* nexthop calculation */ - if (w->hops == 0) - ospf6_add_nexthop( - w->nh_list, + } else { + /* For each LS description in the just-added vertex V's LSA */ + size = (VERTEX_IS_TYPE(ROUTER, v) + ? sizeof(struct ospf6_router_lsdesc) + : sizeof(struct ospf6_network_lsdesc)); + for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; + lsdesc + size <= OSPF6_LSA_END(v->lsa->header); + lsdesc += size) { + lsa = ospf6_lsdesc_lsa(lsdesc, v, v->link_id); + if (lsa == NULL) + continue; + + if (OSPF6_LSA_IS_MAXAGE(lsa)) + continue; + + if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) + continue; + + w = ospf6_vertex_create(lsa); + w->area = oa; + w->parent = v; + if (VERTEX_IS_TYPE(ROUTER, v)) { + w->cost = v->cost + + ROUTER_LSDESC_GET_METRIC(lsdesc); + w->hops = + v->hops + + (VERTEX_IS_TYPE(NETWORK, w) ? + 0 : 1); + } else /* NETWORK */ { + w->cost = v->cost; + w->hops = v->hops + 1; + } + + /* nexthop calculation */ + if (w->hops == 0) + ospf6_add_nexthop(w->nh_list, ROUTER_LSDESC_GET_IFID(lsdesc), NULL); - else if (w->hops == 1 && v->hops == 0) - ospf6_nexthop_calc(w, v, lsdesc); - else { - ospf6_copy_nexthops(w->nh_list, v->nh_list); - } - - /* add new candidate to the candidate_list */ - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug( + else if (w->hops == 1 && v->hops == 0) + ospf6_nexthop_calc(w, v, lsdesc); + else { + ospf6_copy_nexthops(w->nh_list, + v->nh_list); + } + + /* add new candidate to the candidate_list */ + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug( " New candidate: %s hops %d cost %d", - w->name, w->hops, w->cost); - pqueue_enqueue(w, candidate_list); + w->name, w->hops, w->cost); + pqueue_enqueue(w, candidate_list); + } } } diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index 2246e2dfc7..dbb88d12ba 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -68,6 +68,7 @@ struct ospf6_vertex { /* nexthops to this node */ struct list *nh_list; + uint32_t link_id; }; #define OSPF6_VERTEX_TYPE_ROUTER 0x01 diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index a900648236..cc87c499ee 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -583,7 +583,7 @@ static void ospf6_zebra_connected(struct zclient *zclient) void ospf6_zebra_init(struct thread_master *master) { /* Allocate zebra structure. */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_OSPF6, 0, &ospf6d_privs); zclient->zebra_connected = ospf6_zebra_connected; zclient->router_id_update = ospf6_router_id_update_zebra; diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 89c462693b..33461e6df8 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -127,7 +127,8 @@ int ospf_route_map_set_compare(struct route_map_set_values *values1, } /* Add an External info for AS-external-LSA. */ -struct external_info *ospf_external_info_add(u_char type, u_short instance, +struct external_info *ospf_external_info_add(struct ospf *ospf, u_char type, + u_short instance, struct prefix_ipv4 p, ifindex_t ifindex, struct in_addr nexthop, @@ -138,9 +139,9 @@ struct external_info *ospf_external_info_add(u_char type, u_short instance, struct ospf_external *ext; char inetbuf[INET6_BUFSIZ]; - ext = ospf_external_lookup(type, instance); + ext = ospf_external_lookup(ospf, type, instance); if (!ext) - ext = ospf_external_add(type, instance); + ext = ospf_external_add(ospf, type, instance); rn = route_node_get(EXTERNAL_INFO(ext), (struct prefix *)&p); /* If old info exists, -- discard new one or overwrite with new one? */ @@ -157,9 +158,10 @@ struct external_info *ospf_external_info_add(u_char type, u_short instance, inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ); zlog_warn( - "Redistribute[%s][%d]: %s/%d discarding old info with NH %s.", + "Redistribute[%s][%d][%u]: %s/%d discarding old info with NH %s.", ospf_redist_string(type), instance, - inet_ntoa(p.prefix), p.prefixlen, inetbuf); + ospf->vrf_id, inet_ntoa(p.prefix), + p.prefixlen, inetbuf); XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info); rn->info = NULL; } @@ -179,20 +181,20 @@ struct external_info *ospf_external_info_add(u_char type, u_short instance, inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ); zlog_debug( - "Redistribute[%s]: %s/%d external info created, with NH %s", - ospf_redist_string(type), inet_ntoa(p.prefix), - p.prefixlen, inetbuf); + "Redistribute[%s][%u]: %s/%d external info created, with NH %s", + ospf_redist_string(type), ospf->vrf_id, + inet_ntoa(p.prefix), p.prefixlen, inetbuf); } return new; } -void ospf_external_info_delete(u_char type, u_short instance, +void ospf_external_info_delete(struct ospf *ospf, u_char type, u_short instance, struct prefix_ipv4 p) { struct route_node *rn; struct ospf_external *ext; - ext = ospf_external_lookup(type, instance); + ext = ospf_external_lookup(ospf, type, instance); if (!ext) return; @@ -205,13 +207,14 @@ void ospf_external_info_delete(u_char type, u_short instance, } } -struct external_info *ospf_external_info_lookup(u_char type, u_short instance, +struct external_info *ospf_external_info_lookup(struct ospf *ospf, u_char type, + u_short instance, struct prefix_ipv4 *p) { struct route_node *rn; struct ospf_external *ext; - ext = ospf_external_lookup(type, instance); + ext = ospf_external_lookup(ospf, type, instance); if (!ext) return NULL; @@ -288,7 +291,7 @@ void ospf_redistribute_withdraw(struct ospf *ospf, u_char type, struct external_info *ei; struct ospf_external *ext; - ext = ospf_external_lookup(type, instance); + ext = ospf_external_lookup(ospf, type, instance); if (!ext) return; diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 3d7f14e7f2..38ed95322b 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -58,12 +58,15 @@ extern struct external_info *ospf_external_info_new(u_char, u_short); extern void ospf_reset_route_map_set_values(struct route_map_set_values *); extern int ospf_route_map_set_compare(struct route_map_set_values *, struct route_map_set_values *); -extern struct external_info *ospf_external_info_add(u_char, u_short, +extern struct external_info *ospf_external_info_add(struct ospf *, + u_char, u_short, struct prefix_ipv4, ifindex_t, struct in_addr, route_tag_t); -extern void ospf_external_info_delete(u_char, u_short, struct prefix_ipv4); -extern struct external_info *ospf_external_info_lookup(u_char, u_short, +extern void ospf_external_info_delete(struct ospf*, u_char, u_short, + struct prefix_ipv4); +extern struct external_info *ospf_external_info_lookup(struct ospf*, u_char, + u_short, struct prefix_ipv4 *); extern struct ospf_route *ospf_external_route_lookup(struct ospf *, struct prefix_ipv4 *); diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index facce9aafd..36b6d5143d 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -108,7 +108,7 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, struct listnode *node; struct ospf_external *ext; - ext_list = om->external[type]; + ext_list = ospf->external[type]; if (!ext_list) continue; diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index fc866df965..c28e500d5b 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2037,7 +2037,7 @@ int ospf_external_lsa_originate_timer(struct thread *thread) ospf->t_external_lsa = NULL; - ext_list = om->external[type]; + ext_list = ospf->external[type]; if (!ext_list) return 0; @@ -2077,7 +2077,7 @@ static struct external_info *ospf_default_external_info(struct ospf *ospf) if (type == ZEBRA_ROUTE_OSPF) continue; - ext_list = om->external[type]; + ext_list = ospf->external[type]; if (!ext_list) continue; @@ -2114,7 +2114,8 @@ int ospf_default_originate_timer(struct thread *thread) /* If there is no default route via redistribute, then originate AS-external-LSA with nexthop 0 (self). */ nexthop.s_addr = 0; - ospf_external_info_add(DEFAULT_ROUTE, 0, p, 0, nexthop, 0); + ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, + nexthop, 0); } if ((ei = ospf_default_external_info(ospf))) @@ -2245,25 +2246,32 @@ void ospf_external_lsa_refresh_type(struct ospf *ospf, u_char type, struct external_info *ei; struct ospf_external *ext; - if (type != DEFAULT_ROUTE) - if ((ext = ospf_external_lookup(type, instance)) - && EXTERNAL_INFO(ext)) - /* Refresh each redistributed AS-external-LSAs. */ - for (rn = route_top(EXTERNAL_INFO(ext)); rn; - rn = route_next(rn)) - if ((ei = rn->info)) - if (!is_prefix_default(&ei->p)) { - struct ospf_lsa *lsa; - - if ((lsa = ospf_external_info_find_lsa( - ospf, &ei->p))) - ospf_external_lsa_refresh( - ospf, lsa, ei, - force); - else - ospf_external_lsa_originate( - ospf, ei); - } + if (type == DEFAULT_ROUTE) + return; + + ext = ospf_external_lookup(ospf, type, instance); + + if (ext && EXTERNAL_INFO(ext)) { + /* Refresh each redistributed AS-external-LSAs. */ + for (rn = route_top(EXTERNAL_INFO(ext)); rn; + rn = route_next(rn)) { + ei = rn->info; + if (ei) { + if (!is_prefix_default(&ei->p)) { + struct ospf_lsa *lsa; + + lsa = ospf_external_info_find_lsa(ospf, + &ei->p); + if (lsa) + ospf_external_lsa_refresh(ospf, + lsa, ei, force); + else + ospf_external_lsa_originate(ospf + , ei); + } + } + } + } } /* Refresh AS-external-LSA. */ diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index a49143873e..f1848f1eaf 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -201,6 +201,9 @@ DEFUN_NOSH (router_ospf, struct ospf *ospf = NULL; int ret = CMD_SUCCESS; u_short instance = 0; + struct vrf *vrf = NULL; + struct route_node *rn; + struct interface *ifp; ospf = ospf_cmd_lookup_ospf(vty, argv, argc, 1, &instance); if (!ospf) @@ -219,6 +222,34 @@ DEFUN_NOSH (router_ospf, instance, ospf->name ? ospf->name : "NIL", ospf->vrf_id, ospf->oi_running); VTY_PUSH_CONTEXT(OSPF_NODE, ospf); + + /* Activate 'ip ospf area x' configured interfaces for given + * vrf. Activate area on vrf x aware interfaces. + * vrf_enable callback calls router_id_update which + * internally will call ospf_if_update to trigger + * network_run_state + */ + vrf = vrf_lookup_by_id(ospf->vrf_id); + + FOR_ALL_INTERFACES (vrf, ifp) { + struct ospf_if_params *params; + + params = IF_DEF_PARAMS(ifp); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { + for (rn = route_top(ospf->networks); rn; + rn = route_next(rn)) { + if (rn->info != NULL) { + vty_out(vty, + "Interface %s has area config but please remove all network commands first.\n", + ifp->name); + return ret; + } + } + ospf_interface_area_set(ospf, ifp); + ospf->if_ospf_cli_count++; + } + } + ospf_router_id_update(ospf); } @@ -570,6 +601,11 @@ DEFUN (ospf_network_area, if (ospf->if_ospf_cli_count > 0) { vty_out(vty, "Please remove all ip ospf area x.x.x.x commands first.\n"); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s ospf vrf %s num of %u ip osp area x config", + __PRETTY_FUNCTION__, + ospf->name ? ospf->name : "NIL", + ospf->if_ospf_cli_count); return CMD_WARNING_CONFIG_FAILED; } @@ -1541,7 +1577,7 @@ DEFUN (ospf_area_nssa, "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n") { - return ospf_area_nssa_cmd_handler(vty, argc, argv, 1, 0); + return ospf_area_nssa_cmd_handler(vty, argc, argv, 0, 0); } DEFUN (ospf_area_nssa_no_summary, @@ -7926,7 +7962,7 @@ DEFUN (ip_ospf_area, else ospf = ospf_lookup_instance(instance); - if (ospf == NULL) { + if (instance && ospf == NULL) { params = IF_DEF_PARAMS(ifp); if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { UNSET_IF_PARAM(params, if_area); @@ -7971,11 +8007,13 @@ DEFUN (ip_ospf_area, ospf_if_update_params((ifp), (addr)); } - for (rn = route_top(ospf->networks); rn; rn = route_next(rn)) { - if (rn->info != NULL) { - vty_out(vty, - "Please remove all network commands first.\n"); - return CMD_WARNING_CONFIG_FAILED; + if (ospf) { + for (rn = route_top(ospf->networks); rn; rn = route_next(rn)) { + if (rn->info != NULL) { + vty_out(vty, + "Please remove all network commands first.\n"); + return CMD_WARNING_CONFIG_FAILED; + } } } @@ -7985,8 +8023,11 @@ DEFUN (ip_ospf_area, params->if_area = area_id; params->if_area_id_fmt = format; } - ospf_interface_area_set(ospf, ifp); - ospf->if_ospf_cli_count++; + + if (ospf) { + ospf_interface_area_set(ospf, ifp); + ospf->if_ospf_cli_count++; + } return CMD_SUCCESS; } @@ -8361,10 +8402,10 @@ DEFUN (no_ospf_default_information_originate, ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); - if ((ext = ospf_external_lookup(DEFAULT_ROUTE, 0)) - && EXTERNAL_INFO(ext)) { - ospf_external_info_delete(DEFAULT_ROUTE, 0, p); - ospf_external_del(DEFAULT_ROUTE, 0); + ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0); + if (ext && EXTERNAL_INFO(ext)) { + ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p); + ospf_external_del(ospf, DEFAULT_ROUTE, 0); } red = ospf_redist_lookup(ospf, DEFAULT_ROUTE, 0); @@ -8828,188 +8869,438 @@ static void config_write_stub_router(struct vty *vty, struct ospf *ospf) } static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf, - struct route_table *rt) + struct route_table *rt, + json_object *json) { struct route_node *rn; struct ospf_route * or ; struct listnode *pnode, *pnnode; struct ospf_path *path; + json_object *json_route = NULL, *json_nexthop_array = NULL, + *json_nexthop = NULL; - vty_out(vty, "============ OSPF network routing table ============\n"); + if (!json) + vty_out(vty, "============ OSPF network routing table ============\n"); - for (rn = route_top(rt); rn; rn = route_next(rn)) - if ((or = rn->info) != NULL) { - char buf1[19]; - snprintf(buf1, 19, "%s/%d", inet_ntoa(rn->p.u.prefix4), - rn->p.prefixlen); - - switch (or->path_type) { - case OSPF_PATH_INTER_AREA: - if (or->type == OSPF_DESTINATION_NETWORK) + for (rn = route_top(rt); rn; rn = route_next(rn)) { + if ((or = rn->info) == NULL) + continue; + char buf1[PREFIX2STR_BUFFER]; + + memset(buf1, 0, sizeof(buf1)); + prefix2str(&rn->p, buf1, sizeof(buf1)); + + json_route = json_object_new_object(); + if (json) { + json_object_object_add(json, buf1, json_route); + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_NOSLASHESCAPE); + + } + + switch (or->path_type) { + case OSPF_PATH_INTER_AREA: + if (or->type == OSPF_DESTINATION_NETWORK) { + if (json) { + json_object_string_add(json_route, + "routeType", + "N IA"); + json_object_int_add(json_route, + "cost", + or->cost); + json_object_string_add( + json_route, + "area", + inet_ntoa( + or->u.std.area_id)); + } else { vty_out(vty, - "N IA %-18s [%d] area: %s\n", + "N IA %-18s [%d] area: %s\n", buf1, or->cost, - inet_ntoa(or->u.std.area_id)); - else if (or->type == OSPF_DESTINATION_DISCARD) + inet_ntoa(or->u.std.area_id)); + } + } else if (or->type == + OSPF_DESTINATION_DISCARD) { + if (json) { + json_object_string_add(json_route, + "routeType", + "D IA"); + } else { vty_out(vty, "D IA %-18s Discard entry\n", buf1); - break; - case OSPF_PATH_INTRA_AREA: + } + } + break; + case OSPF_PATH_INTRA_AREA: + if (json) { + json_object_string_add(json_route, + "routeType", "N"); + json_object_int_add(json_route, "cost", + or->cost); + json_object_string_add(json_route, + "area", inet_ntoa(or->u.std.area_id)); + } else { vty_out(vty, "N %-18s [%d] area: %s\n", buf1, or->cost, inet_ntoa(or->u.std.area_id)); - break; - default: - break; } + break; + default: + break; + } - if (or->type == OSPF_DESTINATION_NETWORK) - for (ALL_LIST_ELEMENTS(or->paths, pnode, pnnode, - path)) { - if (if_lookup_by_index(path->ifindex, - ospf->vrf_id)) { - if (path->nexthop.s_addr == 0) - vty_out(vty, - "%24s directly attached to %s\n", - "", + if (or->type == OSPF_DESTINATION_NETWORK) { + if (json) { + json_nexthop_array = json_object_new_array(); + json_object_object_add(json_route, "nexthops", + json_nexthop_array); + } + + for (ALL_LIST_ELEMENTS(or->paths, pnode, pnnode, + path)) { + if (json) { + json_nexthop = + json_object_new_object(); + json_object_array_add(json_nexthop_array, + json_nexthop); + } + if (if_lookup_by_index(path->ifindex, + ospf->vrf_id)) { + + if (path->nexthop.s_addr == 0) { + if (json) { + json_object_string_add( + json_nexthop, + "ip", + " "); + json_object_string_add( + json_nexthop, + "directly attached to", ifindex2ifname( - path->ifindex, - ospf->vrf_id)); - else + path->ifindex, + ospf->vrf_id)); + } else { vty_out(vty, - "%24s via %s, %s\n", - "", + "%24s directly attached to %s\n", + "", + ifindex2ifname( + path->ifindex, + ospf->vrf_id)); + } + } else { + if (json) { + json_object_string_add( + json_nexthop, + "ip", inet_ntoa( - path->nexthop), + path->nexthop)); + json_object_string_add( + json_nexthop, + "via", ifindex2ifname( - path->ifindex, - ospf->vrf_id)); + path->ifindex, + ospf->vrf_id)); + } else { + vty_out(vty, + "%24s via %s, %s\n", + "", + inet_ntoa( + path->nexthop), + ifindex2ifname( + path->ifindex, + ospf->vrf_id)); + } } } + } } - vty_out(vty, "\n"); + if (!json) + json_object_free(json_route); + } + if (!json) + vty_out(vty, "\n"); } static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf, - struct route_table *rtrs) + struct route_table *rtrs, + json_object *json) { struct route_node *rn; struct ospf_route * or ; struct listnode *pnode; struct listnode *node; struct ospf_path *path; + json_object *json_route = NULL, *json_nexthop_array = NULL, + *json_nexthop = NULL; - vty_out(vty, "============ OSPF router routing table =============\n"); - for (rn = route_top(rtrs); rn; rn = route_next(rn)) - if (rn->info) { - int flag = 0; + if (!json) + vty_out(vty, "============ OSPF router routing table =============\n"); + + for (rn = route_top(rtrs); rn; rn = route_next(rn)) { + if (rn->info == NULL) + continue; + int flag = 0; + json_route = json_object_new_object(); + if (json) { + json_object_object_add(json, + inet_ntoa(rn->p.u.prefix4), + json_route); + json_object_string_add(json_route, "routeType", + "R "); + } else { vty_out(vty, "R %-15s ", inet_ntoa(rn->p.u.prefix4)); + } - for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, - or)) { - if (flag++) + for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node, + or)) { + if (flag++) { + if (!json) vty_out(vty, "%24s", ""); + } - /* Show path. */ + /* Show path. */ + if (json) { + json_object_int_add(json_route, "cost", + or->cost); + json_object_string_add(json_route, + "area", + inet_ntoa(or->u.std.area_id)); + if (or->path_type == + OSPF_PATH_INTER_AREA) + json_object_boolean_true_add( + json_route, + "IA"); + if (or->u.std.flags & ROUTER_LSA_BORDER) + json_object_string_add( + json_route, + "routerType", + "abr"); + else if (or->u.std.flags & + ROUTER_LSA_EXTERNAL) + json_object_string_add( + json_route, + "routerType", + "asbr"); + } else { vty_out(vty, "%s [%d] area: %s", - (or->path_type == OSPF_PATH_INTER_AREA - ? "IA" - : " "), - or->cost, inet_ntoa(or->u.std.area_id)); + (or->path_type == OSPF_PATH_INTER_AREA + ? "IA" + : " "), + or->cost, inet_ntoa(or->u.std.area_id)); /* Show flags. */ vty_out(vty, "%s%s\n", - (or->u.std.flags & ROUTER_LSA_BORDER - ? ", ABR" - : ""), - (or->u.std.flags & ROUTER_LSA_EXTERNAL - ? ", ASBR" - : "")); - - for (ALL_LIST_ELEMENTS_RO(or->paths, pnode, - path)) { - if (if_lookup_by_index(path->ifindex, - ospf->vrf_id)) { - if (path->nexthop.s_addr == 0) - vty_out(vty, - "%24s directly attached to %s\n", - "", + (or->u.std.flags & ROUTER_LSA_BORDER + ? ", ABR" + : ""), + (or->u.std.flags & ROUTER_LSA_EXTERNAL + ? ", ASBR" + : "")); + } + + if (json) { + json_nexthop_array = + json_object_new_array(); + json_object_object_add(json_route, "nexthops", + json_nexthop_array); + } + + for (ALL_LIST_ELEMENTS_RO(or->paths, pnode, + path)) { + if (json) { + json_nexthop = + json_object_new_object(); + json_object_array_add( + json_nexthop_array, + json_nexthop); + } + if (if_lookup_by_index(path->ifindex, + ospf->vrf_id)) { + if (path->nexthop.s_addr == 0) { + if (json) { + json_object_string_add( + json_nexthop, + "ip", + " "); + json_object_string_add( + json_nexthop, + "directly attached to", ifindex2ifname( path->ifindex, ospf->vrf_id)); - else + } else { vty_out(vty, - "%24s via %s, %s\n", - "", - inet_ntoa( - path->nexthop), + "%24s directly attached to %s\n", + "", + ifindex2ifname( + path->ifindex, + ospf->vrf_id)); + } + } else { + if (json) { + json_object_string_add( + json_nexthop, + "ip", + inet_ntoa(path->nexthop)); + json_object_string_add( + json_nexthop, + "via", ifindex2ifname( path->ifindex, ospf->vrf_id)); + } else { + vty_out(vty, + "%24s via %s, %s\n", + "", + inet_ntoa( + path->nexthop), + ifindex2ifname( + path->ifindex, + ospf->vrf_id)); + } } } } } - vty_out(vty, "\n"); + if (!json) + json_object_free(json_route); + } + if (!json) + vty_out(vty, "\n"); } static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf, - struct route_table *rt) + struct route_table *rt, + json_object *json) { struct route_node *rn; struct ospf_route *er; struct listnode *pnode, *pnnode; struct ospf_path *path; + json_object *json_route = NULL, *json_nexthop_array = NULL, + *json_nexthop = NULL; - vty_out(vty, "============ OSPF external routing table ===========\n"); - for (rn = route_top(rt); rn; rn = route_next(rn)) - if ((er = rn->info) != NULL) { - char buf1[19]; - snprintf(buf1, 19, "%s/%d", inet_ntoa(rn->p.u.prefix4), - rn->p.prefixlen); + if (!json) + vty_out(vty, "============ OSPF external routing table ===========\n"); + + for (rn = route_top(rt); rn; rn = route_next(rn)) { + if ((er = rn->info) == NULL) + continue; + + char buf1[19]; - switch (er->path_type) { - case OSPF_PATH_TYPE1_EXTERNAL: + snprintf(buf1, 19, "%s/%d", inet_ntoa(rn->p.u.prefix4), + rn->p.prefixlen); + json_route = json_object_new_object(); + if (json) { + json_object_object_add(json, buf1, json_route); + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_NOSLASHESCAPE); + + } + + switch (er->path_type) { + case OSPF_PATH_TYPE1_EXTERNAL: + if (json) { + json_object_string_add(json_route, + "routeType", + "N E1"); + json_object_int_add(json_route, "cost", + er->cost); + } else { vty_out(vty, - "N E1 %-18s [%d] tag: %" ROUTE_TAG_PRI - "\n", - buf1, er->cost, er->u.ext.tag); - break; - case OSPF_PATH_TYPE2_EXTERNAL: + "N E1 %-18s [%d] tag: %" ROUTE_TAG_PRI + "\n", + buf1, er->cost, er->u.ext.tag); + } + break; + case OSPF_PATH_TYPE2_EXTERNAL: + if (json) { + json_object_string_add(json_route, + "routeType", + "N E2"); + json_object_int_add(json_route, "cost", + er->cost); + } else { vty_out(vty, - "N E2 %-18s [%d/%d] tag: %" ROUTE_TAG_PRI - "\n", - buf1, er->cost, er->u.ext.type2_cost, + "N E2 %-18s [%d/%d] tag: %" + ROUTE_TAG_PRI + "\n", buf1, er->cost, + er->u.ext.type2_cost, er->u.ext.tag); - break; } + break; + } - for (ALL_LIST_ELEMENTS(er->paths, pnode, pnnode, - path)) { - if (if_lookup_by_index(path->ifindex, - ospf->vrf_id)) { - if (path->nexthop.s_addr == 0) - vty_out(vty, - "%24s directly attached to %s\n", - "", + if (json) { + json_nexthop_array = json_object_new_array(); + json_object_object_add(json_route, "nexthops", + json_nexthop_array); + } + + for (ALL_LIST_ELEMENTS(er->paths, pnode, pnnode, + path)) { + if (json) { + json_nexthop = json_object_new_object(); + json_object_array_add(json_nexthop_array + ,json_nexthop); + } + + if (if_lookup_by_index(path->ifindex, + ospf->vrf_id)) { + if (path->nexthop.s_addr == 0) { + if (json) { + json_object_string_add( + json_nexthop, + "ip", + " "); + json_object_string_add( + json_nexthop, + "directly attached to", ifindex2ifname( - path->ifindex, - ospf->vrf_id)); - else + path->ifindex, + ospf->vrf_id)); + } else { vty_out(vty, - "%24s via %s, %s\n", - "", + "%24s directly attached to %s\n", + "", + ifindex2ifname( + path->ifindex, + ospf->vrf_id)); + } + } else { + if (json) { + json_object_string_add( + json_nexthop, + "ip", inet_ntoa( - path->nexthop), + path->nexthop)); + json_object_string_add( + json_nexthop, + "via", ifindex2ifname( - path->ifindex, - ospf->vrf_id)); + path->ifindex, + ospf->vrf_id)); + } else { + vty_out(vty, + "%24s via %s, %s\n", + "", + inet_ntoa( + path->nexthop), + ifindex2ifname( + path->ifindex, + ospf->vrf_id)); + } } } } - vty_out(vty, "\n"); + if (!json) + json_object_free(json_route); + } + if (!json) + vty_out(vty, "\n"); } static int show_ip_ospf_border_routers_common(struct vty *vty, @@ -9030,7 +9321,7 @@ static int show_ip_ospf_border_routers_common(struct vty *vty, show_ip_ospf_route_network (vty, ospf->new_table); */ /* Show Router routes. */ - show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs); + show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, NULL); vty_out(vty, "\n"); @@ -9113,12 +9404,22 @@ DEFUN (show_ip_ospf_instance_border_routers, } static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf, - u_char use_vrf) + json_object *json, u_char use_vrf) { + json_object *json_vrf = NULL; + if (ospf->instance) vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); - ospf_show_vrf_name(ospf, vty, NULL, use_vrf); + + if (json) { + if (use_vrf) + json_vrf = json_object_new_object(); + else + json_vrf = json; + } + + ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); if (ospf->new_table == NULL) { vty_out(vty, "No OSPF routing information exist\n"); @@ -9126,28 +9427,42 @@ static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf, } /* Show Network routes. */ - show_ip_ospf_route_network(vty, ospf, ospf->new_table); + show_ip_ospf_route_network(vty, ospf, ospf->new_table, json_vrf); /* Show Router routes. */ - show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs); + show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, json_vrf); /* Show AS External routes. */ - show_ip_ospf_route_external(vty, ospf, ospf->old_external_route); + show_ip_ospf_route_external(vty, ospf, ospf->old_external_route, + json_vrf); - vty_out(vty, "\n"); + if (json) { + if (use_vrf) { + //json_object_object_add(json_vrf, "areas", json_areas); + if (ospf->vrf_id == VRF_DEFAULT) + json_object_object_add(json, "default", + json_vrf); + else + json_object_object_add(json, ospf->name, + json_vrf); + } + } else { + vty_out(vty, "\n"); + } return CMD_SUCCESS; } DEFUN (show_ip_ospf_route, show_ip_ospf_route_cmd, - "show ip ospf [vrf <NAME|all>] route", + "show ip ospf [vrf <NAME|all>] route [json]", SHOW_STR IP_STR "OSPF information\n" VRF_CMD_HELP_STR "All VRFs\n" - "OSPF routing table\n") + "OSPF routing table\n" + JSON_STR) { struct ospf *ospf = NULL; struct listnode *node = NULL; @@ -9157,6 +9472,11 @@ DEFUN (show_ip_ospf_route, int inst = 0; int idx_vrf = 0; u_char use_vrf = 0; + u_char uj = use_json(argc, argv); + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); @@ -9167,23 +9487,44 @@ DEFUN (show_ip_ospf_route, for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { if (!ospf->oi_running) continue; - ret = show_ip_ospf_route_common(vty, ospf, + ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf); } + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return ret; } ospf = ospf_lookup_by_inst_name(inst, vrf_name); - if (ospf == NULL || !ospf->oi_running) + if (ospf == NULL || !ospf->oi_running) { + if (uj) + json_object_free(json); return CMD_SUCCESS; + } } else { /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if (ospf == NULL || !ospf->oi_running) + if (ospf == NULL || !ospf->oi_running) { + if (uj) + json_object_free(json); return CMD_SUCCESS; + } + } + + if (ospf) { + ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf); + if (uj) + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); } - if (ospf) - ret = show_ip_ospf_route_common(vty, ospf, use_vrf); + if (uj) + json_object_free(json); return ret; } @@ -9209,7 +9550,7 @@ DEFUN (show_ip_ospf_instance_route, if (!ospf->oi_running) return CMD_SUCCESS; - return show_ip_ospf_route_common(vty, ospf, 0); + return show_ip_ospf_route_common(vty, ospf, NULL, 0); } @@ -9633,6 +9974,9 @@ static int config_write_ospf_area(struct vty *vty, struct ospf *ospf) " area %s nssa translate-always\n", buf); break; + case OSPF_NSSA_ROLE_CANDIDATE: + vty_out(vty, " area %s nssa \n", buf); + break; } if (area->no_summary) vty_out(vty, @@ -10061,7 +10405,14 @@ static int ospf_config_write(struct vty *vty) return write; for (ALL_LIST_ELEMENTS_RO(om->ospf, ospf_node, ospf)) { - if (ospf->oi_running) + /* VRF Default check if it is running. + * Upon daemon start, there could be default instance + * in absence of 'router ospf'/oi_running is disabled. */ + if (ospf->vrf_id == VRF_DEFAULT && ospf->oi_running) + write += ospf_config_write_one(vty, ospf); + /* For Non-Default VRF simply display the configuration, + * even if it is not oi_running. */ + else if (ospf->vrf_id != VRF_DEFAULT) write += ospf_config_write_one(vty, ospf); } return write; diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index d7fe0edcbf..66be29dbb4 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -519,13 +519,14 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p) inet_ntoa(p->prefix), p->prefixlen); } -struct ospf_external *ospf_external_lookup(u_char type, u_short instance) +struct ospf_external *ospf_external_lookup(struct ospf *ospf, u_char type, + u_short instance) { struct list *ext_list; struct listnode *node; struct ospf_external *ext; - ext_list = om->external[type]; + ext_list = ospf->external[type]; if (!ext_list) return (NULL); @@ -536,19 +537,20 @@ struct ospf_external *ospf_external_lookup(u_char type, u_short instance) return NULL; } -struct ospf_external *ospf_external_add(u_char type, u_short instance) +struct ospf_external *ospf_external_add(struct ospf *ospf, u_char type, + u_short instance) { struct list *ext_list; struct ospf_external *ext; - ext = ospf_external_lookup(type, instance); + ext = ospf_external_lookup(ospf, type, instance); if (ext) return ext; - if (!om->external[type]) - om->external[type] = list_new(); + if (!ospf->external[type]) + ospf->external[type] = list_new(); - ext_list = om->external[type]; + ext_list = ospf->external[type]; ext = (struct ospf_external *)XCALLOC(MTYPE_OSPF_EXTERNAL, sizeof(struct ospf_external)); ext->instance = instance; @@ -559,20 +561,21 @@ struct ospf_external *ospf_external_add(u_char type, u_short instance) return ext; } -void ospf_external_del(u_char type, u_short instance) +void ospf_external_del(struct ospf *ospf, u_char type, u_short instance) { struct ospf_external *ext; - ext = ospf_external_lookup(type, instance); + ext = ospf_external_lookup(ospf, type, instance); if (ext) { if (EXTERNAL_INFO(ext)) route_table_finish(EXTERNAL_INFO(ext)); - listnode_delete(om->external[type], ext); - if (!om->external[type]->count) { - list_delete_and_null(&om->external[type]); - } + listnode_delete(ospf->external[type], ext); + + if (!ospf->external[type]->count) + list_delete_and_null(&ospf->external[type]); + XFREE(MTYPE_OSPF_EXTERNAL, ext); } } @@ -684,7 +687,7 @@ int ospf_redistribute_set(struct ospf *ospf, int type, u_short instance, red->dmetric.type = mtype; red->dmetric.value = mvalue; - ospf_external_add(type, instance); + ospf_external_add(ospf, type, instance); zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, instance, ospf->vrf_id); @@ -720,7 +723,7 @@ int ospf_redistribute_unset(struct ospf *ospf, int type, u_short instance) /* Remove the routes from OSPF table. */ ospf_redistribute_withdraw(ospf, type, instance); - ospf_external_del(type, instance); + ospf_external_del(ospf, type, instance); ospf_asbr_status_update(ospf, --ospf->redistribute); @@ -738,7 +741,7 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, red->dmetric.type = mtype; red->dmetric.value = mvalue; - ospf_external_add(DEFAULT_ROUTE, 0); + ospf_external_add(ospf, DEFAULT_ROUTE, 0); if (ospf_is_type_redistributed(ospf, DEFAULT_ROUTE, 0)) { /* if ospf->default_originate changes value, is calling @@ -963,10 +966,11 @@ static int ospf_zebra_read_route(int command, struct zclient *zclient, */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != api.type) - ospf_external_info_delete(i, api.instance, p); + ospf_external_info_delete(ospf, i, + api.instance, p); - ei = ospf_external_info_add(api.type, api.instance, p, ifindex, - nexthop, api.tag); + ei = ospf_external_info_add(ospf, api.type, api.instance, p, + ifindex, nexthop, api.tag); if (ei == NULL) { /* Nothing has changed, so nothing to do; return */ return 0; @@ -1004,7 +1008,7 @@ static int ospf_zebra_read_route(int command, struct zclient *zclient, } } else /* if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */ { - ospf_external_info_delete(api.type, api.instance, p); + ospf_external_info_delete(ospf, api.type, api.instance, p); if (is_prefix_default(&p)) ospf_external_lsa_refresh_default(ospf); else @@ -1087,7 +1091,7 @@ static int ospf_distribute_list_update_timer(struct thread *thread) struct listnode *node; struct ospf_external *ext; - ext_list = om->external[type]; + ext_list = ospf->external[type]; if (!ext_list) continue; @@ -1130,7 +1134,7 @@ void ospf_distribute_list_update(struct ospf *ospf, int type, args[1] = (void *)((ptrdiff_t) type); /* External info does not exist. */ - ext = ospf_external_lookup(type, instance); + ext = ospf_external_lookup(ospf, type, instance); if (!ext || !(rt = EXTERNAL_INFO(ext))) { XFREE(MTYPE_OSPF_DIST_ARGS, args); return; @@ -1471,7 +1475,7 @@ static void ospf_zebra_connected(struct zclient *zclient) void ospf_zebra_init(struct thread_master *master, u_short instance) { /* Allocate zebra structure. */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_OSPF, instance, &ospfd_privs); zclient->zebra_connected = ospf_zebra_connected; zclient->router_id_update = ospf_router_id_update_zebra; diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index 8340f49ede..d4b00dddff 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -59,9 +59,10 @@ extern int ospf_is_type_redistributed(struct ospf *, int, u_short); extern void ospf_distance_reset(struct ospf *); extern u_char ospf_distance_apply(struct ospf *ospf, struct prefix_ipv4 *, struct ospf_route *); -extern struct ospf_external *ospf_external_lookup(u_char, u_short); -extern struct ospf_external *ospf_external_add(u_char, u_short); -extern void ospf_external_del(u_char, u_short); +extern struct ospf_external *ospf_external_lookup(struct ospf*, u_char, + u_short); +extern struct ospf_external *ospf_external_add(struct ospf*, u_char, u_short); +extern void ospf_external_del(struct ospf *, u_char, u_short); extern struct ospf_redist *ospf_redist_lookup(struct ospf *, u_char, u_short); extern struct ospf_redist *ospf_redist_add(struct ospf *, u_char, u_short); extern void ospf_redist_del(struct ospf *, u_char, u_short); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a37867fe23..ceb8440eeb 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -741,7 +741,7 @@ static void ospf_finish_final(struct ospf *ospf) struct listnode *node; struct ospf_external *ext; - ext_list = om->external[i]; + ext_list = ospf->external[i]; if (!ext_list) continue; @@ -970,34 +970,37 @@ static void update_redistributed(struct ospf *ospf, int add_to_ospf) struct external_info *ei; struct ospf_external *ext; - if (ospf_is_type_redistributed(ospf, ZEBRA_ROUTE_CONNECT, 0)) - if ((ext = ospf_external_lookup(ZEBRA_ROUTE_CONNECT, 0)) - && EXTERNAL_INFO(ext)) { + if (ospf_is_type_redistributed(ospf, ZEBRA_ROUTE_CONNECT, 0)) { + ext = ospf_external_lookup(ospf, ZEBRA_ROUTE_CONNECT, 0); + if ((ext) && EXTERNAL_INFO(ext)) { for (rn = route_top(EXTERNAL_INFO(ext)); rn; rn = route_next(rn)) { - if ((ei = rn->info) != NULL) { - if (add_to_ospf) { - if (ospf_external_info_find_lsa( - ospf, &ei->p)) - if (!ospf_distribute_check_connected( - ospf, ei)) - ospf_external_lsa_flush( - ospf, - ei->type, - &ei->p, - ei->ifindex /*, ei->nexthop */); - } else { - if (!ospf_external_info_find_lsa( - ospf, &ei->p)) - if (ospf_distribute_check_connected( - ospf, ei)) - ospf_external_lsa_originate( - ospf, - ei); - } + ei = rn->info; + if (ei == NULL) + continue; + + if (add_to_ospf) { + if (ospf_external_info_find_lsa( + ospf, &ei->p)) + if (!ospf_distribute_check_connected( + ospf, ei)) + ospf_external_lsa_flush( + ospf, + ei->type, + &ei->p, + ei->ifindex /*, ei->nexthop */); + } else { + if (!ospf_external_info_find_lsa( + ospf, &ei->p)) + if (ospf_distribute_check_connected( + ospf, ei)) + ospf_external_lsa_originate( + ospf, + ei); } } } + } } /* Config network statement related functions. */ diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 6cccccc649..5cb8ca85bc 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -93,11 +93,6 @@ struct ospf_master { /* OSPF thread master. */ struct thread_master *master; - - /* Redistributed external information. */ - struct list *external[ZEBRA_ROUTE_MAX + 1]; -#define EXTERNAL_INFO(E) (E->external_info) - /* Various OSPF global configuration. */ u_char options; #define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ @@ -305,7 +300,9 @@ struct ospf { /* Statistics for LSA used for new instantiation. */ u_int32_t rx_lsa_count; - /* Counter of "ip ospf area x.x.x.x" */ + /* Counter of "ip ospf area x.x.x.x" used + * for multual exclusion of network command under + * router ospf or ip ospf area x under interface. */ u_int32_t if_ospf_cli_count; struct route_table *distance_table; @@ -314,6 +311,10 @@ struct ospf { * update to neighbors immediatly */ uint8_t inst_shutdown; + /* Redistributed external information. */ + struct list *external[ZEBRA_ROUTE_MAX + 1]; +#define EXTERNAL_INFO(E) (E->external_info) + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(ospf) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 04466258bb..689e9a7449 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -748,7 +748,7 @@ void pim_zebra_init(void) int i; /* Socket for receiving updates from Zebra daemon */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient->zebra_connected = pim_zebra_connected; zclient->router_id_update = pim_router_id_update_zebra; diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index fd75a699b3..bcaf4a38dd 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -120,7 +120,7 @@ void zclient_lookup_free(void) void zclient_lookup_new(void) { - zlookup = zclient_new(master); + zlookup = zclient_new_notify(master, &zclient_options_default); if (!zlookup) { zlog_err("%s: zclient_new() failure", __PRETTY_FUNCTION__); return; diff --git a/redhat/daemons b/redhat/daemons index c163f4d2ce..889e288e57 100644 --- a/redhat/daemons +++ b/redhat/daemons @@ -49,6 +49,7 @@ pimd=no nhrpd=no eigrpd=no babeld=no +sharpd=no # # Command line options for the daemons # @@ -64,6 +65,7 @@ pimd_options=("-A 127.0.0.1") nhrpd_options=("-A 127.0.0.1") eigrpd_options=("-A 127.0.0.1") babeld_options=("-A 127.0.0.1") +sharpd_options=("-A 127.0.0.1") # # If the vtysh_enable is yes, then the unified config is read diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index e479e2474d..041635e153 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -590,7 +590,7 @@ static void rip_zebra_connected(struct zclient *zclient) void rip_zclient_init(struct thread_master *master) { /* Set default value to the zebra client structure. */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_RIP, 0, &ripd_privs); zclient->zebra_connected = rip_zebra_connected; zclient->interface_add = rip_interface_add; diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 084d58ee53..18a8d14f09 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -413,7 +413,7 @@ static void ripng_zebra_connected(struct zclient *zclient) void zebra_init(struct thread_master *master) { /* Allocate zebra structure. */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient_init(zclient, ZEBRA_ROUTE_RIPNG, 0, &ripngd_privs); zclient->zebra_connected = ripng_zebra_connected; diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c new file mode 100644 index 0000000000..1c80cf055a --- /dev/null +++ b/sharpd/sharp_main.c @@ -0,0 +1,162 @@ +/* + * SHARP - main code + * Copyright (C) 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 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 <zebra.h> + +#include <lib/version.h> +#include "getopt.h" +#include "thread.h" +#include "prefix.h" +#include "linklist.h" +#include "if.h" +#include "vector.h" +#include "vty.h" +#include "command.h" +#include "filter.h" +#include "plist.h" +#include "stream.h" +#include "log.h" +#include "memory.h" +#include "privs.h" +#include "sigevent.h" +#include "zclient.h" +#include "keychain.h" +#include "distribute.h" +#include "libfrr.h" +#include "routemap.h" + +#include "sharp_zebra.h" +#include "sharp_vty.h" + +uint32_t total_routes = 0; +uint32_t installed_routes = 0; +uint32_t removed_routes = 0; + +zebra_capabilities_t _caps_p[] = { + ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, +}; + +struct zebra_privs_t sharp_privs = { +#if defined(FRR_USER) && defined(FRR_GROUP) + .user = FRR_USER, + .group = FRR_GROUP, +#endif +#if defined(VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0}; + +struct option longopts[] = {{0}}; + +/* Master of threads. */ +struct thread_master *master; + +/* SIGHUP handler. */ +static void sighup(void) +{ + zlog_info("SIGHUP received"); +} + +/* SIGINT / SIGTERM handler. */ +static void sigint(void) +{ + zlog_notice("Terminating on signal"); + + exit(0); +} + +/* SIGUSR1 handler. */ +static void sigusr1(void) +{ + zlog_rotate(); +} + +struct quagga_signal_t sharp_signals[] = { + { + .signal = SIGHUP, + .handler = &sighup, + }, + { + .signal = SIGUSR1, + .handler = &sigusr1, + }, + { + .signal = SIGINT, + .handler = &sigint, + }, + { + .signal = SIGTERM, + .handler = &sigint, + }, +}; + +#define SHARP_VTY_PORT 2614 + +FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT, + + .proghelp = "Implementation of a Sharp of routes daemon.", + + .signals = sharp_signals, + .n_signals = array_size(sharp_signals), + + .privs = &sharp_privs, ) + +extern void sharp_vty_init(void); + +int main(int argc, char **argv, char **envp) +{ + frr_preinit(&sharpd_di, argc, argv); + frr_opt_add("", longopts, ""); + + while (1) { + int opt; + + opt = frr_getopt(argc, argv, NULL); + + if (opt == EOF) + break; + + switch (opt) { + case 0: + break; + default: + frr_help_exit(1); + break; + } + } + + master = frr_init(); + + vrf_init(NULL, NULL, NULL, NULL); + + sharp_zebra_init(); + + /* Get configuration file. */ + sharp_vty_init(); + + frr_config_fork(); + frr_run(master); + + /* Not reached. */ + return 0; +} diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c new file mode 100644 index 0000000000..47bb37ce92 --- /dev/null +++ b/sharpd/sharp_vty.c @@ -0,0 +1,114 @@ +/* + * SHARP - vty code + * Copyright (C) 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 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 <zebra.h> + +#include "vty.h" +#include "command.h" +#include "prefix.h" +#include "nexthop.h" +#include "log.h" + +#include "sharpd/sharp_zebra.h" +#include "sharpd/sharp_vty.h" +#include "sharpd/sharp_vty_clippy.c" + +extern uint32_t total_routes; +extern uint32_t installed_routes; +extern uint32_t removed_routes; + +DEFPY (install_routes, + install_routes_cmd, + "install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes", + "install some routes\n" + "Routes to install\n" + "Address to start /32 generation at\n" + "Nexthop to use\n" + "Nexthop address\n" + "How many to create\n") +{ + int i; + struct prefix p; + struct nexthop nhop; + uint32_t temp; + + total_routes = routes; + installed_routes = 0; + + memset(&p, 0, sizeof(p)); + memset(&nhop, 0, sizeof(nhop)); + + p.family = AF_INET; + p.prefixlen = 32; + p.u.prefix4 = start; + + nhop.gate.ipv4 = nexthop; + nhop.type = NEXTHOP_TYPE_IPV4; + + zlog_debug("Inserting %ld routes", routes); + + temp = ntohl(p.u.prefix4.s_addr); + for (i = 0 ; i < routes ; i++) { + route_add(&p, &nhop); + p.u.prefix4.s_addr = htonl(++temp); + } + + return CMD_SUCCESS; +} + +DEFPY (remove_routes, + remove_routes_cmd, + "remove routes A.B.C.D$start (1-1000000)$routes", + "Remove some routes\n" + "Routes to remove\n" + "Starting spot\n" + "Routes to uniinstall\n") +{ + int i; + struct prefix p; + uint32_t temp; + + total_routes = routes; + removed_routes = 0; + + memset(&p, 0, sizeof(p)); + + p.family = AF_INET; + p.prefixlen = 32; + p.u.prefix4 = start; + + zlog_debug("Removing %ld routes", routes); + + temp = ntohl(p.u.prefix4.s_addr); + for (i = 0; i < routes ; i++) { + route_delete(&p); + p.u.prefix4.s_addr = htonl(++temp); + } + + return CMD_SUCCESS; +} + +void sharp_vty_init(void) +{ + install_element(ENABLE_NODE, &install_routes_cmd); + install_element(ENABLE_NODE, &remove_routes_cmd); + return; +} diff --git a/sharpd/sharp_vty.h b/sharpd/sharp_vty.h new file mode 100644 index 0000000000..d4af095e89 --- /dev/null +++ b/sharpd/sharp_vty.h @@ -0,0 +1,26 @@ +/* + * VTY library for SHARP + * Copyright (C) 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 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 __SHARP_VTY_H__ +#define __SHARP_VTY_H__ + +extern void sharp_vty_init(void); +#endif diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c new file mode 100644 index 0000000000..4a5ae13c43 --- /dev/null +++ b/sharpd/sharp_zebra.c @@ -0,0 +1,208 @@ +/* + * Zebra connect code. + * Copyright (C) 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 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 <zebra.h> + +#include "thread.h" +#include "command.h" +#include "network.h" +#include "prefix.h" +#include "routemap.h" +#include "table.h" +#include "stream.h" +#include "memory.h" +#include "zclient.h" +#include "filter.h" +#include "plist.h" +#include "log.h" +#include "nexthop.h" + +#include "sharp_zebra.h" + +/* Zebra structure to hold current status. */ +struct zclient *zclient = NULL; + +/* For registering threads. */ +extern struct thread_master *master; + +static struct interface *zebra_interface_if_lookup(struct stream *s) +{ + char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get(ifname_tmp, s, INTERFACE_NAMSIZ); + + /* And look it up. */ + return if_lookup_by_name(ifname_tmp, VRF_DEFAULT); +} + +/* Inteface addition message from zebra. */ +static int interface_add(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); + + if (!ifp->info) + return 0; + + return 0; +} + +static int interface_delete(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct stream *s; + + s = zclient->ibuf; + /* zebra_interface_state_read () updates interface structure in iflist + */ + ifp = zebra_interface_state_read(s, vrf_id); + + if (ifp == NULL) + return 0; + + if_set_index(ifp, IFINDEX_INTERNAL); + + return 0; +} + +static int interface_address_add(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + + zebra_interface_address_read(command, zclient->ibuf, vrf_id); + + return 0; +} + +static int interface_address_delete(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *c; + + c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); + + if (!c) + return 0; + + connected_free(c); + return 0; +} + +static int interface_state_up(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + + zebra_interface_if_lookup(zclient->ibuf); + + return 0; +} + +static int interface_state_down(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + + zebra_interface_state_read(zclient->ibuf, vrf_id); + + return 0; +} + +extern uint32_t total_routes; +extern uint32_t installed_routes; + +static int notify_owner(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct prefix p; + enum zapi_route_notify_owner note; + + if (!zapi_route_notify_decode(zclient->ibuf, &p, ¬e)) + return -1; + + installed_routes++; + + if (total_routes == installed_routes) + zlog_debug("Installed All Items"); + return 0; +} + +static void zebra_connected(struct zclient *zclient) +{ + zclient_send_reg_requests(zclient, VRF_DEFAULT); +} + +void route_add(struct prefix *p, struct nexthop *nh) +{ + struct zapi_route api; + struct zapi_nexthop *api_nh; + + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_SHARP; + api.safi = SAFI_UNICAST; + memcpy(&api.prefix, p, sizeof(*p)); + + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + + api_nh = &api.nexthops[0]; + api_nh->gate.ipv4 = nh->gate.ipv4; + api_nh->type = nh->type; + api_nh->ifindex = nh->ifindex; + api.nexthop_num = 1; + + zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); +} + +void route_delete(struct prefix *p) +{ + struct zapi_route api; + + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_SHARP; + api.safi = SAFI_UNICAST; + memcpy(&api.prefix, p, sizeof(*p)); + zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); + + return; +} + +extern struct zebra_privs_t sharp_privs; + +void sharp_zebra_init(void) +{ + struct zclient_options opt = { .receive_notify = true }; + + zclient = zclient_new_notify(master, &opt); + + zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); + zclient->zebra_connected = zebra_connected; + zclient->interface_add = interface_add; + zclient->interface_delete = interface_delete; + zclient->interface_up = interface_state_up; + zclient->interface_down = interface_state_down; + zclient->interface_address_add = interface_address_add; + zclient->interface_address_delete = interface_address_delete; + zclient->notify_owner = notify_owner; +} diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h new file mode 100644 index 0000000000..97100f61a6 --- /dev/null +++ b/sharpd/sharp_zebra.h @@ -0,0 +1,29 @@ +/* + * Zebra connect library for SHARP + * Copyright (C) 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 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 __SHARP_ZEBRA_H__ +#define __SHARP_ZEBRA_H__ + +extern void sharp_zebra_init(void); + +extern void route_add(struct prefix *p, struct nexthop *nh); +extern void route_delete(struct prefix *p); +#endif diff --git a/sharpd/sharpd.conf.sample b/sharpd/sharpd.conf.sample new file mode 100644 index 0000000000..bb1c2edca8 --- /dev/null +++ b/sharpd/sharpd.conf.sample @@ -0,0 +1,3 @@ +! +! +log stdout diff --git a/sharpd/subdir.am b/sharpd/subdir.am new file mode 100644 index 0000000000..da7d68e0bc --- /dev/null +++ b/sharpd/subdir.am @@ -0,0 +1,21 @@ +# +# sharpd +# + +if SHARPD +noinst_LIBRARIES += sharpd/libsharp.a +sbin_PROGRAMS += sharpd/sharpd +dist_examples_DATA += sharpd/sharpd.conf.sample +endif + +sharpd_libsharp_a_SOURCES = \ + sharpd/sharp_zebra.c \ + sharpd/sharp_vty.c \ + # end + +sharpd/sharp_vty_clippy.c: $(CLIPPY_DEPS) +sharpd/sharp_vty.$(OBJEXT): sharpd/sharp_vty_clippy.c + +sharpd_sharpd_SOURCES = sharpd/sharp_main.c +sharpd_sharpd_LDADD = sharpd/libsharp.a lib/libfrr.la @LIBCAP@ + diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c index ccd3b6f4c2..247fcf7da0 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -374,7 +374,7 @@ static int global_test_init(void) { qobj_init(); master = thread_master_create(NULL); - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); bgp_master_init(master); vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); diff --git a/tests/test_lblmgr.c b/tests/test_lblmgr.c index 5e604db61a..b08f63b70f 100644 --- a/tests/test_lblmgr.c +++ b/tests/test_lblmgr.c @@ -115,7 +115,7 @@ void init_zclient(struct thread_master *master, char *lm_zserv_path) { frr_zclient_addr(&zclient_addr, &zclient_addr_len, lm_zserv_path); - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); /* zclient_init(zclient, ZEBRA_LABEL_MANAGER, 0); */ zclient->sock = -1; zclient->redist_default = ZEBRA_ROUTE_LDP; diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index a460827924..ac17fed03a 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -33,3 +33,4 @@ ldpd=no nhrpd=no eigrpd=no babeld=no +sharpd=no diff --git a/tools/etc/frr/daemons.conf b/tools/etc/frr/daemons.conf index 0d92d13671..3f40836c90 100644 --- a/tools/etc/frr/daemons.conf +++ b/tools/etc/frr/daemons.conf @@ -16,6 +16,7 @@ ldpd_options=" --daemon -A 127.0.0.1" nhrpd_options=" --daemon -A 127.0.0.1" eigrpd_options=" --daemon -A 127.0.0.1" babeld_options=" --daemon -A 127.0.0.1" +sharpd_options=" --daemon -A 127.0.0.1" # The list of daemons to watch is automatically generated by the init script. watchfrr_enable=yes diff --git a/tools/etc/iproute2/rt_protos.d/frr.conf b/tools/etc/iproute2/rt_protos.d/frr.conf index 2d3b884e7e..b8d4c1c03b 100644 --- a/tools/etc/iproute2/rt_protos.d/frr.conf +++ b/tools/etc/iproute2/rt_protos.d/frr.conf @@ -8,3 +8,4 @@ 191 nhrp 192 eigrp 193 ldp +194 sharp
\ No newline at end of file @@ -21,7 +21,7 @@ V_PATH=/var/run/frr # Local Daemon selection may be done by using /etc/frr/daemons. # See /usr/share/doc/frr/README.Debian.gz for further information. # Keep zebra first and do not list watchfrr! -DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd" +DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd" MAX_INSTANCES=5 RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 5156d336b3..3ddb6aba54 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -132,6 +132,10 @@ vtysh_scan += $(top_srcdir)/babeld/babel_zebra.c vtysh_scan += $(top_srcdir)/babeld/babeld.c endif +if SHARPD +vtysh_scan += $(top_srcdir)/sharpd/sharp_vty.c +endif + if SNMP vtysh_scan += $(top_srcdir)/lib/agentx.c endif diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index f33c7b9603..dedf3d1647 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -82,7 +82,7 @@ foreach (@ARGV) { $protocol = "VTYSH_RIPD"; } elsif ($file =~ /lib\/routemap\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD"; + $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD"; } elsif ($file =~ /lib\/vrf\.c$/) { $protocol = "VTYSH_ALL"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b021607240..76343ded60 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -74,6 +74,7 @@ struct vtysh_client vtysh_client[] = { {.fd = -1, .name = "nhrpd", .flag = VTYSH_NHRPD, .next = NULL}, {.fd = -1, .name = "eigrpd", .flag = VTYSH_EIGRPD, .next = NULL}, {.fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .next = NULL}, + {.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL}, {.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL}, }; @@ -1045,7 +1046,9 @@ struct cmd_node link_params_node = { LINK_PARAMS_NODE, "%s(config-link-params)# ", }; +#if defined(HAVE_RPKI) static struct cmd_node rpki_node = {RPKI_NODE, "%s(config-rpki)# ", 1}; +#endif /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -1183,6 +1186,7 @@ DEFUNSH(VTYSH_BGPD, address_family_ipv6_labeled_unicast, return CMD_SUCCESS; } +#if defined(HAVE_RPKI) DEFUNSH(VTYSH_BGPD, rpki, rpki_cmd, @@ -1211,6 +1215,7 @@ DEFUNSH(VTYSH_BGPD, { return rpki_exit(self, vty, argc, argv); } +#endif DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd, "address-family <l2vpn evpn>", @@ -3010,7 +3015,9 @@ void vtysh_init_vty(void) install_node(&keychain_key_node, NULL); install_node(&isis_node, NULL); install_node(&vty_node, NULL); +#if defined(HAVE_RPKI) install_node(&rpki_node, NULL); +#endif struct cmd_node *node; for (unsigned int i = 0; i < vector_active(cmdvec); i++) { @@ -3209,10 +3216,12 @@ void vtysh_init_vty(void) install_element(BGP_EVPN_NODE, &exit_address_family_cmd); install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); +#if defined(HAVE_RPKI) install_element(CONFIG_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); install_element(RPKI_NODE, &vtysh_end_all_cmd); +#endif /* EVPN commands */ install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 9d6ea4bda4..c584d7a905 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -37,13 +37,15 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_NHRPD 0x800 #define VTYSH_EIGRPD 0x1000 #define VTYSH_BABELD 0x2000 +#define VTYSH_SHARPD 0x4000 + /* commands in REALLYALL are crucial to correct vtysh operation */ #define VTYSH_REALLYALL ~0U /* watchfrr is not in ALL since library CLI functions should not be * run on it (logging & co. should stay in a fixed/frozen config, and * things like prefix lists are not even initialised) */ -#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD +#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD|VTYSH_EIGRPD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD #define VTYSH_NS VTYSH_ZEBRA diff --git a/zebra/client_main.c b/zebra/client_main.c index 95b9d00dc0..9b82e48261 100644 --- a/zebra/client_main.c +++ b/zebra/client_main.c @@ -184,7 +184,7 @@ int main(int argc, char **argv) master = thread_master_create(NULL); /* Establish connection to zebra. */ - zclient = zclient_new(master); + zclient = zclient_new_notify(master, &zclient_options_default); zclient->enable = 1; zclient_socket_connect(zclient); diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 6fbb751789..bf4522b70f 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -221,7 +221,7 @@ static void lm_zclient_init(char *lm_zserv_path) lm_zserv_path); /* Set default values. */ - zclient = zclient_new(zebrad.master); + zclient = zclient_new_notify(zebrad.master, &zclient_options_default); zclient->sock = -1; zclient->t_connect = NULL; lm_zclient_connect(NULL); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e8333ef0cf..3830e1fbde 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -98,7 +98,7 @@ static inline int is_selfroute(int proto) || (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG) || (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP) || (proto == RTPROT_LDP) || (proto == RTPROT_BABEL) - || (proto == RTPROT_RIP)) { + || (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)) { return 1; } @@ -139,6 +139,9 @@ static inline int zebra2proto(int proto) case ZEBRA_ROUTE_LDP: proto = RTPROT_LDP; break; + case ZEBRA_ROUTE_SHARP: + proto = RTPROT_SHARP; + break; default: proto = RTPROT_ZEBRA; break; @@ -1605,7 +1608,23 @@ int kernel_route_rib(struct prefix *p, struct prefix *src_p, if (old && !new) return netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); - return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 1); + if (p->family == AF_INET) + return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 1); + + /* + * So v6 route replace semantics are not in the kernel at this + * point as I understand it. + * So let's do a delete than an add. + * In the future once v6 route replace semantics are in + * we can figure out what to do here to allow working + * with old and new kernels. + * + * I'm also intentionally ignoring the failure case + * of the route delete. If that happens yeah we're + * screwed. + */ + netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); + return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0); } int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index afb03f878d..51350fd6fb 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -51,6 +51,7 @@ #define RTPROT_NHRP 191 #define RTPROT_EIGRP 192 #define RTPROT_LDP 193 +#define RTPROT_SHARP 194 void rt_netlink_init(void); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5e0baf807d..791f319120 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -449,9 +449,15 @@ static int nexthop_active(afi_t afi, struct route_entry *re, while (rn) { route_unlock_node(rn); - /* If lookup self prefix return immediately. */ - if (rn == top) - return 0; + /* Lookup should halt if we've matched against ourselves ('top', + * if specified) - i.e., we cannot have a nexthop NH1 is + * resolved by a route NH1. The exception is if the route is a + * host route. + */ + if (top && rn == top) + if (((afi == AFI_IP) && (rn->p.prefixlen != 32)) || + ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) + return 0; /* Pick up selected route. */ /* However, do not resolve over default route unless explicitly @@ -1022,6 +1028,14 @@ int rib_install_kernel(struct route_node *rn, struct route_entry *re, } } + /* + * If this is a replace to a new RE let the originator of the RE + * know that they've lost + */ + if (old && old != re) + zsend_route_notify_owner(old->type, old->instance, + old->vrf_id, p, + ZAPI_ROUTE_BETTER_ADMIN_WON); /* * Make sure we update the FPM any time we send new information to @@ -1042,7 +1056,11 @@ int rib_install_kernel(struct route_node *rn, struct route_entry *re, else UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } - } + zsend_route_notify_owner(re->type, re->instance, re->vrf_id, + p, ZAPI_ROUTE_INSTALLED); + } else + zsend_route_notify_owner(re->type, re->instance, re->vrf_id, + p, ZAPI_ROUTE_FAIL_INSTALL); return ret; } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 355fef94f4..33d0b3a641 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -370,11 +370,12 @@ static int zebra_rnh_apply_nht_rmap(int family, struct route_node *prn, } /* - * Determine appropriate route (RE entry) resolving a tracked entry - * (nexthop or BGP route for import). + * Determine appropriate route (RE entry) resolving a tracked BGP route + * for BGP route for import. */ -static struct route_entry *zebra_rnh_resolve_entry(vrf_id_t vrfid, int family, - rnh_type_t type, +static +struct route_entry *zebra_rnh_resolve_import_entry(vrf_id_t vrfid, + int family, struct route_node *nrn, struct rnh *rnh, struct route_node **prn) @@ -393,48 +394,21 @@ static struct route_entry *zebra_rnh_resolve_entry(vrf_id_t vrfid, int family, if (!rn) return NULL; - /* When resolving nexthops, do not resolve via the default route unless - * 'ip nht resolve-via-default' is configured. - */ - if ((type == RNH_NEXTHOP_TYPE) - && (is_default_prefix(&rn->p) - && !nh_resolve_via_default(rn->p.family))) - re = NULL; - else if ((type == RNH_IMPORT_CHECK_TYPE) - && CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH) - && !prefix_same(&nrn->p, &rn->p)) - re = NULL; - else { - /* Identify appropriate route entry. */ - RNODE_FOREACH_RE (rn, re) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) - continue; - if (!CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB)) - continue; + /* Unlock route node - we don't need to lock when walking the tree. */ + route_unlock_node(rn); - if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { - if (re->type == ZEBRA_ROUTE_CONNECT) - break; - if (re->type == ZEBRA_ROUTE_NHRP) { - struct nexthop *nexthop; - for (nexthop = re->nexthop; nexthop; - nexthop = nexthop->next) - if (nexthop->type - == NEXTHOP_TYPE_IFINDEX) - break; - if (nexthop) - break; - } - } else if ((type == RNH_IMPORT_CHECK_TYPE) - && (re->type == ZEBRA_ROUTE_BGP)) - continue; - else - break; - } + if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH) && + !prefix_same(&nrn->p, &rn->p)) + return NULL; + + /* Identify appropriate route entry. */ + RNODE_FOREACH_RE(rn, re) { + if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) && + CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) && + (re->type != ZEBRA_ROUTE_BGP)) + break; } - /* Need to unlock route node */ - route_unlock_node(rn); if (re) *prn = rn; return re; @@ -650,6 +624,86 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family, } } +/* + * Determine appropriate route (route entry) resolving a tracked + * nexthop. + */ +static struct route_entry *zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid, + int family, + struct route_node *nrn, + struct rnh *rnh, + struct route_node **prn) +{ + struct route_table *route_table; + struct route_node *rn; + struct route_entry *re; + + *prn = NULL; + + route_table = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid); + if (!route_table) + return NULL; + + rn = route_node_match(route_table, &nrn->p); + if (!rn) + return NULL; + + /* Unlock route node - we don't need to lock when walking the tree. */ + route_unlock_node(rn); + + /* While resolving nexthops, we may need to walk up the tree from the + * most-specific match. Do similar logic as in zebra_rib.c + */ + while (rn) { + /* Do not resolve over default route unless allowed && + * match route to be exact if so specified + */ + if (is_default_prefix(&rn->p) && + !nh_resolve_via_default(rn->p.family)) + return NULL; + + /* Identify appropriate route entry. */ + RNODE_FOREACH_RE(rn, re) { + if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) + continue; + if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) + continue; + + if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { + if ((re->type == ZEBRA_ROUTE_CONNECT) + || (re->type == ZEBRA_ROUTE_STATIC)) + break; + if (re->type == ZEBRA_ROUTE_NHRP) { + struct nexthop *nexthop; + + for (nexthop = re->nexthop; + nexthop; + nexthop = nexthop->next) + if (nexthop->type + == NEXTHOP_TYPE_IFINDEX) + break; + if (nexthop) + break; + } + } else + break; + } + + /* Route entry found, we're done; else, walk up the tree. */ + if (re) { + *prn = rn; + return re; + } + + if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + rn = rn->parent; + else + return NULL; + } + + return NULL; +} + static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh) { struct zebra_pw *pw; @@ -724,7 +778,12 @@ static void zebra_rnh_evaluate_entry(vrf_id_t vrfid, int family, int force, rnh = nrn->info; /* Identify route entry (RE) resolving this tracked entry. */ - re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn); + if (type == RNH_IMPORT_CHECK_TYPE) + re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, + rnh, &prn); + else + re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh, + &prn); /* If the entry cannot be resolved and that is also the existing state, * there is nothing further to do. @@ -759,7 +818,13 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family, rnh = nrn->info; - re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn); + /* Identify route entry (RIB) resolving this tracked entry. */ + if (type == RNH_IMPORT_CHECK_TYPE) + re = zebra_rnh_resolve_import_entry(vrfid, family, nrn, + rnh, &prn); + else + re = zebra_rnh_resolve_nexthop_entry(vrfid, family, nrn, rnh, + &prn); if (re) { UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index f5caf9d0b9..9c70b55a1a 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -759,7 +759,7 @@ static int zvni_macip_send_msg_to_client(vni_t vni, char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; - client = zebra_find_client(ZEBRA_ROUTE_BGP); + client = zebra_find_client(ZEBRA_ROUTE_BGP, 0); /* BGP may not be running. */ if (!client) return 0; @@ -2122,7 +2122,7 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni) struct zserv *client; struct stream *s; - client = zebra_find_client(ZEBRA_ROUTE_BGP); + client = zebra_find_client(ZEBRA_ROUTE_BGP, 0); /* BGP may not be running. */ if (!client) return 0; @@ -2154,7 +2154,7 @@ static int zvni_send_del_to_client(vni_t vni) struct zserv *client; struct stream *s; - client = zebra_find_client(ZEBRA_ROUTE_BGP); + client = zebra_find_client(ZEBRA_ROUTE_BGP, 0); /* BGP may not be running. */ if (!client) return 0; diff --git a/zebra/zserv.c b/zebra/zserv.c index 2389944e84..b6d70084c0 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -988,6 +988,43 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, return zebra_server_send_message(client); } +int zsend_route_notify_owner(u_char proto, u_short instance, + vrf_id_t vrf_id, struct prefix *p, + enum zapi_route_notify_owner note) +{ + struct zserv *client; + struct stream *s; + uint8_t blen; + + client = zebra_find_client(proto, instance); + if (!client || !client->notify_owner) { + if (IS_ZEBRA_DEBUG_PACKET) { + char buff[PREFIX_STRLEN]; + + zlog_debug("Not Notifying Owner: %u about prefix %s", + proto, prefix2str(p, buff, sizeof(buff))); + } + return 0; + } + + s = client->obuf; + stream_reset(s); + + zserv_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id); + + stream_put(s, ¬e, sizeof(note)); + + stream_putc(s, p->family); + + blen = prefix_blen(p); + stream_putc(s, p->prefixlen); + stream_put(s, &p->u.prefix, blen); + + stream_putw_at(s, 0, stream_get_endp(s)); + + return 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) @@ -1884,9 +1921,13 @@ static void zread_hello(struct zserv *client) /* type of protocol (lib/zebra.h) */ u_char proto; u_short instance; + u_char notify; STREAM_GETC(client->ibuf, proto); STREAM_GETW(client->ibuf, instance); + STREAM_GETC(client->ibuf, notify); + if (notify) + client->notify_owner = true; /* accept only dynamic routing protocols */ if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_STATIC)) { @@ -2962,13 +3003,14 @@ static void zebra_show_client_brief(struct vty *vty, struct zserv *client) client->v6_route_del_cnt); } -struct zserv *zebra_find_client(u_char proto) +struct zserv *zebra_find_client(u_char proto, u_short instance) { struct listnode *node, *nnode; struct zserv *client; for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) { - if (client->proto == proto) + if (client->proto == proto && + client->instance == instance) return client; } diff --git a/zebra/zserv.h b/zebra/zserv.h index 60e055088a..6077dc105a 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -75,6 +75,8 @@ struct zserv { /* Router-id information. */ vrf_bitmap_t ridinfo; + bool notify_owner; + /* client's protocol */ u_char proto; u_short instance; @@ -183,6 +185,10 @@ extern int zsend_interface_vrf_update(struct zserv *, struct interface *, extern int zsend_interface_link_params(struct zserv *, struct interface *); extern int zsend_pw_update(struct zserv *, struct zebra_pw *); +extern int zsend_route_notify_owner(u_char proto, u_short instance, + vrf_id_t vrf_id, struct prefix *p, + enum zapi_route_notify_owner note); + extern pid_t pid; extern void zserv_create_header(struct stream *s, uint16_t cmd, @@ -191,7 +197,7 @@ extern void zserv_nexthop_num_warn(const char *, const struct prefix *, const unsigned int); extern int zebra_server_send_message(struct zserv *client); -extern struct zserv *zebra_find_client(u_char proto); +extern struct zserv *zebra_find_client(u_char proto, u_short instance); #if defined(HANDLE_ZAPI_FUZZING) extern void zserv_read_file(char *input); |
