diff options
| -rw-r--r-- | bgpd/bgp_routemap.c | 11 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 27 | ||||
| -rw-r--r-- | lib/log.c | 4 | ||||
| -rw-r--r-- | ospfd/ospf_flood.c | 25 | ||||
| -rw-r--r-- | ospfd/ospf_lsa.c | 160 | ||||
| -rw-r--r-- | ospfd/ospf_lsa.h | 4 | ||||
| -rw-r--r-- | ospfd/ospf_nsm.c | 28 | ||||
| -rw-r--r-- | ospfd/ospf_vty.c | 17 | ||||
| -rw-r--r-- | ospfd/ospf_zebra.c | 132 | ||||
| -rw-r--r-- | ospfd/ospfd.c | 32 | ||||
| -rw-r--r-- | ospfd/ospfd.h | 2 | ||||
| -rw-r--r-- | sharpd/sharp_zebra.c | 2 | ||||
| -rw-r--r-- | vrrpd/vrrp.c | 29 | ||||
| -rw-r--r-- | vrrpd/vrrp_zebra.c | 8 | ||||
| -rw-r--r-- | vtysh/vtysh_config.c | 38 | ||||
| -rw-r--r-- | yang/frr-filter.yang | 353 | ||||
| -rw-r--r-- | yang/frr-route-map.yang | 404 | ||||
| -rw-r--r-- | zebra/if_netlink.c | 6 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 5 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 69 |
20 files changed, 1014 insertions, 342 deletions
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 04043fdc8e..5ffc416dc5 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2091,12 +2091,19 @@ route_set_lcommunity_delete(void *rule, const struct prefix *pfx, static void *route_set_lcommunity_delete_compile(const char *arg) { struct rmap_community *rcom; + char **splits; + int num; - rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + frrstr_split(arg, " ", &splits, &num); - rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]); rcom->name_hash = bgp_clist_hash_key(rcom->name); + for (int i = 0; i < num; i++) + XFREE(MTYPE_TMP, splits[i]); + XFREE(MTYPE_TMP, splits); + return rcom; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 27042017dd..58a202d510 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7770,7 +7770,7 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json) /* Show BGP peer's summary information. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, - bool use_json, json_object *json) + bool use_json) { struct peer *peer; struct listnode *node, *nnode; @@ -7781,6 +7781,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, int len; int max_neighbor_width = 0; int pfx_rcd_safi; + json_object *json = NULL; json_object *json_peer = NULL; json_object *json_peers = NULL; struct peer_af *paf; @@ -7795,9 +7796,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, pfx_rcd_safi = safi; if (use_json) { - if (json == NULL) - json = json_object_new_object(); - + json = json_object_new_object(); json_peers = json_object_new_object(); } else { /* Loop over all neighbors that will be displayed to determine @@ -8202,8 +8201,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, } static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, - int safi, bool use_json, - json_object *json) + int safi, bool use_json) { int is_first = 1; int afi_wildcard = (afi == AFI_MAX); @@ -8221,6 +8219,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, while (safi < SAFI_MAX) { if (bgp_afi_safi_peer_exists(bgp, afi, safi)) { nbr_output = true; + if (is_wildcard) { /* * So limit output to those afi/safi @@ -8229,8 +8228,6 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, * them */ if (use_json) { - json = json_object_new_object(); - if (!is_first) vty_out(vty, ",\n"); else @@ -8245,8 +8242,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, safi)); } } - bgp_show_summary(vty, bgp, afi, safi, use_json, - json); + bgp_show_summary(vty, bgp, afi, safi, use_json); } safi++; if (!safi_wildcard) @@ -8272,7 +8268,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, { struct listnode *node, *nnode; struct bgp *bgp; - json_object *json = NULL; int is_first = 1; bool nbr_output = false; @@ -8282,8 +8277,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { nbr_output = true; if (use_json) { - json = json_object_new_object(); - if (!is_first) vty_out(vty, ",\n"); else @@ -8299,7 +8292,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, ? VRF_DEFAULT_NAME : bgp->name); } - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, json); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json); } if (use_json) @@ -8330,8 +8323,8 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, return CMD_WARNING; } - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, - NULL); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, + use_json); return CMD_SUCCESS; } } @@ -8339,7 +8332,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, bgp = bgp_get_default(); if (bgp) - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, NULL); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json); else { if (use_json) vty_out(vty, "{}\n"); @@ -387,10 +387,8 @@ void vzlog(int priority, const char *format, va_list args) /* If it doesn't match on a filter, do nothing with the debug log */ if ((priority == LOG_DEBUG) && zlog_filter_count - && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) { - pthread_mutex_unlock(&loglock); + && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) goto out; - } /* call external hook */ hook_call(zebra_ext_log, priority, format, args); diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 6d1e44996e..1d85a04984 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -83,6 +83,9 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, struct as_external_lsa *al; struct prefix_ipv4 p; struct route_node *rn; + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; int type; al = (struct as_external_lsa *)lsa->data; @@ -91,7 +94,7 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, p.prefix = lsa->data->id; p.prefixlen = ip_masklen(al->mask); - for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { int redist_on = 0; redist_on = @@ -105,10 +108,6 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, ospf->vrf_id)); // Pending: check for MI above. if (redist_on) { - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - ext_list = ospf->external[type]; if (!ext_list) continue; @@ -129,6 +128,22 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, } } + if (is_prefix_default(&p) && ospf->external[DEFAULT_ROUTE]) { + ext_list = ospf->external[DEFAULT_ROUTE]; + + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + if (!ext->external_info) + continue; + + rn = route_node_lookup(ext->external_info, + (struct prefix *)&p); + if (!rn) + continue; + route_unlock_node(rn); + if (rn->info != NULL) + return (struct external_info *)rn->info; + } + } return NULL; } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index bf46d22031..db41df7c47 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1979,6 +1979,13 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, */ + if (ospf->router_id.s_addr == 0) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero", + &ei->p.prefix); + return NULL; + } + /* Check the AS-external-LSA should be originated. */ if (!ospf_redistribute_check(ospf, ei, NULL)) return NULL; @@ -2019,50 +2026,6 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, return new; } -/* Originate AS-external-LSA from external info with initial flag. */ -int ospf_external_lsa_originate_timer(struct thread *thread) -{ - struct ospf *ospf = THREAD_ARG(thread); - struct route_node *rn; - struct external_info *ei; - struct route_table *rt; - int type = THREAD_VAL(thread); - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - - ospf->t_external_lsa = NULL; - - ext_list = ospf->external[type]; - if (!ext_list) - return 0; - - for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { - /* Originate As-external-LSA from all type of distribute source. - */ - rt = ext->external_info; - if (!rt) - continue; - - for (rn = route_top(rt); rn; rn = route_next(rn)) { - ei = rn->info; - - if (!ei) - continue; - - if (is_prefix_default((struct prefix_ipv4 *)&ei->p)) - continue; - - if (!ospf_external_lsa_originate(ospf, ei)) - flog_warn( - EC_OSPF_LSA_INSTALL_FAILURE, - "LSA: AS-external-LSA was not originated."); - } - } - - return 0; -} - static struct external_info *ospf_default_external_info(struct ospf *ospf) { int type; @@ -2102,31 +2065,52 @@ static struct external_info *ospf_default_external_info(struct ospf *ospf) return NULL; } -int ospf_default_originate_timer(struct thread *thread) +void ospf_external_lsa_rid_change(struct ospf *ospf) { - struct prefix_ipv4 p; - struct in_addr nexthop; struct external_info *ei; - struct ospf *ospf; + int type; - ospf = THREAD_ARG(thread); + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { + struct route_node *rn; + struct route_table *rt; + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; + ext_list = ospf->external[type]; + if (!ext_list) + continue; - if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) { - /* 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(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop, - 0); - } + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + /* Originate As-external-LSA from all type of + * distribute source. + */ + rt = ext->external_info; + if (!rt) + continue; - if ((ei = ospf_default_external_info(ospf))) - ospf_external_lsa_originate(ospf, ei); + for (rn = route_top(rt); rn; rn = route_next(rn)) { + ei = rn->info; - return 0; + if (!ei) + continue; + + if (is_prefix_default( + (struct prefix_ipv4 *)&ei->p)) + continue; + + if (!ospf_external_lsa_originate(ospf, ei)) + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "LSA: AS-external-LSA was not originated."); + } + } + } + + ei = ospf_default_external_info(ospf); + if (ei && !ospf_external_lsa_originate(ospf, ei)) { + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "LSA: AS-external-LSA for default route was not originated."); + } } /* Flush any NSSA LSAs for given prefix */ @@ -2218,44 +2202,20 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf) ei = ospf_default_external_info(ospf); lsa = ospf_external_info_find_lsa(ospf, &p); - if (ei) { - if (lsa) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", - (void *)lsa); - ospf_external_lsa_refresh(ospf, lsa, ei, - LSA_REFRESH_FORCE); - } else { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); - ospf_external_lsa_originate(ospf, ei); - } - } else { - if (lsa) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); - ospf_refresher_unregister_lsa(ospf, lsa); - ospf_lsa_flush_as(ospf, lsa); - } - } -} - -void ospf_default_originate_lsa_update(struct ospf *ospf) -{ - struct prefix_ipv4 p; - struct ospf_lsa *lsa; - - p.family = AF_INET; - p.prefixlen = 0; - p.prefix.s_addr = 0; - - lsa = ospf_external_info_find_lsa(ospf, &p); - if (lsa && IS_LSA_MAXAGE(lsa)) { - ospf_discard_from_db(ospf, lsa->lsdb, lsa); - ospf_lsdb_delete(lsa->lsdb, lsa); + if (ei && lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", + (void *)lsa); + ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE); + } else if (ei && !lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); + ospf_external_lsa_originate(ospf, ei); + } else if (lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); + ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); } } diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 5e3dabc27a..4033659bff 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -275,8 +275,7 @@ extern struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *); extern struct ospf_lsa *ospf_external_lsa_originate(struct ospf *, struct external_info *); -extern int ospf_external_lsa_originate_timer(struct thread *); -extern int ospf_default_originate_timer(struct thread *); +extern void ospf_external_lsa_rid_change(struct ospf *ospf); extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *, uint32_t, struct in_addr, struct in_addr); @@ -301,7 +300,6 @@ extern int ospf_lsa_maxage_walker(struct thread *); extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *, struct ospf_lsa *); extern void ospf_external_lsa_refresh_default(struct ospf *); -extern void ospf_default_originate_lsa_update(struct ospf *ospf); extern void ospf_external_lsa_refresh_type(struct ospf *, uint8_t, unsigned short, int); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index f7c73fee33..ee27ec0942 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -616,8 +616,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) struct ospf_interface *oi = nbr->oi; struct ospf_area *vl_area = NULL; uint8_t old_state; - int x; - int force = 1; /* Preserve old status. */ old_state = nbr->state; @@ -664,32 +662,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) if (++vl_area->full_vls == 1) ospf_schedule_abr_task(oi->ospf); - - /* kevinm: refresh any redistributions */ - for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++) { - struct list *red_list; - struct listnode *node; - struct ospf_redist *red; - - if (x == ZEBRA_ROUTE_OSPF6) - continue; - - red_list = oi->ospf->redist[x]; - if (!red_list) - continue; - - for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) - ospf_external_lsa_refresh_type( - oi->ospf, x, red->instance, - force); - } - /* XXX: Clearly some thing is wrong with refresh of - * external LSAs - * this added to hack around defaults not refreshing - * after a timer - * jump. - */ - ospf_external_lsa_refresh_default(oi->ospf); } else { oi->full_nbrs--; oi->area->full_nbrs--; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 98ddd6a79e..2564c6f330 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -8487,22 +8487,8 @@ DEFUN (no_ospf_default_information_originate, "Pointer to route-map entries\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - struct prefix_ipv4 p; - struct ospf_external *ext; struct ospf_redist *red; - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; - - ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 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); if (!red) return CMD_SUCCESS; @@ -8510,7 +8496,8 @@ DEFUN (no_ospf_default_information_originate, ospf_routemap_unset(red); ospf_redist_del(ospf, DEFAULT_ROUTE, 0); - return ospf_redistribute_default_unset(ospf); + return ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, + 0, 0); } DEFUN (ospf_default_metric, diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 951402f47f..47438b985e 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -744,10 +744,10 @@ int ospf_redistribute_unset(struct ospf *ospf, int type, int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, int mvalue) { - struct ospf_external *ext; struct prefix_ipv4 p; struct in_addr nexthop; int cur_originate = ospf->default_originate; + const char *type_str = NULL; nexthop.s_addr = 0; p.family = AF_INET; @@ -756,41 +756,7 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, ospf->default_originate = originate; - ospf_external_add(ospf, DEFAULT_ROUTE, 0); - - if (cur_originate == DEFAULT_ORIGINATE_NONE) { - /* First time configuration */ - if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", - metric_type(ospf, DEFAULT_ROUTE, 0), - metric_value(ospf, DEFAULT_ROUTE, 0)); - - if (ospf->router_id.s_addr == 0) - ospf->external_origin |= (1 << DEFAULT_ROUTE); - if ((originate == DEFAULT_ORIGINATE_ALWAYS) - && (ospf->router_id.s_addr)) { - - /* always , so originate lsa even it doesn't - * exist in RIB. - */ - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, - p, 0, nexthop, 0); - ospf_external_lsa_refresh_default(ospf); - - } else if (originate == DEFAULT_ORIGINATE_ZEBRA) { - /* Send msg to Zebra to validate default route - * existance. - */ - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, AFI_IP, - ospf->vrf_id); - } - - ospf_asbr_status_update(ospf, ++ospf->redistribute); - return CMD_SUCCESS; - - - } else if (originate == cur_originate) { + if (cur_originate == originate) { /* Refresh the lsa since metric might different */ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) zlog_debug( @@ -800,67 +766,51 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, metric_value(ospf, DEFAULT_ROUTE, 0)); ospf_external_lsa_refresh_default(ospf); - - } else { - /* "default-info originate always" configured now, - * where "default-info originate" configured previoulsly. - */ - if (originate == DEFAULT_ORIGINATE_ALWAYS) { - - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, - zclient, AFI_IP, ospf->vrf_id); - /* here , ex-info should be added since ex-info might - * have not updated earlier if def route is not exist. - * If ex-iinfo ex-info already exist , it will return - * smoothly. - */ - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, - p, 0, nexthop, 0); - ospf_external_lsa_refresh_default(ospf); - - } else { - /* "default-info originate" configured now,where - * "default-info originate always" configured - * previoulsy. - */ - - ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); - - ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0); - if (ext && EXTERNAL_INFO(ext)) - ospf_external_info_delete(ospf, - DEFAULT_ROUTE, 0, p); - - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_ADD, - zclient, AFI_IP, ospf->vrf_id); - } + return CMD_SUCCESS; } - return CMD_SUCCESS; -} -int ospf_redistribute_default_unset(struct ospf *ospf) -{ - if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) { - if (!ospf_is_type_redistributed(ospf, DEFAULT_ROUTE, 0)) - return CMD_SUCCESS; + switch (cur_originate) { + case DEFAULT_ORIGINATE_NONE: + break; + case DEFAULT_ORIGINATE_ZEBRA: zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, AFI_IP, ospf->vrf_id); + ospf->redistribute--; + break; + case DEFAULT_ORIGINATE_ALWAYS: + ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p); + ospf_external_del(ospf, DEFAULT_ROUTE, 0); + ospf->redistribute--; + break; } - ospf->default_originate = DEFAULT_ORIGINATE_NONE; + switch (originate) { + case DEFAULT_ORIGINATE_NONE: + type_str = "none"; + break; + case DEFAULT_ORIGINATE_ZEBRA: + type_str = "normal"; + ospf->redistribute++; + zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, + zclient, AFI_IP, ospf->vrf_id); + break; + case DEFAULT_ORIGINATE_ALWAYS: + type_str = "always"; + ospf->redistribute++; + ospf_external_add(ospf, DEFAULT_ROUTE, 0); + ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop, + 0); + break; + } if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[DEFAULT]: Stop"); - - // Pending: how does the external_info cleanup work in this case? - - ospf_asbr_status_update(ospf, --ospf->redistribute); - - /* clean up maxage default originate external lsa */ - ospf_default_originate_lsa_update(ospf); + zlog_debug("Redistribute[DEFAULT]: %s Type[%d], Metric[%d]", + type_str, + metric_type(ospf, DEFAULT_ROUTE, 0), + metric_value(ospf, DEFAULT_ROUTE, 0)); + ospf_external_lsa_refresh_default(ospf); + ospf_asbr_status_update(ospf, ospf->redistribute); return CMD_SUCCESS; } @@ -1067,11 +1017,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) /* Nothing has changed, so nothing to do; return */ return 0; } - if (ospf->router_id.s_addr == 0) - /* Set flags to generate AS-external-LSA originate event - for each redistributed protocols later. */ - ospf->external_origin |= (1 << rt_type); - else { + if (ospf->router_id.s_addr != 0) { if (ei) { if (is_prefix_default(&p)) ospf_external_lsa_refresh_default(ospf); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a64ddbc3b7..b91a55f635 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -91,7 +91,6 @@ void ospf_router_id_update(struct ospf *ospf) struct ospf_interface *oi; struct interface *ifp; struct listnode *node; - int type; if (!ospf->oi_running) { if (IS_DEBUG_OSPF_EVENT) @@ -135,24 +134,6 @@ void ospf_router_id_update(struct ospf *ospf) ospf_nbr_self_reset(oi, router_id); } - /* If AS-external-LSA is queued, then flush those LSAs. */ - if (router_id_old.s_addr == 0 && ospf->external_origin) { - /* Originate each redistributed external route. */ - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - if (ospf->external_origin & (1 << type)) - thread_add_event( - master, - ospf_external_lsa_originate_timer, - ospf, type, NULL); - /* Originate Deafult. */ - if (ospf->external_origin & (1 << ZEBRA_ROUTE_MAX)) - thread_add_event(master, - ospf_default_originate_timer, - ospf, 0, NULL); - - ospf->external_origin = 0; - } - /* Flush (inline) all external LSAs based on the OSPF_LSA_SELF * flag */ if (ospf->lsdb) { @@ -196,20 +177,14 @@ void ospf_router_id_update(struct ospf *ospf) } } - /* Originate each redistributed external route. */ - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - thread_add_event(master, - ospf_external_lsa_originate_timer, - ospf, type, NULL); - thread_add_event(master, ospf_default_originate_timer, ospf, 0, - NULL); - /* update router-lsa's for each area */ ospf_router_lsa_update(ospf); /* update ospf_interface's */ FOR_ALL_INTERFACES (vrf, ifp) ospf_if_update(ospf, ifp); + + ospf_external_lsa_rid_change(ospf); } } @@ -633,7 +608,7 @@ static void ospf_finish_final(struct ospf *ospf) ospf_redist_del(ospf, i, red->instance); } } - ospf_redistribute_default_unset(ospf); + ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, 0, 0); for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) ospf_remove_vls_through_area(ospf, area); @@ -702,7 +677,6 @@ static void ospf_finish_final(struct ospf *ospf) /* Cancel all timers. */ OSPF_TIMER_OFF(ospf->t_read); OSPF_TIMER_OFF(ospf->t_write); - OSPF_TIMER_OFF(ospf->t_external_lsa); OSPF_TIMER_OFF(ospf->t_spf_calc); OSPF_TIMER_OFF(ospf->t_ase_calc); OSPF_TIMER_OFF(ospf->t_maxage); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index cbea033b73..b31ad30375 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -202,7 +202,6 @@ struct ospf { struct ospf_lsdb *lsdb; /* Flags. */ - int external_origin; /* AS-external-LSA origin flag. */ int ase_calc; /* ASE calculation flag. */ struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ @@ -233,7 +232,6 @@ struct ospf { struct thread *t_distribute_update; /* Distirbute list update timer. */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ - struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ struct thread *t_sr_update; /* Segment Routing update timer */ diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index cd6f956580..6263f429ea 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -188,7 +188,7 @@ static void handle_repeated(bool installed) sg.r.inst, sg.r.total_routes); } - if (installed) { + if (!installed) { sg.r.installed_routes = 0; sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, &sg.r.nhop_group, diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 5213b27d32..951ad3f58f 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -196,9 +196,20 @@ static struct vrrp_vrouter *vrrp_lookup_by_if_mvl(struct interface *mvl_ifp) { struct interface *p; - if (!mvl_ifp || !mvl_ifp->link_ifindex - || !vrrp_ifp_has_vrrp_mac(mvl_ifp)) + if (!mvl_ifp || mvl_ifp->link_ifindex == 0 + || !vrrp_ifp_has_vrrp_mac(mvl_ifp)) { + if (mvl_ifp && mvl_ifp->link_ifindex == 0) + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Interface %s has no parent ifindex; disregarding", + mvl_ifp->name); + if (mvl_ifp && !vrrp_ifp_has_vrrp_mac(mvl_ifp)) + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Interface %s has a non-VRRP MAC; disregarding", + mvl_ifp->name); return NULL; + } p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT); uint8_t vrid = mvl_ifp->hw_addr[5]; @@ -2028,9 +2039,19 @@ static void vrrp_bind_pending(struct interface *mvl_ifp) { struct vrrp_vrouter *vr; + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Searching for instances that could use interface %s", + mvl_ifp->name); + vr = vrrp_lookup_by_if_mvl(mvl_ifp); if (vr) { + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX VRRP_LOGPFX_VRID + "<-- This instance can probably use interface %s", + vr->vrid, mvl_ifp->name); + if (mvl_ifp->hw_addr[4] == 0x01 && !vr->v4->mvl_ifp) vrrp_attach_interface(vr->v4); else if (mvl_ifp->hw_addr[4] == 0x02 && !vr->v6->mvl_ifp) @@ -2112,9 +2133,13 @@ void vrrp_if_down(struct interface *ifp) struct listnode *ln; struct list *vrs; + vrrp_bind_pending(ifp); + vrs = vrrp_lookup_by_if_any(ifp); for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) { + vrrp_check_start(vr); + if (vr->ifp == ifp || vr->v4->mvl_ifp == ifp || vr->v6->mvl_ifp == ifp) { DEBUGD(&vrrp_dbg_auto, diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c index dbfcbe945e..72b77c1313 100644 --- a/vrrpd/vrrp_zebra.c +++ b/vrrpd/vrrp_zebra.c @@ -38,9 +38,11 @@ static void vrrp_zebra_debug_if_state(struct interface *ifp, vrf_id_t vrf_id, const char *func) { DEBUGD(&vrrp_dbg_zebra, - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - func, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, - ifp->metric, ifp->mtu, if_is_operative(ifp)); + "%s: %s index %d(%u) parent %d mac %02x:%02x:%02x:%02x:%02x:%02x flags %ld metric %d mtu %d operative %d", + func, ifp->name, vrf_id, ifp->link_ifindex, ifp->ifindex, + ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2], + ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5], + (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } static void vrrp_zebra_debug_if_dump_address(struct interface *ifp, diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index e357a60296..3ec2eb239d 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -23,6 +23,7 @@ #include "command.h" #include "linklist.h" #include "memory.h" +#include "typesafe.h" #include "vtysh/vtysh.h" #include "vtysh/vtysh_user.h" @@ -33,6 +34,8 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line") vector configvec; +PREDECL_RBTREE_UNIQ(config_master); + struct config { /* Configuration node name. */ char *name; @@ -45,6 +48,9 @@ struct config { /* Index of this config. */ uint32_t index; + + /* Node entry for the typed Red-black tree */ + struct config_master_item rbt_item; }; struct list *config_top; @@ -66,7 +72,7 @@ static struct config *config_new(void) return config; } -static int config_cmp(struct config *c1, struct config *c2) +static int config_cmp(const struct config *c1, const struct config *c2) { return strcmp(c1->name, c2->name); } @@ -78,28 +84,23 @@ static void config_del(struct config *config) XFREE(MTYPE_VTYSH_CONFIG, config); } +DECLARE_RBTREE_UNIQ(config_master, struct config, rbt_item, config_cmp) + static struct config *config_get(int index, const char *line) { struct config *config; - struct config *config_loop; - struct list *master; - struct listnode *node, *nnode; - - config = config_loop = NULL; + struct config_master_head *master; master = vector_lookup_ensure(configvec, index); if (!master) { - master = list_new(); - master->del = (void (*)(void *))config_del; - master->cmp = (int (*)(void *, void *))config_cmp; + master = XMALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config_master_head)); + config_master_init(master); vector_set_index(configvec, index, master); } - for (ALL_LIST_ELEMENTS(master, node, nnode, config_loop)) { - if (strcmp(config_loop->name, line) == 0) - config = config_loop; - } + const struct config config_ref = { .name = (char *)line }; + config = config_master_find(master, &config_ref); if (!config) { config = config_new(); @@ -108,7 +109,7 @@ static struct config *config_get(int index, const char *line) config->line->cmp = (int (*)(void *, void *))line_cmp; config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); config->index = index; - listnode_add(master, config); + config_master_add(master, config); } return config; } @@ -432,7 +433,7 @@ void vtysh_config_dump(void) struct listnode *node, *nnode; struct listnode *mnode, *mnnode; struct config *config; - struct list *master; + struct config_master_head *master; char *line; unsigned int i; @@ -443,7 +444,7 @@ void vtysh_config_dump(void) for (i = 0; i < vector_active(configvec); i++) if ((master = vector_slot(configvec, i)) != NULL) { - for (ALL_LIST_ELEMENTS(master, node, nnode, config)) { + while ((config = config_master_pop(master))) { /* Don't print empty sections for interface. * Route maps on the * other hand could have a legitimate empty @@ -463,6 +464,8 @@ void vtysh_config_dump(void) vty_out(vty, "%s\n", line); if (!NO_DELIMITER(i)) vty_out(vty, "!\n"); + + config_del(config); } if (NO_DELIMITER(i)) vty_out(vty, "!\n"); @@ -470,7 +473,8 @@ void vtysh_config_dump(void) for (i = 0; i < vector_active(configvec); i++) if ((master = vector_slot(configvec, i)) != NULL) { - list_delete(&master); + config_master_fini(master); + XFREE(MTYPE_VTYSH_CONFIG, master); vector_slot(configvec, i) = NULL; } list_delete_all_node(config_top); diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang new file mode 100644 index 0000000000..e79ede87b7 --- /dev/null +++ b/yang/frr-filter.yang @@ -0,0 +1,353 @@ +module frr-filter { + yang-version 1.1; + namespace "http://frrouting.org/yang/filter"; + prefix frr-filter; + + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + + organization "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description "This module defines filter settings"; + + revision 2019-07-04 { + description "Initial revision"; + } + + /* + * Types. + */ + typedef access-list-standard { + description "Standard IPv4 access list (any, host or a prefix)"; + type uint16 { + range "1..99 | 1300..1999"; + } + } + + typedef access-list-extended { + description + "Extended IPv4 access list (source / destination any, hosts or prefixes)"; + type uint16 { + range "100..199 | 2000..2699"; + } + } + + typedef access-list-legacy { + description "Standard/Extended IPv4 access list"; + type uint16 { + range "1..199 | 1300..2699"; + } + } + + typedef access-list-name { + description "Access list name formatting"; + type string; + } + + typedef access-list-sequence { + description "Access list sequence number"; + type uint32 { + range "1..4294967295"; + } + } + + typedef access-list-action { + description "Access list return action on match"; + type enumeration { + enum deny { + description "Deny an entry"; + value 0; + } + enum permit { + description "Accept an entry"; + value 1; + } + } + } + + /* + * Configuration data. + */ + container filter-list { + list access-list-legacy { + description "Access list legacy instance"; + + key "number sequence"; + + leaf number { + description "Access list sequence value"; + type access-list-legacy; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; + } + + leaf remark { + description "Access list remark"; + type string; + } + + choice value { + description + "Standard access list: value to match. + Extended access list: source value to match."; + mandatory true; + + leaf host { + description "Host to match"; + type inet:ipv4-address; + } + leaf network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf any { + description "Match any"; + type empty; + } + } + + choice extended-value { + when "./sequence >= 100 and ./sequence <= 199 or + ./sequence >= 2000 and ./sequence <= 2699"; + description "Destination value to match"; + + leaf destination-host { + description "Host to match"; + type inet:ipv4-address; + } + leaf destination-network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf destination-any { + description "Match any"; + type empty; + } + } + } + + list access-list { + description "Access list instance"; + + key "type identifier sequence"; + + leaf type { + description "Access list content type"; + type enumeration { + enum ipv4 { + description "Internet Protocol address version 4"; + value 0; + } + enum ipv6 { + description "Internet Protocol address version 6"; + value 1; + } + enum mac { + description "Media Access Control address"; + value 2; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `value` leaf to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum custom { + description "Custom data type"; + value 100; + } + } + } + + leaf identifier { + description "Access list identifier"; + type access-list-name; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; + } + + leaf remark { + description "Access list remark"; + type string; + } + + choice value { + description "Access list value to match"; + mandatory true; + + case ipv4-prefix { + when "./type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } + } + case ipv6-prefix { + when "./type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } + } + case mac { + when "./type = 'mac'"; + + leaf mac { + description "Configure MAC address to match"; + type yang:mac-address; + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } + } + } + } + + list prefix-list { + description "Prefix list instance"; + + key "type name sequence"; + + leaf type { + description "Prefix list type"; + type enumeration { + enum ipv4 { + description "Internet Protocol address version 4"; + value 0; + } + enum ipv6 { + description "Internet Protocol address version 6"; + value 1; + } + } + } + + leaf name { + description "Prefix list name"; + type access-list-name; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Prefix list action on match"; + type access-list-action; + mandatory true; + } + + leaf description { + description "Prefix list user description"; + type string; + } + + choice value { + description "Prefix list value to match"; + mandatory true; + + case ipv4-prefix { + when "./type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..32"; + } + } + + leaf ipv4-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix { + when "./type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..128"; + } + } + + leaf ipv6-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..128"; + } + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } + } + } + } + } +} diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang new file mode 100644 index 0000000000..0ce40b474b --- /dev/null +++ b/yang/frr-route-map.yang @@ -0,0 +1,404 @@ +module frr-route-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/route-map"; + prefix frr-route-map; + + import ietf-inet-types { + prefix inet; + } + import frr-filter { + prefix filter; + } + + organization "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description "This module defines route map settings"; + + revision 2019-07-01 { + description "Initial revision"; + } + + /* + * Types. + */ + typedef route-map-sequence { + description "Route map valid sequence numbers"; + type uint16 { + range "1..65535"; + } + } + + typedef route-map-name { + description "Route map name format"; + type string; + } + + /* + * Operational data. + */ + container route-map { + list instance { + description "Route map instance"; + + key "name sequence"; + + leaf name { + description "Route map instance name"; + type route-map-name; + } + + leaf sequence { + description + "Route map instance priority (low number means higher priority)"; + type route-map-sequence; + } + + leaf description { + description "Route map description"; + type string; + } + + leaf action { + description + "Route map actions: permit (executes action), deny (quits evaluation)"; + mandatory true; + type enumeration { + enum permit { + description + "Executes configured action and permits the prefix/route + if the conditions matched. An alternative exit action can + be configured to continue processing the route map list + or jump to process another route map."; + value 0; + } + enum deny { + description + "If all conditions are met the prefix/route is denied and + route map processing stops."; + value 1; + } + } + } + + list match-condition { + description "Route map match conditions"; + + key "condition"; + + leaf condition { + description "Match condition"; + type enumeration { + enum interface { + description "Match interface"; + value 0; + } + enum ipv4-address-list { + description "Match an IPv4 access-list"; + value 1; + } + enum ipv4-prefix-list { + description "Match an IPv4 prefix-list"; + value 2; + } + enum ipv4-prefix-length { + description "Match an IPv4 prefix length"; + value 3; + } + enum ipv4-next-hop-list { + description "Match an IPv4 next-hop"; + value 4; + } + enum ipv4-next-hop-prefix-list { + description "Match an IPv4 next-hop prefix list"; + value 5; + } + enum ipv4-next-hop-prefix-length { + description "Match an IPv4 next-hop prefix length"; + value 6; + } + enum ipv4-next-hop-type { + description "Match an IPv4 next-hop type"; + value 7; + } + enum ipv6-address-list { + description "Match an IPv6 access-list"; + value 8; + } + enum ipv6-prefix-list { + description "Match an IPv6 prefix-list"; + value 9; + } + enum ipv6-prefix-length { + description "Match an IPv6 prefix length"; + value 10; + } + enum ipv6-next-hop { + description "Match an IPv6 next-hop"; + value 11; + } + enum ipv6-next-hop-type { + description "Match an IPv6 next-hop type"; + value 12; + } + enum metric { + description "Match a route metric"; + value 13; + } + enum tag { + description "Match a route tag"; + value 14; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `condition-value` to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum routing-protocol-specific { + description "Match a routing protocol specific type"; + value 100; + } + } + } + + choice condition-value { + description + "Value to match (interpretation depends on condition type)"; + case access-list-num { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-next-hop-list'"; + leaf access-list-num { + type filter:access-list-standard; + } + } + case access-list-num-extended { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-next-hop-list'"; + leaf access-list-num-extended { + type filter:access-list-extended; + } + } + case list-name { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-prefix-list' or + ./condition = 'ipv4-next-hop-list' or + ./condition = 'ipv4-next-hop-prefix-list' or + ./condition = 'ipv6-address-list' or + ./condition = 'ipv6-prefix-list'"; + leaf list-name { + type filter:access-list-name; + } + } + case ipv6-address { + when "./condition = 'ipv6-next-hop'"; + leaf ipv6-address { + type inet:ipv6-address; + } + } + case ipv4-prefix-length { + when "./condition = 'ipv4-prefix-length' or + ./condition = 'ipv4-next-hop-prefix-length'"; + leaf ipv4-prefix-length { + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix-length { + when "./condition = 'ipv6-prefix-length'"; + leaf ipv6-prefix-length { + type uint8 { + range "0..128"; + } + } + } + case ipv4-next-hop-type { + when "./condition = 'ipv4-next-hop-type'"; + leaf ipv4-next-hop-type { + type enumeration { + enum blackhole { + value 0; + } + } + } + } + case ipv6-next-hop-type { + when "./condition = 'ipv6-next-hop-type'"; + leaf ipv6-next-hop-type { + type enumeration { + enum blackhole { + value 0; + } + } + } + } + case metric { + when "./condition = 'metric'"; + leaf metric { + type uint32 { + range "1..4294967295"; + } + } + } + case tag { + when "./condition = 'tag'"; + leaf tag { + type uint32 { + range "1..4294967295"; + } + } + } + } + } + + list set-action { + description "Route map set actions"; + + key "action"; + + leaf action { + description "Action to do when the route map matches"; + type enumeration { + enum ipv4-next-hop { + description "Set IPv4 address of the next hop"; + value 0; + } + enum ipv6-next-hop { + description "Set IPv6 address of the next hop"; + value 1; + } + enum metric { + description "Set prefix/route metric"; + value 2; + } + enum tag { + description "Set tag"; + value 3; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `action-value` to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum routing-protocol-specific { + description "Set a routing protocol specific action"; + value 100; + } + } + } + + choice action-value { + description + "Value to set (interpretation depends on action-type)"; + case ipv4-address { + when "./action = 'ipv4-next-hop'"; + leaf ipv4-address { + description "IPv4 address"; + type inet:ipv4-address; + } + } + case ipv6-address { + when "./action = 'ipv6-next-hop'"; + leaf ipv6-address { + description "IPv6 address"; + type inet:ipv6-address; + } + } + case metric { + when "./action = 'metric'"; + choice metric-value { + description "Metric to set or use"; + case value { + leaf value { + description "Use the following metric value"; + type uint32 { + range "0..4294967295"; + } + } + } + case add-metric { + leaf add-metric { + description "Add unit to metric"; + type boolean; + } + } + case subtract-metric { + leaf subtract-metric { + description "Subtract unit from metric"; + type boolean; + } + } + case use-round-trip-time { + leaf use-round-trip-time { + description "Use the round trip time as metric"; + type boolean; + } + } + case add-round-trip-time { + leaf add-round-trip-time { + description "Add round trip time to metric"; + type boolean; + } + } + case subtract-round-trip-time { + leaf subtract-round-trip-time { + description "Subtract round trip time to metric"; + type boolean; + } + } + } + } + case tag { + leaf tag { + description "Tag value"; + type uint32 { + range "0..4294967295"; + } + } + } + } + } + + leaf call { + description + "Call another route map before calling `exit-policy`. If the + called route map returns deny then this route map will also + return deny"; + type string; + } + + leaf exit-policy { + description "What do to after route map successful match, set and call"; + type enumeration { + enum permit-or-deny { + description "End route map evaluation and return"; + value 0; + } + enum next { + description + "Proceed evaluating next route map entry per sequence"; + value 1; + } + enum goto { + description + "Go to route map entry with the provided sequence number"; + value 2; + } + } + default "permit-or-deny"; + } + + leaf goto-value { + when "../exit-policy = 'goto'"; + description + "Sequence number to jump (when using `goto` exit policy)"; + type route-map-sequence; + } + } + } +} diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index df8d4bfe15..63e72fed00 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1347,6 +1347,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Intf %s(%u) has come UP", name, ifp->ifindex); if_up(ifp); + } else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has gone DOWN", + name, ifp->ifindex); + if_down(ifp); } } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f3721c478d..3608b887ee 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1926,6 +1926,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) goto done; } + /* Ensure we clear the QUEUED flag */ + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + /* Is this a notification that ... matters? We only really care about * the route that is currently selected for installation. */ @@ -1990,7 +1993,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_ctx_get_vrf(ctx), dest_str); /* We expect this to be the selected route, so we want - * to tell others about this transistion. + * to tell others about this transition. */ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 359585df73..2e8c81bddd 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3403,6 +3403,39 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) return 0; } +static bool zvni_check_mac_del_from_db(struct mac_walk_ctx *wctx, + zebra_mac_t *mac) +{ + if ((wctx->flags & DEL_LOCAL_MAC) && + (mac->flags & ZEBRA_MAC_LOCAL)) + return true; + else if ((wctx->flags & DEL_REMOTE_MAC) && + (mac->flags & ZEBRA_MAC_REMOTE)) + return true; + else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) && + (mac->flags & ZEBRA_MAC_REMOTE) && + IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) + return true; + else if ((wctx->flags & DEL_LOCAL_MAC) && + (mac->flags & ZEBRA_MAC_AUTO) && + !listcount(mac->neigh_list)) { + if (IS_ZEBRA_DEBUG_VXLAN) { + char buf[ETHER_ADDR_STRLEN]; + + zlog_debug("%s: Del MAC %s flags 0x%x", + __PRETTY_FUNCTION__, + prefix_mac2str(&mac->macaddr, + buf, sizeof(buf)), + mac->flags); + } + wctx->uninstall = 0; + + return true; + } + + return false; +} + /* * Free MAC hash entry (callback) */ @@ -3411,18 +3444,11 @@ static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) struct mac_walk_ctx *wctx = arg; zebra_mac_t *mac = bucket->data; - if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) - || ((wctx->flags & DEL_REMOTE_MAC) - && (mac->flags & ZEBRA_MAC_REMOTE)) - || ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) - && (mac->flags & ZEBRA_MAC_REMOTE) - && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, - &wctx->r_vtep_ip))) { + if (zvni_check_mac_del_from_db(wctx, mac)) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { zvni_mac_send_del_to_client(wctx->zvni->vni, &mac->macaddr); } - if (wctx->uninstall) zvni_mac_uninstall(wctx->zvni, mac); @@ -5332,8 +5358,6 @@ static void process_remote_macip_add(vni_t vni, if (ipa_len) SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); } else { - const char *mac_type; - /* When host moves but changes its (MAC,IP) * binding, BGP may install a MACIP entry that * corresponds to "older" location of the host @@ -5342,16 +5366,14 @@ static void process_remote_macip_add(vni_t vni, * the sequence number and ignore this update * if appropriate. */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) tmp_seq = mac->loc_seq; - mac_type = "local"; - } else { + else tmp_seq = mac->rem_seq; - mac_type = "remote"; - } + if (seq < tmp_seq) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u", + zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing MAC has higher seq %u flags 0x%x", vni, prefix_mac2str(macaddr, buf, sizeof(buf)), @@ -5359,8 +5381,7 @@ static void process_remote_macip_add(vni_t vni, ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "", - mac_type, - tmp_seq); + tmp_seq, mac->flags); return; } } @@ -7274,8 +7295,13 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, * of a VxLAN bridge. */ zvni = zvni_from_svi(ifp, link_if); - if (!zvni) + if (!zvni) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: Del neighbor %s VNI is not present for interface %s", + __PRETTY_FUNCTION__, + ipaddr2str(ip, buf, sizeof(buf)), ifp->name); return 0; + } if (!zvni->vxlan_if) { zlog_debug( @@ -7672,9 +7698,10 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, return 0; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u flags 0x%x", + zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, - ifp->ifindex, vid, zvni->vni, mac->flags); + ifp->ifindex, vid, zvni->vni, mac->loc_seq, + mac->flags, listcount(mac->neigh_list)); /* Update all the neigh entries associated with this mac */ zvni_process_neigh_on_local_mac_del(zvni, mac); |
