diff options
40 files changed, 661 insertions, 181 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e21c84355e..ab9dc3092a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -724,10 +724,13 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, struct community *community, struct ecommunity *ecommunity, struct lcommunity *lcommunity, - int as_set, uint8_t atomic_aggregate) + struct bgp_aggregate *aggregate, + uint8_t atomic_aggregate, + struct prefix *p) { struct attr attr; struct attr *new; + int ret; memset(&attr, 0, sizeof(struct attr)); @@ -778,7 +781,7 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, attr.label = MPLS_INVALID_LABEL; attr.weight = BGP_ATTR_DEFAULT_WEIGHT; attr.mp_nexthop_len = IPV6_MAX_BYTELEN; - if (!as_set || atomic_aggregate) + if (!aggregate->as_set || atomic_aggregate) attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR); if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) @@ -789,7 +792,42 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, attr.label_index = BGP_INVALID_LABEL_INDEX; attr.label = MPLS_INVALID_LABEL; - new = bgp_attr_intern(&attr); + /* Apply route-map */ + if (aggregate->rmap.name) { + struct attr attr_tmp = attr; + struct bgp_path_info rmap_path; + + memset(&rmap_path, 0, sizeof(struct bgp_path_info)); + rmap_path.peer = bgp->peer_self; + rmap_path.attr = &attr_tmp; + + SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE); + + ret = route_map_apply(aggregate->rmap.map, p, RMAP_BGP, + &rmap_path); + + bgp->peer_self->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) { + /* Free uninterned attribute. */ + bgp_attr_flush(&attr_tmp); + + /* Unintern original. */ + aspath_unintern(&attr.aspath); + return NULL; + } + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + bgp_attr_add_gshut_community(&attr_tmp); + + new = bgp_attr_intern(&attr_tmp); + } else { + + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + bgp_attr_add_gshut_community(&attr); + + new = bgp_attr_intern(&attr); + } aspath_unintern(&new->aspath); return new; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1592a8df4e..f1a871fe43 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -272,8 +272,9 @@ extern struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, struct community *community, struct ecommunity *ecommunity, struct lcommunity *lcommunity, - int as_set, - uint8_t atomic_aggregate); + struct bgp_aggregate *aggregate, + uint8_t atomic_aggregate, + struct prefix *p); extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct bpacket_attr_vec_arr *vecarr, diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 8fca202345..3af373b562 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -663,6 +663,11 @@ static int bmp_peer_established(struct peer *peer) if (!bmpbgp) return 0; + /* Check if this peer just went to Established */ + if ((peer->last_major_event != OpenConfirm) || + !(peer_established(peer))) + return 0; + if (peer->doppelganger && (peer->doppelganger->status != Deleted)) { struct bmp_bgp_peer *bbpeer, *bbdopp; @@ -2226,7 +2231,7 @@ static int bgp_bmp_module_init(void) { hook_register(bgp_packet_dump, bmp_mirror_packet); hook_register(bgp_packet_send, bmp_outgoing_packet); - hook_register(peer_established, bmp_peer_established); + hook_register(peer_status_changed, bmp_peer_established); hook_register(peer_backward_transition, bmp_peer_backward); hook_register(bgp_process, bmp_process); hook_register(bgp_inst_config_write, bmp_config_write); diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 535f36ab5e..640224e759 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -494,13 +494,13 @@ static void bgp_dump_common(struct stream *obuf, struct peer *peer, } /* Dump BGP status change. */ -void bgp_dump_state(struct peer *peer, int status_old, int status_new) +int bgp_dump_state(struct peer *peer) { struct stream *obuf; /* If dump file pointer is disabled return immediately. */ if (bgp_dump_all.fp == NULL) - return; + return 0; /* Make dump stream. */ obuf = bgp_dump_obuf; @@ -510,8 +510,8 @@ void bgp_dump_state(struct peer *peer, int status_old, int status_new) bgp_dump_all.type); bgp_dump_common(obuf, peer, 1); /* force this in as4speak*/ - stream_putw(obuf, status_old); - stream_putw(obuf, status_new); + stream_putw(obuf, peer->ostatus); + stream_putw(obuf, peer->status); /* Set length. */ bgp_dump_set_size(obuf, MSG_PROTOCOL_BGP4MP); @@ -519,6 +519,7 @@ void bgp_dump_state(struct peer *peer, int status_old, int status_new) /* Write to the stream. */ fwrite(STREAM_DATA(obuf), stream_get_endp(obuf), 1, bgp_dump_all.fp); fflush(bgp_dump_all.fp); + return 0; } static void bgp_dump_packet_func(struct bgp_dump *bgp_dump, struct peer *peer, @@ -867,6 +868,7 @@ void bgp_dump_init(void) install_element(CONFIG_NODE, &no_dump_bgp_all_cmd); hook_register(bgp_packet_dump, bgp_dump_packet); + hook_register(peer_status_changed, bgp_dump_state); } void bgp_dump_finish(void) @@ -878,4 +880,5 @@ void bgp_dump_finish(void) stream_free(bgp_dump_obuf); bgp_dump_obuf = NULL; hook_unregister(bgp_packet_dump, bgp_dump_packet); + hook_unregister(peer_status_changed, bgp_dump_state); } diff --git a/bgpd/bgp_dump.h b/bgpd/bgp_dump.h index 5ec0561b05..86c80d481c 100644 --- a/bgpd/bgp_dump.h +++ b/bgpd/bgp_dump.h @@ -51,6 +51,6 @@ extern void bgp_dump_init(void); extern void bgp_dump_finish(void); -extern void bgp_dump_state(struct peer *, int, int); +extern int bgp_dump_state(struct peer *); #endif /* _QUAGGA_BGP_DUMP_H */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 6c77f18f33..50fef00a96 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5668,6 +5668,8 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) for (ALL_LIST_ELEMENTS(bgp_vrf->l2vnis, node, next, vpn)) bgpevpn_unlink_from_l3vni(vpn); + UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY); + /* Delete the instance if it was autocreated */ if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO)) bgp_delete(bgp_vrf); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index cc7f81d9ff..79c873e601 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -57,7 +57,7 @@ #include "bgpd/bgp_zebra.h" DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer)) -DEFINE_HOOK(peer_established, (struct peer * peer), (peer)) +DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer)) /* Definition of display strings corresponding to FSM events. This should be * kept consistent with the events defined in bgpd.h @@ -962,8 +962,6 @@ void bgp_fsm_change_status(struct peer *peer, int status) struct bgp *bgp; uint32_t peer_count; - bgp_dump_state(peer, peer->status, status); - bgp = peer->bgp; peer_count = bgp->established_peers; @@ -1025,6 +1023,9 @@ void bgp_fsm_change_status(struct peer *peer, int status) /* Save event that caused status change. */ peer->last_major_event = peer->cur_event; + /* Operations after status change */ + hook_call(peer_status_changed, peer); + if (status == Established) UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); @@ -1657,8 +1658,6 @@ static int bgp_establish(struct peer *peer) peer->host); } - hook_call(peer_established, peer); - /* Reset uptime, turn on keepalives, send current table. */ if (!peer->v_holdtime) bgp_keepalives_on(peer); diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 3476a3c3a9..9d0500ae2c 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -88,6 +88,5 @@ extern void bgp_adjust_routeadv(struct peer *); #include "hook.h" DECLARE_HOOK(peer_backward_transition, (struct peer * peer), (peer)) -DECLARE_HOOK(peer_established, (struct peer * peer), (peer)) #endif /* _QUAGGA_BGP_FSM_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 32c9fb16f3..5eeab36742 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5704,6 +5704,8 @@ static struct bgp_aggregate *bgp_aggregate_new(void) static void bgp_aggregate_free(struct bgp_aggregate *aggregate) { + XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name); + route_map_counter_decrement(aggregate->rmap.map); XFREE(MTYPE_BGP_AGGREGATE, aggregate); } @@ -5754,6 +5756,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_node *rn; struct bgp_table *table; struct bgp_path_info *pi, *orig, *new; + struct attr *attr; table = bgp->rib[afi][safi]; @@ -5791,14 +5794,18 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, if (pi) bgp_path_info_delete(rn, pi); + attr = bgp_attr_aggregate_intern( + bgp, origin, aspath, community, ecommunity, lcommunity, + aggregate, atomic_aggregate, p); + + if (!attr) { + bgp_aggregate_delete(bgp, p, afi, safi, aggregate); + return; + } + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0, - bgp->peer_self, - bgp_attr_aggregate_intern(bgp, origin, aspath, - community, ecommunity, - lcommunity, - aggregate->as_set, - atomic_aggregate), - rn); + bgp->peer_self, attr, rn); + SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_add(rn, new); @@ -5821,7 +5828,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, } /* Update an aggregate as routes are added/removed from the BGP table */ -static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, +void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { @@ -5982,7 +5989,7 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, aggregate); } -static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, +void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; @@ -6426,7 +6433,8 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, } static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, - safi_t safi, uint8_t summary_only, uint8_t as_set) + safi_t safi, const char *rmap, uint8_t summary_only, + uint8_t as_set) { VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; @@ -6451,8 +6459,9 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, /* Old configuration check. */ rn = bgp_node_get(bgp->aggregate[afi][safi], &p); + aggregate = bgp_node_get_bgp_aggregate_info(rn); - if (bgp_node_has_bgp_path_info_data(rn)) { + if (aggregate) { vty_out(vty, "There is already same aggregate network.\n"); /* try to remove the old entry */ ret = bgp_aggregate_unset(vty, prefix_str, afi, safi); @@ -6468,6 +6477,15 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, aggregate->summary_only = summary_only; aggregate->as_set = as_set; aggregate->safi = safi; + + if (rmap) { + XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name); + route_map_counter_decrement(aggregate->rmap.map); + aggregate->rmap.name = + XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); + aggregate->rmap.map = route_map_lookup_by_name(rmap); + route_map_counter_increment(aggregate->rmap.map); + } bgp_node_set_bgp_aggregate_info(rn, aggregate); /* Aggregate address insert into BGP routing table. */ @@ -6478,17 +6496,20 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, DEFUN (aggregate_address, aggregate_address_cmd, - "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>]", + "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D/M", &idx); char *prefix = argv[idx]->arg; + char *rmap = NULL; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; idx = 0; @@ -6496,25 +6517,33 @@ DEFUN (aggregate_address, ? AGGREGATE_SUMMARY_ONLY : 0; + idx = 0; + argv_find(argv, argc, "WORD", &idx); + if (idx) + rmap = argv[idx]->arg; + return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty), - summary_only, as_set); + rmap, summary_only, as_set); } DEFUN (aggregate_address_mask, aggregate_address_mask_cmd, - "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>]", + "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D", &idx); char *prefix = argv[idx]->arg; char *mask = argv[idx + 1]->arg; + char *rmap = NULL; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; idx = 0; @@ -6522,6 +6551,10 @@ DEFUN (aggregate_address_mask, ? AGGREGATE_SUMMARY_ONLY : 0; + argv_find(argv, argc, "WORD", &idx); + if (idx) + rmap = argv[idx]->arg; + char prefix_str[BUFSIZ]; int ret = netmask_str2prefix_str(prefix, mask, prefix_str); @@ -6531,7 +6564,7 @@ DEFUN (aggregate_address_mask, } return bgp_aggregate_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty), - summary_only, as_set); + rmap, summary_only, as_set); } DEFUN (no_aggregate_address, @@ -6581,17 +6614,20 @@ DEFUN (no_aggregate_address_mask, DEFUN (ipv6_aggregate_address, ipv6_aggregate_address_cmd, - "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>]", + "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n" "Filter more specific routes from updates\n" - "Generate AS set path information\n") + "Generate AS set path information\n" + "Apply route map to aggregate network\n" + "Name of route map\n") { int idx = 0; argv_find(argv, argc, "X:X::X:X/M", &idx); char *prefix = argv[idx]->arg; + char *rmap = NULL; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; @@ -6599,8 +6635,13 @@ DEFUN (ipv6_aggregate_address, int sum_only = argv_find(argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY : 0; - return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, sum_only, - as_set); + + argv_find(argv, argc, "WORD", &idx); + if (idx) + rmap = argv[idx]->arg; + + return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap, + sum_only, as_set); } DEFUN (no_ipv6_aggregate_address, @@ -12467,6 +12508,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp_aggregate->summary_only) vty_out(vty, " summary-only"); + if (bgp_aggregate->rmap.name) + vty_out(vty, " route-map %s", bgp_aggregate->rmap.name); + vty_out(vty, "\n"); } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 704cd39710..ba4e32c23d 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -313,7 +313,10 @@ struct bgp_aggregate { uint8_t as_set; /* Route-map for aggregated route. */ - struct route_map *map; + struct { + char *name; + struct route_map *map; + } rmap; /* Suppress-count. */ unsigned long count; @@ -545,6 +548,10 @@ extern void bgp_config_write_network(struct vty *, struct bgp *, afi_t, safi_t); extern void bgp_config_write_distance(struct vty *, struct bgp *, afi_t, safi_t); +extern void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi, struct bgp_aggregate *aggregate); +extern void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, afi_t afi, + safi_t safi, struct bgp_aggregate *aggregate); extern void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 545ca19762..b1f1819b6b 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -269,7 +269,8 @@ route_match_peer(void *rule, const struct prefix *prefix, /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, - REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH + REDISTRIBUTE, AGGREGATE-ADDRESS or DEFAULT_GENERATED route + => return RMAP_MATCH */ if (sockunion_same(su, &su_def)) { int ret; @@ -277,6 +278,8 @@ route_match_peer(void *rule, const struct prefix *prefix, || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE) || CHECK_FLAG(peer->rmap_type, + PEER_RMAP_TYPE_AGGREGATE) + || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_DEFAULT)) ret = RMAP_MATCH; else @@ -3248,6 +3251,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, struct peer *peer; struct bgp_node *bn; struct bgp_static *bgp_static; + struct bgp_aggregate *aggregate; struct listnode *node, *nnode; struct route_map *map; char buf[INET6_ADDRSTRLEN]; @@ -3331,6 +3335,35 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, safi); } } + + /* For aggregate-address route-map updates. */ + for (bn = bgp_table_top(bgp->aggregate[afi][safi]); bn; + bn = bgp_route_next(bn)) { + aggregate = bgp_node_get_bgp_aggregate_info(bn); + if (!aggregate) + continue; + + if (!aggregate->rmap.name + || (strcmp(rmap_name, aggregate->rmap.name) != 0)) + continue; + + if (!aggregate->rmap.map) + route_map_counter_increment(map); + + aggregate->rmap.map = map; + + if (route_update) { + if (bgp_debug_zebra(&bn->p)) + zlog_debug( + "Processing route_map %s update on aggregate-address route %s", + rmap_name, + inet_ntop(bn->p.family, + &bn->p.u.prefix, buf, + INET6_ADDRSTRLEN)); + bgp_aggregate_route(bgp, &bn->p, afi, safi, + aggregate); + } + } } /* For redistribute route-map updates. */ diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 44cbeabd69..c266440899 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -894,6 +894,10 @@ static int bgpTrapEstablished(struct peer *peer) struct in_addr addr; oid index[sizeof(oid) * IN_ADDR_SIZE]; + /* Check if this peer just went to Established */ + if ((peer->last_major_event != OpenConfirm) || !(peer_established(peer))) + return 0; + ret = inet_aton(peer->host, &addr); if (ret == 0) return 0; @@ -935,7 +939,7 @@ static int bgp_snmp_init(struct thread_master *tm) static int bgp_snmp_module_init(void) { - hook_register(peer_established, bgpTrapEstablished); + hook_register(peer_status_changed, bgpTrapEstablished); hook_register(peer_backward_transition, bgpTrapBackwardTransition); hook_register(frr_late_init, bgp_snmp_init); return 0; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 477c036009..9d45d96987 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1211,6 +1211,7 @@ struct peer { #define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */ #define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */ #define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */ +#define PEER_RMAP_TYPE_AGGREGATE (1 << 8) /* aggregate-address route-map */ /* peer specific BFD information */ struct bfd_info *bfd_info; @@ -1935,4 +1936,7 @@ extern struct peer *peer_new(struct bgp *bgp); extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, const char *ip_str, bool use_json); +/* Hooks */ +DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer)) + #endif /* _QUAGGA_BGPD_H */ diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index da339b4409..7b3cdf2c4b 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -368,6 +368,16 @@ Administrative Distance Metrics Sets the administrative distance for a particular route. +.. _bgp-requires-policy: + +Require policy on EBGP +------------------------------- + +.. index:: [no] bgp ebgp-requires-policy +.. clicmd:: [no] bgp ebgp-requires-policy + + This command requires incoming and outgoing filters to be applied for eBGP sessions. Without the incoming filter, no routes will be accepted. Without the outgoing filter, no routes will be announced. + .. _bgp-route-flap-dampening: Route Flap Dampening @@ -675,6 +685,11 @@ Route Aggregation-IPv4 Address Family This command specifies an aggregate address. +.. index:: aggregate-address A.B.C.D/M route-map NAME +.. clicmd:: aggregate-address A.B.C.D/M route-map NAME + + Apply a route-map for an aggregated prefix. + .. index:: aggregate-address A.B.C.D/M as-set .. clicmd:: aggregate-address A.B.C.D/M as-set @@ -689,11 +704,11 @@ Route Aggregation-IPv4 Address Family .. index:: no aggregate-address A.B.C.D/M .. clicmd:: no aggregate-address A.B.C.D/M - + This command removes an aggregate address. - This configuration example setup the aggregate-address under + This configuration example setup the aggregate-address under ipv4 address-family. .. code-block:: frr @@ -703,6 +718,7 @@ Route Aggregation-IPv4 Address Family aggregate-address 10.0.0.0/8 aggregate-address 20.0.0.0/8 as-set aggregate-address 40.0.0.0/8 summary-only + aggregate-address 50.0.0.0/8 route-map aggr-rmap exit-address-family @@ -716,6 +732,11 @@ Route Aggregation-IPv6 Address Family This command specifies an aggregate address. +.. index:: aggregate-address X:X::X:X/M route-map NAME +.. clicmd:: aggregate-address X:X::X:X/M route-map NAME + + Apply a route-map for an aggregated prefix. + .. index:: aggregate-address X:X::X:X/M as-set .. clicmd:: aggregate-address X:X::X:X/M as-set @@ -734,16 +755,17 @@ Route Aggregation-IPv6 Address Family This command removes an aggregate address. - This configuration example setup the aggregate-address under - ipv4 address-family. + This configuration example setup the aggregate-address under + ipv6 address-family. .. code-block:: frr router bgp 1 address-family ipv6 unicast aggregate-address 10::0/64 - aggregate-address 20::0/64 as-set - aggregate-address 40::0/64 summary-only + aggregate-address 20::0/64 as-set + aggregate-address 40::0/64 summary-only + aggregate-address 50::0/64 route-map aggr-rmap exit-address-family .. _bgp-redistribute-to-bgp: @@ -2311,7 +2333,7 @@ attribute. Displaying Routes by Large Community Attribute ---------------------------------------------- -The following commands allow displaying routes based on their +The following commands allow displaying routes based on their large community attribute. .. index:: show [ip] bgp <ipv4|ipv6> large-community @@ -2328,8 +2350,8 @@ large community attribute. These commands display BGP routes which have the large community attribute. attribute. When ``LARGE-COMMUNITY`` is specified, BGP routes that match that - large community are displayed. When `exact-match` is specified, it display - only routes that have an exact match. When `json` is specified, it display + large community are displayed. When `exact-match` is specified, it display + only routes that have an exact match. When `json` is specified, it display routes in json format. .. index:: show [ip] bgp <ipv4|ipv6> large-community-list WORD @@ -2342,8 +2364,8 @@ large community attribute. .. clicmd:: show [ip] bgp <ipv4|ipv6> large-community-list WORD json These commands display BGP routes for the address family specified that - match the specified large community list. When `exact-match` is specified, - it displays only routes that have an exact match. When `json` is specified, + match the specified large community list. When `exact-match` is specified, + it displays only routes that have an exact match. When `json` is specified, it display routes in json format. .. _bgp-display-routes-by-as-path: diff --git a/doc/user/ospf_fundamentals.rst b/doc/user/ospf_fundamentals.rst index 7db822c820..76a9364cf9 100644 --- a/doc/user/ospf_fundamentals.rst +++ b/doc/user/ospf_fundamentals.rst @@ -24,7 +24,7 @@ Each router thus builds up an :abbr:`LSDB (Link State Database)` of all the link-state messages. From this collection of LSAs in the LSDB, each router can then calculate the shortest path to any other router, based on some common metric, by using an algorithm such as -`Edgar Djikstra's <http://www.cs.utexas.edu/users/EWD/>`_ +`Edsger Djikstra's <http://www.cs.utexas.edu/users/EWD/>`_ :abbr:`SPF (Shortest Path First)` algorithm. .. index:: Link-state routing protocol advantages diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 50c518d456..b7283d83de 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -292,6 +292,62 @@ Link Parameters Commands .. _zebra-vrf: +Administrative Distance +======================= + +Administrative distance allows FRR to make decisions about what routes +should be installed in the rib based upon the originating protocol. +The lowest Admin Distance is the route selected. This is purely a +subjective decision about ordering and care has been taken to choose +the same distances that other routing suites have choosen. + ++------------+-----------+ +| Protocol | Distance | ++------------+-----------+ +| System | 0 | ++------------+-----------+ +| Kernel | 0 | ++------------+-----------+ +| Connect | 0 | ++------------+-----------+ +| Static | 1 | ++------------+-----------+ +| NHRP | 10 | ++------------+-----------+ +| EBGP | 20 | ++------------+-----------+ +| EIGRP | 90 | ++------------+-----------+ +| BABEL | 100 | ++------------+-----------+ +| OSPF | 110 | ++------------+-----------+ +| ISIS | 115 | ++------------+-----------+ +| OPENFABRIC | 115 | ++------------+-----------+ +| RIP | 120 | ++------------+-----------+ +| Table | 150 | ++------------+-----------+ +| SHARP | 150 | ++------------+-----------+ +| IBGP | 200 | ++------------+-----------+ +| PBR | 200 | ++------------+-----------+ + +An admin distance of 255 indicates to Zebra that the route should not be +installed into the Data Plane. Additionally routes with an admin distance +of 255 will not be redistributed. + +Zebra does treat Kernel routes as special case for the purposes of Admin +Distance. Upon learning about a route that is not originated by FRR +we read the metric value as a uint32_t. The top byte of the value +is interpreted as the Administrative Distance and the low three bytes +are read in as the metric. This special case is to facilitate VRF +default routes. + Virtual Routing and Forwarding ============================== @@ -374,6 +430,14 @@ commands in relationship to VRF. Here is an extract of some of those commands: This command will dump the routing tables within the vrf scope. If `vrf all` is executed, all routing tables will be dumped. +.. index:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix] +.. clicmd:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix] + + This command will dump a summary output of the specified VRF and TABLENO + combination. If neither VRF or TABLENO is specified FRR defaults to + the default vrf and default table. If prefix is specified dump the + number of prefix routes. + By using the :option:`-n` option, the *Linux network namespace* will be mapped over the *Zebra* VRF. One nice feature that is possible by handling *Linux network namespace* is the ability to name default VRF. At startup, *Zebra* diff --git a/lib/command.c b/lib/command.c index de28a726b0..eecca2a5f5 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1061,8 +1061,10 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, vty->num_cfg_changes = 0; memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes)); - /* Regenerate candidate configuration. */ - if (frr_get_cli_mode() == FRR_CLI_CLASSIC) + /* Regenerate candidate configuration if necessary. */ + if (frr_get_cli_mode() == FRR_CLI_CLASSIC + && running_config->version + > vty->candidate_config->version) nb_config_replace(vty->candidate_config, running_config, true); } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 5a29c1fb07..a508ae657f 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1362,11 +1362,12 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, case NSM_Down: case NSM_Attempt: case NSM_TwoWay: - flog_warn( - EC_OSPF_PACKET, - "Packet[DD]: Neighbor %s state is %s, packet discarded.", - inet_ntoa(nbr->router_id), - lookup_msg(ospf_nsm_state_msg, nbr->state, NULL)); + if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) + zlog_info( + "Packet[DD]: Neighbor %s state is %s, packet discarded.", + inet_ntoa(nbr->router_id), + lookup_msg(ospf_nsm_state_msg, nbr->state, + NULL)); break; case NSM_Init: OSPF_NSM_EVENT_EXECUTE(nbr, NSM_TwoWayReceived); diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 3aa2a92241..53ab22754c 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -259,11 +259,11 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, curr += offset; curr_size -= offset; - if (curr_size != 8) { + if (curr_size < 8) { char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); zlog_warn( - "%s: preference/metric size is not 8: size=%d from %s on interface %s", + "%s: preference/metric size is less than 8 bytes: size=%d from %s on interface %s", __PRETTY_FUNCTION__, curr_size, src_str, ifp->name); return -3; } diff --git a/tests/topotests/Dockerfile b/tests/topotests/Dockerfile index 4602688782..fc6d6df530 100644 --- a/tests/topotests/Dockerfile +++ b/tests/topotests/Dockerfile @@ -19,6 +19,7 @@ RUN export DEBIAN_FRONTEND=noninteractive \ libpython-dev \ libreadline-dev \ libc-ares-dev \ + libcap-dev \ man \ mininet \ pkg-config \ diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref index 0a20231371..a7d6fe11a6 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref @@ -15,6 +15,7 @@ S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX S>* 4.5.6.13/32 [1/0] unreachable (blackhole), XX:XX:XX S>* 4.5.6.14/32 [1/0] unreachable (blackhole), XX:XX:XX +S 4.5.6.15/32 [255/0] via 192.168.0.2, r1-eth0, XX:XX:XX S>* 4.5.6.7/32 [1/0] unreachable (blackhole), XX:XX:XX S>* 4.5.6.8/32 [1/0] unreachable (blackhole), XX:XX:XX S>* 4.5.6.9/32 [1/0] unreachable (ICMP unreachable), XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref index 6e3e9c87c1..d5bc16a2bf 100644 --- a/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref +++ b/tests/topotests/all-protocol-startup/r1/ipv6_routes.ref @@ -20,9 +20,10 @@ C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, XX:XX:XX -S>* 4:5::/32 [1/0] is directly connected, r1-eth0, XX:XX:XX S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, XX:XX:XX +S>* 4:5::6:12/128 [1/0] is directly connected, r1-eth0, XX:XX:XX +S 4:5::6:15/128 [255/0] via fc00::2, r1-eth0, XX:XX:XX S>* 4:5::6:7/128 [1/0] unreachable (blackhole), XX:XX:XX S>* 4:5::6:8/128 [1/0] unreachable (blackhole), XX:XX:XX S>* 4:5::6:9/128 [1/0] unreachable (ICMP unreachable), XX:XX:XX diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf index c621593ef7..85c8676964 100644 --- a/tests/topotests/all-protocol-startup/r1/zebra.conf +++ b/tests/topotests/all-protocol-startup/r1/zebra.conf @@ -20,7 +20,12 @@ ip route 4.5.6.11/32 192.168.0.2 r1-eth0 ipv6 route 4:5::6:11/128 fc00:0:0:0::2 r1-eth0 # Create ifname routes ip route 4.5.6.12/32 r1-eth0 -ipv6 route 4:5::6:12/32 r1-eth0 +ipv6 route 4:5::6:12/128 r1-eth0 +# Create a route that has a large admin distance +# an admin distance of 255 should be accepted +# by zebra but not installed. +ip route 4.5.6.15/32 192.168.0.2 255 +ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255 ! interface r1-eth0 description to sw0 - no routing protocol diff --git a/tests/topotests/bgp_aggregate-address_route-map/__init__.py b/tests/topotests/bgp_aggregate-address_route-map/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/__init__.py diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf new file mode 100644 index 0000000000..ef34817bb1 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65000 + neighbor 192.168.255.2 remote-as 65001 + address-family ipv4 unicast + redistribute connected + aggregate-address 172.16.255.0/24 route-map aggr-rmap + exit-address-family +! +route-map aggr-rmap permit 10 + set metric 123 +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf new file mode 100644 index 0000000000..0a283c06d5 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r1/zebra.conf @@ -0,0 +1,9 @@ +! +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf new file mode 100644 index 0000000000..73d4d0aeea --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf @@ -0,0 +1,4 @@ +router bgp 65001 + neighbor 192.168.255.1 remote-as 65000 + exit-address-family +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py new file mode 100644 index 0000000000..bee5115323 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python + +# +# bgp_aggregate-address_route-map.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +bgp_aggregate-address_route-map.py: + +Test if works the following commands: +router bgp 65031 + address-family ipv4 unicast + aggregate-address 192.168.255.0/24 route-map aggr-rmap + +route-map aggr-rmap permit 10 + set metric 123 +""" + +import os +import sys +import json +import time +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_maximum_prefix_invalid(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_converge(router): + while True: + output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + if output['192.168.255.1']['bgpState'] == 'Established': + if output['192.168.255.1']['addressFamilyInfo']['ipv4Unicast']['acceptedPrefixCounter'] == 3: + return True + + def _bgp_aggregate_address_has_metric(router): + output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.0/24 json")) + if output['paths'][0]['med'] == 123: + return True + return False + + if _bgp_converge('r2'): + assert _bgp_aggregate_address_has_metric('r2') == True + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index 853d823880..0c62954570 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -23,6 +23,11 @@ module frr-eigrpd { description "This module defines a model for managing FRR eigrpd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2019-06-19 { description "Initial revision."; reference @@ -94,9 +99,7 @@ module frr-eigrpd { leaf-list passive-interface { description "List of suppressed interfaces"; - type string { - length "1..16"; - } + type frr-interface:interface-ref; } leaf active-time { diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang index d3cc66dfaa..4f7f3beebd 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -11,6 +11,10 @@ module frr-interface { description "This module defines a model for managing FRR interfaces."; + revision 2019-09-09 { + description + "Added interface-ref typedef"; + } revision 2018-03-28 { description "Initial revision."; @@ -43,4 +47,13 @@ module frr-interface { } } } + + typedef interface-ref { + type leafref { + require-instance false; + path "/frr-interface:lib/frr-interface:interface/frr-interface:name"; + } + description + "Reference to an interface"; + } } diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 9180b0c5f3..3313dc2f20 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -27,6 +27,11 @@ module frr-isisd { description "This module defines a model for managing FRR isisd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2018-07-26 { description "Initial revision."; @@ -296,7 +301,7 @@ module frr-isisd { description "Interface specific IS-IS notification data grouping"; leaf interface-name { - type string; + type frr-interface:interface-ref; description "IS-IS interface name"; } diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang index 07690793f0..94a9ebf3e1 100644 --- a/yang/frr-ripd.yang +++ b/yang/frr-ripd.yang @@ -24,6 +24,11 @@ module frr-ripd { description "This module defines a model for managing FRR ripd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2017-12-06 { description "Initial revision."; @@ -113,9 +118,7 @@ module frr-ripd { "Enable RIP on the specified IP network."; } leaf-list interface { - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "Enable RIP on the specified interface."; } @@ -124,7 +127,15 @@ module frr-ripd { description "Offset-list to modify route metric."; leaf interface { - type string; + type union { + type frr-interface:interface-ref; + type enumeration { + enum '*' { + description + "Match all interfaces."; + } + } + } description "Interface to match. Use '*' to match all interfaces."; } @@ -168,18 +179,14 @@ module frr-ripd { } leaf-list passive-interface { when "../passive-default = 'false'"; - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "A list of interfaces where the sending of RIP packets is disabled."; } leaf-list non-passive-interface { when "../passive-default = 'true'"; - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "A list of interfaces where the sending of RIP packets is enabled."; diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang index b341b438a4..831758af86 100644 --- a/yang/frr-ripngd.yang +++ b/yang/frr-ripngd.yang @@ -24,6 +24,11 @@ module frr-ripngd { description "This module defines a model for managing FRR ripngd daemon."; + revision 2019-09-09 { + description + "Changed interface references to use + frr-interface:interface-ref typedef"; + } revision 2018-11-27 { description "Initial revision."; @@ -71,9 +76,7 @@ module frr-ripngd { "Enable RIPng on the specified IPv6 network."; } leaf-list interface { - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "Enable RIPng on the specified interface."; } @@ -82,7 +85,15 @@ module frr-ripngd { description "Offset-list to modify route metric."; leaf interface { - type string; + type union { + type frr-interface:interface-ref; + type enumeration { + enum '*' { + description + "Match all interfaces."; + } + } + } description "Interface to match. Use '*' to match all interfaces."; } @@ -118,9 +129,7 @@ module frr-ripngd { } } leaf-list passive-interface { - type string { - length "1..16"; - } + type frr-interface:interface-ref; description "A list of interfaces where the sending of RIPng packets is disabled."; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 5edcf9bb8a..91a3024038 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2304,13 +2304,7 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) } req; int ret; int dst_alen; - struct zebra_if *zif; - struct interface *br_if; - struct zebra_if *br_zif; int vid_present = 0; - char vid_buf[20]; - struct zebra_ns *zns; - struct interface *ifp; int cmd; struct in_addr vtep_ip; vlanid_t vid; @@ -2320,42 +2314,6 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) else cmd = RTM_DELNEIGH; - /* Locate zebra ns and interface objects from context data */ - zns = zebra_ns_lookup(dplane_ctx_get_ns(ctx)->ns_id); - if (zns == NULL) { - /* Nothing to be done */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("MAC %s on IF %s(%u) - zebra ns unknown", - (cmd == RTM_NEWNEIGH) ? "add" : "del", - dplane_ctx_get_ifname(ctx), - dplane_ctx_get_ifindex(ctx)); - - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - ifp = if_lookup_by_index_per_ns(zns, dplane_ctx_get_ifindex(ctx)); - if (ifp == NULL) { - /* Nothing to be done */ - /* Nothing to be done */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("MAC %s on IF %s(%u) - interface unknown", - (cmd == RTM_NEWNEIGH) ? "add" : "del", - dplane_ctx_get_ifname(ctx), - dplane_ctx_get_ifindex(ctx)); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - - vid = dplane_ctx_mac_get_vlan(ctx); - - zif = ifp->info; - if ((br_if = zif->brslave_info.br_if) == NULL) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("MAC %s on IF %s(%u) - no mapping to bridge", - (cmd == RTM_NEWNEIGH) ? "add" : "del", - ifp->name, ifp->ifindex); - return ZEBRA_DPLANE_REQUEST_FAILURE; - } - memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); @@ -2374,24 +2332,31 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) addattr_l(&req.n, sizeof(req), NDA_LLADDR, dplane_ctx_mac_get_addr(ctx), 6); - req.ndm.ndm_ifindex = ifp->ifindex; + req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); dst_alen = 4; // TODO: hardcoded vtep_ip = *(dplane_ctx_mac_get_vtep_ip(ctx)); addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip, dst_alen); - br_zif = (struct zebra_if *)br_if->info; - if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) { + vid = dplane_ctx_mac_get_vlan(ctx); + + if (vid > 0) { addattr16(&req.n, sizeof(req), NDA_VLAN, vid); vid_present = 1; - sprintf(vid_buf, " VLAN %u", vid); } - addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + addattr32(&req.n, sizeof(req), NDA_MASTER, + dplane_ctx_mac_get_br_ifindex(ctx)); if (IS_ZEBRA_DEBUG_KERNEL) { char ipbuf[PREFIX_STRLEN]; char buf[ETHER_ADDR_STRLEN]; char dst_buf[PREFIX_STRLEN + 10]; + char vid_buf[20]; + + if (vid_present) + snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid); + else + vid_buf[0] = '\0'; inet_ntop(AF_INET, &vtep_ip, ipbuf, sizeof(ipbuf)); snprintf(dst_buf, sizeof(dst_buf), " dst %s", ipbuf); @@ -2399,8 +2364,9 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s%s", nl_msg_type_to_str(cmd), - nl_family_to_str(req.ndm.ndm_family), ifp->name, - ifp->ifindex, vid_present ? vid_buf : "", + nl_family_to_str(req.ndm.ndm_family), + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx), vid_buf, dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "", buf, dst_buf); } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 2bf541617c..12f8a1ae3d 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -152,6 +152,7 @@ struct dplane_intf_info { */ struct dplane_mac_info { vlanid_t vid; + ifindex_t br_ifindex; struct ethaddr mac; struct in_addr vtep_ip; bool is_sticky; @@ -377,6 +378,7 @@ static enum zebra_dplane_result intf_addr_update_internal( enum dplane_op_e op); static enum zebra_dplane_result mac_update_internal( enum dplane_op_e op, const struct interface *ifp, + const struct interface *br_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, bool sticky); static enum zebra_dplane_result neigh_update_internal( @@ -1272,6 +1274,12 @@ const struct in_addr *dplane_ctx_mac_get_vtep_ip( return &(ctx->u.macinfo.vtep_ip); } +ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.macinfo.br_ifindex; +} + /* Accessors for neighbor information */ const struct ipaddr *dplane_ctx_neigh_get_ipaddr( const struct zebra_dplane_ctx *ctx) @@ -2134,6 +2142,7 @@ static enum zebra_dplane_result intf_addr_update_internal( * Enqueue vxlan/evpn mac add (or update). */ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, @@ -2142,8 +2151,8 @@ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, enum zebra_dplane_result result; /* Use common helper api */ - result = mac_update_internal(DPLANE_OP_MAC_INSTALL, ifp, vid, - mac, vtep_ip, sticky); + result = mac_update_internal(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp, + vid, mac, vtep_ip, sticky); return result; } @@ -2151,6 +2160,7 @@ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, * Enqueue vxlan/evpn mac delete. */ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip) @@ -2158,8 +2168,8 @@ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, enum zebra_dplane_result result; /* Use common helper api */ - result = mac_update_internal(DPLANE_OP_MAC_DELETE, ifp, vid, mac, - vtep_ip, false); + result = mac_update_internal(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, + vid, mac, vtep_ip, false); return result; } @@ -2169,6 +2179,7 @@ enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, static enum zebra_dplane_result mac_update_internal(enum dplane_op_e op, const struct interface *ifp, + const struct interface *br_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, @@ -2204,6 +2215,7 @@ mac_update_internal(enum dplane_op_e op, /* Init the mac-specific data area */ memset(&ctx->u.macinfo, 0, sizeof(ctx->u.macinfo)); + ctx->u.macinfo.br_ifindex = br_ifp->ifindex; ctx->u.macinfo.vtep_ip = vtep_ip; ctx->u.macinfo.mac = *mac; ctx->u.macinfo.vid = vid; diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 31f0fc98b3..30dfdafdf5 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -328,6 +328,7 @@ const struct ethaddr *dplane_ctx_mac_get_addr( const struct zebra_dplane_ctx *ctx); const struct in_addr *dplane_ctx_mac_get_vtep_ip( const struct zebra_dplane_ctx *ctx); +ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx); /* Accessors for neighbor information */ const struct ipaddr *dplane_ctx_neigh_get_ipaddr( @@ -402,12 +403,14 @@ enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp, * Enqueue evpn mac operations for the dataplane. */ enum zebra_dplane_result dplane_mac_add(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip, bool sticky); enum zebra_dplane_result dplane_mac_del(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, const struct ethaddr *mac, struct in_addr vtep_ip); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ee2956d3ea..35df02a19a 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -122,6 +122,33 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, _nexthop_add(&nexthop->resolved, resolved_hop); } +/* Checks if nexthop we are trying to resolve to is valid */ +static bool nexthop_valid_resolve(const struct nexthop *nexthop, + const struct nexthop *resolved) +{ + /* Can't resolve to a recursive nexthop */ + if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE)) + return false; + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + /* If the nexthop we are resolving to does not match the + * ifindex for the nexthop the route wanted, its not valid. + */ + if (nexthop->ifindex != resolved->ifindex) + return false; + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: + break; + } + + return true; +} + /* * Given a nexthop we need to properly recursively resolve * the route. As such, do a table lookup to find and match @@ -287,8 +314,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; - if (CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_RECURSIVE)) + if (!nexthop_valid_resolve(nexthop, newhop)) continue; SET_FLAG(nexthop->flags, @@ -308,8 +334,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; - if (CHECK_FLAG(newhop->flags, - NEXTHOP_FLAG_RECURSIVE)) + if (!nexthop_valid_resolve(nexthop, newhop)) continue; SET_FLAG(nexthop->flags, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 38de01e228..7984481093 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1384,35 +1384,37 @@ DEFPY (show_route_detail, DEFPY (show_route_summary, show_route_summary_cmd, - "show\ - <\ - ip$ipv4 route [vrf <NAME$vrf_name|all$vrf_all>]\ - summary [prefix$prefix]\ - |ipv6$ipv6 route [vrf <NAME$vrf_name|all$vrf_all>]\ - summary [prefix$prefix]\ - >", + "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] \ + summary [table (1-4294967295)$table_id] [prefix$prefix]", SHOW_STR IP_STR - "IP routing table\n" - VRF_FULL_CMD_HELP_STR - "Summary of all routes\n" - "Prefix routes\n" IP6_STR "IP routing table\n" VRF_FULL_CMD_HELP_STR "Summary of all routes\n" + "Table to display summary for\n" + "The table number\n" "Prefix routes\n") { afi_t afi = ipv4 ? AFI_IP : AFI_IP6; struct route_table *table; + if (table_id == 0) + table_id = RT_TABLE_MAIN; + if (vrf_all) { struct vrf *vrf; struct zebra_vrf *zvrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - if ((zvrf = vrf->info) == NULL - || (table = zvrf->table[afi][SAFI_UNICAST]) == NULL) + if ((zvrf = vrf->info) == NULL) + continue; + + table = zebra_vrf_table_with_table_id(afi, + SAFI_UNICAST, + zvrf->vrf->vrf_id, + table_id); + if (!table) continue; if (prefix) @@ -1426,7 +1428,9 @@ DEFPY (show_route_summary, if (vrf_name) VRF_GET_ID(vrf_id, vrf_name, false); - table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); + table = zebra_vrf_table_with_table_id(afi, + SAFI_UNICAST, + vrf_id, table_id); if (!table) return CMD_SUCCESS; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index bb8b61e7e3..c7f2976ace 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2553,8 +2553,9 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n) return 0; if (!zvni->vxlan_if) { - zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", - zvni->vni, zvni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", + zvni->vni, zvni); return -1; } @@ -2843,9 +2844,12 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, /* mac entry should be present */ mac = zvni_mac_lookup(zvni, &n->emac); if (!mac) { - zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u", - prefix_mac2str(&n->emac, buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u", + prefix_mac2str(&n->emac, + buf1, sizeof(buf1)), + ipaddr2str(ip, buf2, sizeof(buf2)), + zvni->vni); return -1; } @@ -3736,10 +3740,12 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) */ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) { - struct zebra_if *zif; - struct zebra_l2info_vxlan *vxl; + const struct zebra_if *zif, *br_zif; + const struct zebra_l2info_vxlan *vxl; bool sticky; enum zebra_dplane_result res; + const struct interface *br_ifp; + vlanid_t vid; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; @@ -3747,13 +3753,25 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) zif = zvni->vxlan_if->info; if (!zif) return -1; + + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; sticky = !!CHECK_FLAG(mac->flags, (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); - res = dplane_mac_add(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, - mac->fwd_info.r_vtep_ip, sticky); + br_zif = (const struct zebra_if *)(br_ifp->info); + + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + + res = dplane_mac_add(zvni->vxlan_if, br_ifp, vid, + &mac->macaddr, mac->fwd_info.r_vtep_ip, sticky); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; else @@ -3765,30 +3783,44 @@ static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) */ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) { - struct zebra_if *zif; - struct zebra_l2info_vxlan *vxl; + const struct zebra_if *zif, *br_zif; + const struct zebra_l2info_vxlan *vxl; struct in_addr vtep_ip; - struct interface *ifp; + const struct interface *ifp, *br_ifp; + vlanid_t vid; enum zebra_dplane_result res; if (!(mac->flags & ZEBRA_MAC_REMOTE)) return 0; if (!zvni->vxlan_if) { - zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", - zvni->vni, zvni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", + zvni->vni, zvni); return -1; } zif = zvni->vxlan_if->info; if (!zif) return -1; + + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; + br_zif = (const struct zebra_if *)br_ifp->info; + + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + ifp = zvni->vxlan_if; vtep_ip = mac->fwd_info.r_vtep_ip; - res = dplane_mac_del(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip); + res = dplane_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; else @@ -4491,9 +4523,11 @@ static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) */ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) { - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl = NULL; + const struct zebra_if *zif = NULL, *br_zif = NULL; + const struct zebra_l2info_vxlan *vxl = NULL; + const struct interface *br_ifp; enum zebra_dplane_result res; + vlanid_t vid; if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) @@ -4503,9 +4537,20 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) if (!zif) return -1; + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; - res = dplane_mac_add(zl3vni->vxlan_if, vxl->access_vlan, + br_zif = (const struct zebra_if *)br_ifp->info; + + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + + res = dplane_mac_add(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; @@ -4519,8 +4564,10 @@ static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) { char buf[ETHER_ADDR_STRLEN]; - struct zebra_if *zif = NULL; - struct zebra_l2info_vxlan *vxl = NULL; + const struct zebra_if *zif = NULL, *br_zif; + const struct zebra_l2info_vxlan *vxl = NULL; + const struct interface *br_ifp; + vlanid_t vid; enum zebra_dplane_result res; if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) @@ -4528,10 +4575,12 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) return 0; if (!zl3vni->vxlan_if) { - zlog_debug( - "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", - prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), - zl3vni->vni, zl3vni); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", + prefix_mac2str(&zrmac->macaddr, + buf, sizeof(buf)), + zl3vni->vni, zl3vni); return -1; } @@ -4539,9 +4588,19 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) if (!zif) return -1; + br_ifp = zif->brslave_info.br_if; + if (br_ifp == NULL) + return -1; + vxl = &zif->l2info.vxl; - res = dplane_mac_del(zl3vni->vxlan_if, vxl->access_vlan, + br_zif = (const struct zebra_if *)br_ifp->info; + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + vid = vxl->access_vlan; + else + vid = 0; + + res = dplane_mac_del(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; |
