diff options
| -rw-r--r-- | bgpd/bgp_evpn.c | 69 | ||||
| -rw-r--r-- | bgpd/bgp_evpn_vty.c | 20 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 23 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 4 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 85 | ||||
| -rw-r--r-- | doc/user/ospfd.rst | 9 | ||||
| -rw-r--r-- | lib/command.h | 1 | ||||
| -rw-r--r-- | ospfd/ospf_memory.c | 1 | ||||
| -rw-r--r-- | ospfd/ospf_memory.h | 1 | ||||
| -rw-r--r-- | ospfd/ospf_ri.c | 576 | ||||
| -rw-r--r-- | ospfd/ospf_ri.h | 66 | ||||
| -rw-r--r-- | ospfd/ospf_te.c | 8 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_vty.c | 3 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 36 |
15 files changed, 638 insertions, 266 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index c91a2ab6bd..cff050a9ef 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1693,6 +1693,58 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, } /* + * If the local route was not selected evict it and tell zebra to re-add + * the best remote dest. + * + * Typically a local path added by zebra is expected to be selected as + * best. In which case when a remote path wins as best (later) + * evpn_route_select_install itself evicts the older-local-best path. + * + * However if bgp's add and zebra's add cross paths (race condition) it + * is possible that the local path is no longer the "older" best path. + * It is a path that was never designated as best and hence requires + * additional handling to prevent bgp from injecting and holding on to a + * non-best local path. + */ +static void evpn_cleanup_local_non_best_route(struct bgp *bgp, + struct bgpevpn *vpn, + struct bgp_node *rn, + struct bgp_path_info *local_pi) +{ + struct bgp_path_info *tmp_pi; + struct bgp_path_info *curr_select = NULL; + uint8_t flags = 0; + char buf[PREFIX_STRLEN]; + + /* local path was not picked as the winner; kick it out */ + if (bgp_debug_zebra(NULL)) { + zlog_debug("evicting local evpn prefix %s as remote won", + prefix2str(&rn->p, buf, sizeof(buf))); + } + evpn_delete_old_local_route(bgp, vpn, rn, local_pi); + bgp_path_info_reap(rn, local_pi); + + /* tell zebra to re-add the best remote path */ + for (tmp_pi = rn->info; tmp_pi; tmp_pi = tmp_pi->next) { + if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_SELECTED)) { + curr_select = tmp_pi; + break; + } + } + if (curr_select && + curr_select->type == ZEBRA_ROUTE_BGP + && curr_select->sub_type == BGP_ROUTE_IMPORTED) { + if (curr_select->attr->sticky) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); + if (curr_select->attr->default_gw) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, + curr_select->attr->nexthop, flags, + mac_mobility_seqnum(curr_select->attr)); + } +} + +/* * Create or update EVPN route (of type based on prefix) for specified VNI * and schedule for processing. */ @@ -1754,10 +1806,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, assert(pi); attr_new = pi->attr; + /* lock ri to prevent freeing in evpn_route_select_install */ + bgp_path_info_lock(pi); /* Perform route selection; this is just to set the flags correctly * as local route in the VNI always wins. */ evpn_route_select_install(bgp, vpn, rn); + /* + * If the new local route was not selected evict it and tell zebra + * to re-add the best remote dest. BGP doesn't retain non-best local + * routes. + */ + if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { + route_change = 0; + evpn_cleanup_local_non_best_route(bgp, vpn, rn, pi); + } + bgp_path_info_unlock(pi); + bgp_unlock_node(rn); /* If this is a new route or some attribute has changed, export the @@ -1928,8 +1993,10 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, /* Delete route entry in the VNI route table. This can just be removed. */ delete_evpn_route_entry(bgp, afi, safi, rn, &pi); - if (pi) + if (pi) { bgp_path_info_reap(rn, pi); + evpn_route_select_install(bgp, vpn, rn); + } bgp_unlock_node(rn); return 0; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 29f9f64cca..aa5eabeade 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3195,7 +3195,7 @@ DEFUN (no_bgp_evpn_advertise_type5, */ DEFUN(show_bgp_l2vpn_evpn_vni, show_bgp_l2vpn_evpn_vni_cmd, - "show bgp l2vpn evpn vni [(1-16777215)] [json]", + "show bgp l2vpn evpn vni [" CMD_VNI_RANGE "] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -3623,7 +3623,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_esi, * Display per-VNI EVPN routing table. */ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, - "show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>] [json]", + "show bgp l2vpn evpn route vni " CMD_VNI_RANGE " [<type <macip|multicast> | vtep A.B.C.D>] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -3696,7 +3696,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, */ DEFUN(show_bgp_l2vpn_evpn_route_vni_macip, show_bgp_l2vpn_evpn_route_vni_macip_cmd, - "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD] [json]", + "show bgp l2vpn evpn route vni " CMD_VNI_RANGE " mac WORD [ip WORD] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -3766,7 +3766,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_macip, */ DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast, show_bgp_l2vpn_evpn_route_vni_multicast_cmd, - "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D [json]", + "show bgp l2vpn evpn route vni " CMD_VNI_RANGE " multicast A.B.C.D [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -4019,7 +4019,7 @@ DEFUN(test_withdraw_evpn_type4_route, } ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd, - "show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR + "show bgp evpn vni [" CMD_VNI_RANGE "]", SHOW_STR BGP_STR EVPN_HELP_STR "Show VNI\n" "VNI number\n") @@ -4060,7 +4060,7 @@ ALIAS_HIDDEN( ALIAS_HIDDEN( show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd, - "show bgp evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]", + "show bgp evpn route vni " CMD_VNI_RANGE " [<type <macip|multicast> | vtep A.B.C.D>]", SHOW_STR BGP_STR EVPN_HELP_STR "EVPN route information\n" "VXLAN Network Identifier\n" @@ -4073,7 +4073,7 @@ ALIAS_HIDDEN( ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip, show_bgp_evpn_route_vni_macip_cmd, - "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]", + "show bgp evpn route vni " CMD_VNI_RANGE " mac WORD [ip WORD]", SHOW_STR BGP_STR EVPN_HELP_STR "EVPN route information\n" "VXLAN Network Identifier\n" @@ -4085,7 +4085,7 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip, ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast, show_bgp_evpn_route_vni_multicast_cmd, - "show bgp evpn route vni (1-16777215) multicast A.B.C.D", + "show bgp evpn route vni " CMD_VNI_RANGE " multicast A.B.C.D", SHOW_STR BGP_STR EVPN_HELP_STR "EVPN route information\n" "VXLAN Network Identifier\n" @@ -4108,7 +4108,7 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd, DEFUN_NOSH (bgp_evpn_vni, bgp_evpn_vni_cmd, - "vni (1-16777215)", + "vni " CMD_VNI_RANGE, "VXLAN Network Identifier\n" "VNI number\n") { @@ -4134,7 +4134,7 @@ DEFUN_NOSH (bgp_evpn_vni, DEFUN (no_bgp_evpn_vni, no_bgp_evpn_vni_cmd, - "no vni (1-16777215)", + "no vni " CMD_VNI_RANGE, NO_STR "VXLAN Network Identifier\n" "VNI number\n") diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4542d0ec27..8ae74a008c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -453,6 +453,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, char exist_buf[PATH_ADDPATH_STR_BUFFER]; uint32_t new_mm_seq; uint32_t exist_mm_seq; + int nh_cmp; *paths_eq = 0; @@ -545,6 +546,28 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, exist_mm_seq); return 0; } + + /* + * if sequence numbers are the same path with the lowest IP + * wins + */ + nh_cmp = bgp_path_info_nexthop_cmp(new, exist); + if (nh_cmp < 0) { + if (debug) + zlog_debug( + "%s: %s wins over %s due to same MM seq %u and lower IP %s", + pfx_buf, new_buf, exist_buf, new_mm_seq, + inet_ntoa(new->attr->nexthop)); + return 1; + } + if (nh_cmp > 0) { + if (debug) + zlog_debug( + "%s: %s loses to %s due to same MM seq %u and higher IP %s", + pfx_buf, new_buf, exist_buf, new_mm_seq, + inet_ntoa(new->attr->nexthop)); + return 0; + } } /* 1. Weight check. */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 60a4e994c9..f7c4175383 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3438,7 +3438,7 @@ DEFUN (no_match_evpn_route_type, DEFUN (match_evpn_vni, match_evpn_vni_cmd, - "match evpn vni (1-16777215)", + "match evpn vni " CMD_VNI_RANGE, MATCH_STR EVPN_HELP_STR "Match VNI\n" @@ -3450,7 +3450,7 @@ DEFUN (match_evpn_vni, DEFUN (no_match_evpn_vni, no_match_evpn_vni_cmd, - "no match evpn vni (1-16777215)", + "no match evpn vni " CMD_VNI_RANGE, NO_STR MATCH_STR EVPN_HELP_STR diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 948cc8518c..c57cd38151 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -822,6 +822,87 @@ DEFUN_HIDDEN (no_bgp_multiple_instance, return CMD_SUCCESS; } +DEFUN_HIDDEN (bgp_local_mac, + bgp_local_mac_cmd, + "bgp local-mac vni " CMD_VNI_RANGE " mac WORD seq (0-4294967295)", + BGP_STR + "Local MAC config\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "local mac\n" + "mac address\n" + "mac-mobility sequence\n" + "seq number\n") +{ + int rv; + vni_t vni; + struct ethaddr mac; + struct ipaddr ip; + uint32_t seq; + struct bgp *bgp; + + vni = strtoul(argv[3]->arg, NULL, 10); + if (!prefix_str2mac(argv[5]->arg, &mac)) { + vty_out(vty, "%% Malformed MAC address\n"); + return CMD_WARNING; + } + memset(&ip, 0, sizeof(ip)); + seq = strtoul(argv[7]->arg, NULL, 10); + + bgp = bgp_get_default(); + if (!bgp) { + vty_out(vty, "Default BGP instance is not there\n"); + return CMD_WARNING; + } + + rv = bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, 0 /* flags */, seq); + if (rv < 0) { + vty_out(vty, "Internal error\n"); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN_HIDDEN (no_bgp_local_mac, + no_bgp_local_mac_cmd, + "no bgp local-mac vni " CMD_VNI_RANGE " mac WORD", + NO_STR + BGP_STR + "Local MAC config\n" + "VxLAN Network Identifier\n" + "VNI number\n" + "local mac\n" + "mac address\n") +{ + int rv; + vni_t vni; + struct ethaddr mac; + struct ipaddr ip; + struct bgp *bgp; + + vni = strtoul(argv[4]->arg, NULL, 10); + if (!prefix_str2mac(argv[6]->arg, &mac)) { + vty_out(vty, "%% Malformed MAC address\n"); + return CMD_WARNING; + } + memset(&ip, 0, sizeof(ip)); + + bgp = bgp_get_default(); + if (!bgp) { + vty_out(vty, "Default BGP instance is not there\n"); + return CMD_WARNING; + } + + rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip); + if (rv < 0) { + vty_out(vty, "Internal error\n"); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + #if (CONFDATE > 20190601) CPP_NOTICE("bgpd: time to remove deprecated cli bgp config-type cisco") CPP_NOTICE("This includes BGP_OPT_CISCO_CONFIG") @@ -12593,6 +12674,10 @@ void bgp_vty_init(void) install_element(CONFIG_NODE, &bgp_config_type_cmd); install_element(CONFIG_NODE, &no_bgp_config_type_cmd); + /* "bgp local-mac" hidden commands. */ + install_element(CONFIG_NODE, &bgp_local_mac_cmd); + install_element(CONFIG_NODE, &no_bgp_local_mac_cmd); + /* bgp route-map delay-timer commands. */ install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd); install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd); diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index e843136396..b6a7cd5de0 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -979,14 +979,17 @@ Traffic Engineering Router Information ================== -.. index:: router-info [as | area <A.B.C.D>] -.. clicmd:: router-info [as | area <A.B.C.D>] +.. index:: router-info [as | area] +.. clicmd:: router-info [as | area] .. index:: no router-info .. clicmd:: no router-info Enable Router Information (:rfc:`4970`) LSA advertisement with AS scope - (default) or Area scope flooding when area is specified. + (default) or Area scope flooding when area is specified. Old syntax + `router-info area <A.B.C.D>` is always supported but mark as deprecated + as the area ID is no more necessary. Indeed, router information support + multi-area and detect automatically the areas. .. index:: pce address <A.B.C.D> .. clicmd:: pce address <A.B.C.D> diff --git a/lib/command.h b/lib/command.h index 873ecdda98..11514fd5e8 100644 --- a/lib/command.h +++ b/lib/command.h @@ -378,6 +378,7 @@ struct cmd_node { #define WATCHFRR_STR "watchfrr information\n" #define ZEBRA_STR "Zebra information\n" +#define CMD_VNI_RANGE "(1-16777215)" #define CONF_BACKUP_EXT ".sav" /* Command warnings. */ diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index 1332104b0a..c4dc0136ed 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -52,6 +52,7 @@ DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info") DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params") DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message") DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters") +DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters") DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters") DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters") DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters") diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index 50c6f33ecf..861de64c25 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -51,6 +51,7 @@ DECLARE_MTYPE(OSPF_IF_INFO) DECLARE_MTYPE(OSPF_IF_PARAMS) DECLARE_MTYPE(OSPF_MESSAGE) DECLARE_MTYPE(OSPF_MPLS_TE) +DECLARE_MTYPE(OSPF_ROUTER_INFO) DECLARE_MTYPE(OSPF_PCE_PARAMS) DECLARE_MTYPE(OSPF_SR_PARAMS) DECLARE_MTYPE(OSPF_EXT_PARAMS) diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index bef16761f2..72f6dbe08e 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -59,60 +59,6 @@ #include "ospfd/ospf_ri.h" #include "ospfd/ospf_errors.h" -/* Store Router Information PCE TLV and SubTLV in network byte order. */ -struct ospf_pce_info { - bool enabled; - struct ri_tlv_pce pce_header; - struct ri_pce_subtlv_address pce_address; - struct ri_pce_subtlv_path_scope pce_scope; - struct list *pce_domain; - struct list *pce_neighbor; - struct ri_pce_subtlv_cap_flag pce_cap_flag; -}; - -/* - * Store Router Information Segment Routing TLV and SubTLV - * in network byte order - */ -struct ospf_ri_sr_info { - bool enabled; - /* Algorithms supported by the node */ - struct ri_sr_tlv_sr_algorithm algo; - /* - * Segment Routing Global Block i.e. label range - * Only one range supported in this code - */ - struct ri_sr_tlv_sid_label_range range; - /* Maximum SID Depth supported by the node */ - struct ri_sr_tlv_node_msd msd; -}; - -/* Following structure are internal use only. */ -struct ospf_router_info { - bool enabled; - - uint8_t registered; - uint8_t scope; - -/* Flags to manage this router information. */ -#define RIFLG_LSA_ENGAGED 0x1 -#define RIFLG_LSA_FORCED_REFRESH 0x2 - uint32_t flags; - - /* area pointer if flooding is Type 10 Null if flooding is AS scope */ - struct ospf_area *area; - struct in_addr area_id; - - /* Store Router Information Capabilities LSA */ - struct ri_tlv_router_cap router_cap; - - /* Store PCE capability LSA */ - struct ospf_pce_info pce_info; - - /* Store SR capability LSA */ - struct ospf_ri_sr_info sr_info; -}; - /* * Global variable to manage Opaque-LSA/Router Information on this node. * Note that all parameter values are stored in network byte order. @@ -126,28 +72,29 @@ static struct ospf_router_info OspfRI; static void ospf_router_info_ism_change(struct ospf_interface *oi, int old_status); -static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr, - int old_status); static void ospf_router_info_config_write_router(struct vty *vty); static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa); static int ospf_router_info_lsa_originate(void *arg); static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa); -static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode); +static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai, + enum lsa_opcode opcode); static void ospf_router_info_register_vty(void); static int ospf_router_info_lsa_update(struct ospf_lsa *lsa); +static void del_area_info(void *val); static void del_pce_info(void *val); int ospf_router_info_init(void) { - zlog_info("RI -> Initialize Router Information"); + zlog_info("RI (%s): Initialize Router Information", __func__); memset(&OspfRI, 0, sizeof(struct ospf_router_info)); OspfRI.enabled = false; OspfRI.registered = 0; OspfRI.scope = OSPF_OPAQUE_AS_LSA; - OspfRI.area_id.s_addr = 0; - OspfRI.flags = 0; + OspfRI.as_flags = RIFLG_LSA_INACTIVE; + OspfRI.area_info = list_new(); + OspfRI.area_info->del = del_area_info; /* Initialize pce domain and neighbor list */ OspfRI.pce_info.enabled = false; @@ -171,13 +118,15 @@ static int ospf_router_info_register(uint8_t scope) if (OspfRI.registered) return rc; - zlog_info("RI -> Register Router Information with scope %s(%d)", + zlog_info("RI (%s): Register Router Information with scope %s(%d)", + __func__, scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope); rc = ospf_register_opaque_functab( scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA, NULL, /* new interface */ NULL, /* del interface */ - ospf_router_info_ism_change, ospf_router_info_nsm_change, + ospf_router_info_ism_change, + NULL, /* NSM change */ ospf_router_info_config_write_router, NULL, /* Config. write interface */ NULL, /* Config. write debug */ @@ -188,7 +137,7 @@ static int ospf_router_info_register(uint8_t scope) if (rc != 0) { flog_warn( EC_OSPF_OPAQUE_REGISTRATION, - "ospf_router_info_init: Failed to register functions"); + "RI (%s): Failed to register functions", __func__); return rc; } @@ -235,10 +184,14 @@ void ospf_router_info_finish(void) OspfRI.enabled = false; } +static void del_area_info(void *val) +{ + XFREE(MTYPE_OSPF_ROUTER_INFO, val); +} + static void del_pce_info(void *val) { XFREE(MTYPE_OSPF_PCE_PARAMS, val); - return; } /* Catch RI LSA flooding Scope for ospf_ext.[h,c] code */ @@ -248,14 +201,26 @@ struct scope_info ospf_router_info_get_flooding_scope(void) if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { flooding_scope.scope = OSPF_OPAQUE_AS_LSA; - flooding_scope.area_id.s_addr = 0; + flooding_scope.areas = NULL; return flooding_scope; } flooding_scope.scope = OSPF_OPAQUE_AREA_LSA; - flooding_scope.area_id.s_addr = OspfRI.area_id.s_addr; + flooding_scope.areas = OspfRI.area_info; return flooding_scope; } +static struct ospf_ri_area_info *lookup_by_area(struct ospf_area *area) +{ + struct listnode *node, *nnode; + struct ospf_ri_area_info *ai; + + for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) + if (ai->area == area) + return ai; + + return NULL; +} + /*------------------------------------------------------------------------* * Followings are control functions for ROUTER INFORMATION parameters *management. @@ -525,6 +490,9 @@ static void initialize_params(struct ospf_router_info *ori) { uint32_t cap = 0; struct ospf *top; + struct listnode *node, *nnode; + struct ospf_area *area; + struct ospf_ri_area_info *new; /* * Initialize default Router Information Capabilities. @@ -536,14 +504,22 @@ static void initialize_params(struct ospf_router_info *ori) /* If Area address is not null and exist, retrieve corresponding * structure */ top = ospf_lookup_by_vrf_id(VRF_DEFAULT); - zlog_info("RI-> Initialize Router Info for %s scope within area %s", - OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", - inet_ntoa(OspfRI.area_id)); + zlog_info("RI (%s): Initialize Router Info for %s scope", __func__, + OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS"); - /* Try to get the Area context at this step. Do it latter if not - * available */ - if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) - OspfRI.area = ospf_area_lookup_by_area_id(top, OspfRI.area_id); + /* Try to get available Area's context from ospf at this step. + * Do it latter if not available */ + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { + for (ALL_LIST_ELEMENTS(top->areas, node, nnode, area)) { + zlog_debug("RI (%s): Add area %s to Router Information", + __func__, inet_ntoa(area->area_id)); + new = XCALLOC(MTYPE_OSPF_ROUTER_INFO, + sizeof(struct ospf_ri_area_info)); + new->area = area; + new->flags = RIFLG_LSA_INACTIVE; + listnode_add(OspfRI.area_info, new); + } + } /* * Initialize default PCE Information values @@ -597,16 +573,31 @@ static int is_mandated_params_set(struct ospf_router_info ori) */ void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd) { + struct listnode *node, *nnode; + struct ospf_ri_area_info *ai; + + /* First, check if Router Information is registered or not */ + if (!OspfRI.registered) + ospf_router_info_register(OSPF_OPAQUE_AREA_LSA); + + /* Verify that scope is AREA */ + if (OspfRI.scope != OSPF_OPAQUE_AREA_LSA) { + zlog_err( + "RI (%s): Router Info is %s flooding: Change scope to Area flooding for Segment Routing", + __func__, + OspfRI.scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS"); + return; + } - /* First activate and initialize Router Information is necessary */ + /* Then, activate and initialize Router Information if necessary */ if (!OspfRI.enabled) { OspfRI.enabled = true; initialize_params(&OspfRI); } if (IS_DEBUG_OSPF_SR) - zlog_debug("RI-> %s Routing Information for Segment Routing", - enable ? "Enable" : "Disable"); + zlog_debug("RI (%s): %s Routing Information for Segment Routing", + __func__, enable ? "Enable" : "Disable"); /* Unset or Set SR parameters */ if (!enable) { @@ -626,10 +617,14 @@ void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd) } /* Refresh if already engaged or originate RI LSA */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); - else - ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA); + for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) { + if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA); + else + ospf_router_info_lsa_schedule(ai, + REORIGINATE_THIS_LSA); + + } } /*------------------------------------------------------------------------* @@ -638,14 +633,22 @@ void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd) static void ospf_router_info_ism_change(struct ospf_interface *oi, int old_state) { - /* So far, nothing to do here. */ - return; -} -static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr, - int old_state) -{ - /* So far, nothing to do here. */ + struct ospf_ri_area_info *ai; + + /* Collect area information */ + ai = lookup_by_area(oi->area); + + /* Check if area is not yet registered */ + if (ai != NULL) + return; + + /* Add this new area to the list */ + ai = XCALLOC(MTYPE_OSPF_ROUTER_INFO, sizeof(struct ospf_ri_area_info)); + ai->area = oi->area; + ai->flags = RIFLG_LSA_INACTIVE; + listnode_add(OspfRI.area_info, ai); + return; } @@ -723,7 +726,7 @@ static void ospf_router_info_lsa_body_set(struct stream *s) } /* Create new opaque-LSA. */ -static struct ospf_lsa *ospf_router_info_lsa_new() +static struct ospf_lsa *ospf_router_info_lsa_new(struct ospf_area *area) { struct ospf *top; struct stream *s; @@ -768,8 +771,7 @@ static struct ospf_lsa *ospf_router_info_lsa_new() /* Now, create an OSPF LSA instance. */ new = ospf_lsa_new_and_data(length); - new->area = OspfRI.area; /* Area must be null if the Opaque type is AS - scope, fulfill otherwise */ + new->area = area; if (new->area && new->area->ospf) new->vrf_id = new->area->ospf->vrf_id; @@ -783,36 +785,31 @@ static struct ospf_lsa *ospf_router_info_lsa_new() return new; } -static int ospf_router_info_lsa_originate1(void *arg) +static int ospf_router_info_lsa_originate_as(void *arg) { struct ospf_lsa *new; struct ospf *top; - struct ospf_area *area; int rc = -1; vrf_id_t vrf_id = VRF_DEFAULT; - /* First check if the area is known if flooding scope is Area */ + /* Sanity Check */ if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { - area = (struct ospf_area *)arg; - if (area->area_id.s_addr != OspfRI.area_id.s_addr) { - zlog_debug( - "RI -> This is not the Router Information Area. Stop processing"); - return rc; - } - OspfRI.area = area; - if (area->ospf) - vrf_id = area->ospf->vrf_id; + flog_warn( + EC_OSPF_LSA_INSTALL_FAILURE, + "RI (%s): wrong flooding scope AREA instead of AS ?", + __func__); + return rc; } /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ - new = ospf_router_info_lsa_new(); - new->vrf_id = vrf_id; + new = ospf_router_info_lsa_new(NULL); + new->vrf_id = VRF_DEFAULT; + top = (struct ospf *)arg; - /* Get ospf info */ - top = ospf_lookup_by_vrf_id(vrf_id); + /* Check ospf info */ if (top == NULL) { - zlog_debug("%s: ospf instance not found for vrf id %u", - __PRETTY_FUNCTION__, vrf_id); + zlog_debug("RI (%s): ospf instance not found for vrf id %u", + __func__, vrf_id); ospf_lsa_unlock(&new); return rc; } @@ -821,22 +818,86 @@ static int ospf_router_info_lsa_originate1(void *arg) if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { flog_warn( EC_OSPF_LSA_INSTALL_FAILURE, - "ospf_router_info_lsa_originate1: ospf_lsa_install() ?"); + "RI (%s): ospf_lsa_install() ?", __func__); + ospf_lsa_unlock(&new); + return rc; + } + + /* Update new LSA origination count. */ + top->lsa_originate_count++; + + /* Flood new LSA through AREA or AS. */ + SET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED); + ospf_flood_through_as(top, NULL /*nbr */, new); + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug( + "LSA[Type%d:%s]: Originate Opaque-LSA/ROUTER INFORMATION", + new->data->type, inet_ntoa(new->data->id)); + ospf_lsa_header_dump(new->data); + } + + rc = 0; + return rc; +} + +static int ospf_router_info_lsa_originate_area(void *arg) +{ + struct ospf_lsa *new; + struct ospf *top; + struct ospf_ri_area_info *ai = NULL; + int rc = -1; + vrf_id_t vrf_id = VRF_DEFAULT; + + /* Sanity Check */ + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { + flog_warn( + EC_OSPF_LSA_INSTALL_FAILURE, + "RI (%s): wrong flooding scope AS instead of AREA ?", + __func__); + return rc; + } + + /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ + ai = lookup_by_area((struct ospf_area *)arg); + if (ai == NULL) { + zlog_debug( + "RI (%s): There is no context for this Router Information. Stop processing", + __func__); + return rc; + } + if (ai->area->ospf) { + vrf_id = ai->area->ospf->vrf_id; + top = ai->area->ospf; + } else { + top = ospf_lookup_by_vrf_id(vrf_id); + } + new = ospf_router_info_lsa_new(ai->area); + new->vrf_id = vrf_id; + + /* Check ospf info */ + if (top == NULL) { + zlog_debug("RI (%s): ospf instance not found for vrf id %u", + __func__, vrf_id); ospf_lsa_unlock(&new); return rc; } - /* Now this Router Info parameter entry has associated LSA. */ - SET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED); + /* Install this LSA into LSDB. */ + if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { + flog_warn( + EC_OSPF_LSA_INSTALL_FAILURE, + "RI (%s): ospf_lsa_install() ?", __func__); + ospf_lsa_unlock(&new); + return rc; + } /* Update new LSA origination count. */ top->lsa_originate_count++; - /* Flood new LSA through AS. */ - if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) - ospf_flood_through_as(top, NULL /*nbr */, new); - else - ospf_flood_through_area(OspfRI.area, NULL /*nbr */, new); + /* Flood new LSA through AREA or AS. */ + SET_FLAG(ai->flags, RIFLG_LSA_ENGAGED); + ospf_flood_through_area(ai->area, NULL /*nbr */, new); if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { zlog_debug( @@ -852,38 +913,62 @@ static int ospf_router_info_lsa_originate1(void *arg) static int ospf_router_info_lsa_originate(void *arg) { + struct ospf_ri_area_info *ai; int rc = -1; if (!OspfRI.enabled) { - zlog_info( - "ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now."); + zlog_info("RI (%s): ROUTER INFORMATION is disabled now.", + __func__); rc = 0; /* This is not an error case. */ return rc; } /* Check if Router Information LSA is already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) { - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH)) { - UNSET_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH); - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { + if ((CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)) + && (CHECK_FLAG(OspfRI.as_flags, + RIFLG_LSA_FORCED_REFRESH))) { + UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_FORCED_REFRESH); + ospf_router_info_lsa_schedule(NULL, REFRESH_THIS_LSA); + rc = 0; + return rc; } } else { - if (!is_mandated_params_set(OspfRI)) + ai = lookup_by_area((struct ospf_area *)arg); + if (ai == NULL) { flog_warn( EC_OSPF_LSA, - "ospf_router_info_lsa_originate: lacks mandated ROUTER INFORMATION parameters"); - - /* Ok, let's try to originate an LSA */ - if (ospf_router_info_lsa_originate1(arg) != 0) + "RI (%s): Missing area information", __func__); return rc; + } + if ((CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)) + && (CHECK_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH))) { + UNSET_FLAG(ai->flags, RIFLG_LSA_FORCED_REFRESH); + ospf_router_info_lsa_schedule(ai, REFRESH_THIS_LSA); + rc = 0; + return rc; + } } - rc = 0; + /* Router Information is not yet Engaged, check parameters */ + if (!is_mandated_params_set(OspfRI)) + flog_warn( + EC_OSPF_LSA, + "RI (%s): lacks mandated ROUTER INFORMATION parameters", + __func__); + + /* Ok, let's try to originate an LSA */ + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + rc = ospf_router_info_lsa_originate_as(arg); + else + rc = ospf_router_info_lsa_originate_area(arg); + return rc; } static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) { + struct ospf_ri_area_info *ai = NULL; struct ospf_lsa *new = NULL; struct ospf *top; @@ -893,8 +978,8 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) * status change. * It seems a slip among routers in the routing domain. */ - zlog_info( - "ospf_router_info_lsa_refresh: ROUTER INFORMATION is disabled now."); + zlog_info("RI (%s): ROUTER INFORMATION is disabled now.", + __func__); lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ } @@ -903,37 +988,66 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) if (GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)) != 0) { flog_warn( EC_OSPF_LSA, - "ospf_router_info_lsa_refresh: Unsupported Router Information ID"); + "RI (%s): Unsupported Router Information ID", + __func__); return NULL; } - /* If the lsa's age reached to MaxAge, start flushing procedure. */ - if (IS_LSA_MAXAGE(lsa)) { - UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED); - ospf_opaque_lsa_flush_schedule(lsa); - return NULL; - } - - /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ - new = ospf_router_info_lsa_new(); - new->data->ls_seqnum = lsa_seqnum_increment(lsa); - new->vrf_id = lsa->vrf_id; - - /* Install this LSA into LSDB. */ - /* Given "lsa" will be freed in the next function. */ - top = ospf_lookup_by_vrf_id(lsa->vrf_id); - if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { - flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, - "ospf_router_info_lsa_refresh: ospf_lsa_install() ?"); - ospf_lsa_unlock(&new); - return new; - } - - /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */ - if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + /* Process LSA depending of the flooding scope */ + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { + /* Get context AREA context */ + ai = lookup_by_area(lsa->area); + if (ai == NULL) { + flog_warn( + EC_OSPF_LSA, + "RI (%s): No associated Area", __func__); + return NULL; + } + /* Flush LSA, if the lsa's age reached to MaxAge. */ + if (IS_LSA_MAXAGE(lsa)) { + UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED); + ospf_opaque_lsa_flush_schedule(lsa); + return NULL; + } + /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ + new = ospf_router_info_lsa_new(ai->area); + new->data->ls_seqnum = lsa_seqnum_increment(lsa); + new->vrf_id = lsa->vrf_id; + /* Install this LSA into LSDB. */ + /* Given "lsa" will be freed in the next function. */ + top = ospf_lookup_by_vrf_id(lsa->vrf_id); + if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "RI (%s): ospf_lsa_install() ?", __func__); + ospf_lsa_unlock(&new); + return new; + } + /* Flood updated LSA through AREA */ + ospf_flood_through_area(ai->area, NULL /*nbr */, new); + + } else { /* AS Flooding scope */ + /* Flush LSA, if the lsa's age reached to MaxAge. */ + if (IS_LSA_MAXAGE(lsa)) { + UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED); + ospf_opaque_lsa_flush_schedule(lsa); + return NULL; + } + /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ + new = ospf_router_info_lsa_new(NULL); + new->data->ls_seqnum = lsa_seqnum_increment(lsa); + new->vrf_id = lsa->vrf_id; + /* Install this LSA into LSDB. */ + /* Given "lsa" will be freed in the next function. */ + top = ospf_lookup_by_vrf_id(lsa->vrf_id); + if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "RI (%s): ospf_lsa_install() ?", __func__); + ospf_lsa_unlock(&new); + return new; + } + /* Flood updated LSA through AS */ ospf_flood_through_as(top, NULL /*nbr */, new); - else - ospf_flood_through_area(OspfRI.area, NULL /*nbr */, new); + } /* Debug logging. */ if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { @@ -946,7 +1060,8 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) return new; } -static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode) +static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai, + enum lsa_opcode opcode) { struct ospf_lsa lsa; struct lsa_header lsah; @@ -956,28 +1071,44 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode) memset(&lsa, 0, sizeof(lsa)); memset(&lsah, 0, sizeof(lsah)); - zlog_debug("RI-> LSA schedule %s%s%s", + zlog_debug("RI (%s): LSA schedule %s%s%s", __func__, opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", opcode == REFRESH_THIS_LSA ? "Refresh" : "", opcode == FLUSH_THIS_LSA ? "Flush" : ""); - /* Check LSA flags state coherence */ - if (!CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) - && (opcode != REORIGINATE_THIS_LSA)) - return; + /* Check LSA flags state coherence and collect area information */ + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) { + if ((ai == NULL) || (ai->area == NULL)) { + flog_warn( + EC_OSPF_LSA, + "RI (%s): Router Info is Area scope flooding but area is not set", + __func__); + return; + } - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) - && (opcode == REORIGINATE_THIS_LSA)) - opcode = REFRESH_THIS_LSA; + if (!CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED) + && (opcode != REORIGINATE_THIS_LSA)) + return; - top = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) { - flog_warn( - EC_OSPF_LSA, - "ospf_router_info_lsa_schedule(): Router Info is Area scope flooding but area is not set"); - OspfRI.area = ospf_area_lookup_by_area_id(top, OspfRI.area_id); + if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED) + && (opcode == REORIGINATE_THIS_LSA)) + opcode = REFRESH_THIS_LSA; + + lsa.area = ai->area; + top = ai->area->ospf; + } else { + if (!CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED) + && (opcode != REORIGINATE_THIS_LSA)) + return; + + if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED) + && (opcode == REORIGINATE_THIS_LSA)) + opcode = REFRESH_THIS_LSA; + + top = ospf_lookup_by_vrf_id(VRF_DEFAULT); + lsa.area = NULL; } - lsa.area = OspfRI.area; + lsa.data = &lsah; lsah.type = OspfRI.scope; @@ -989,7 +1120,7 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode) case REORIGINATE_THIS_LSA: if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) ospf_opaque_lsa_reoriginate_schedule( - (void *)OspfRI.area, OSPF_OPAQUE_AREA_LSA, + (void *)ai->area, OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_ROUTER_INFORMATION_LSA); else ospf_opaque_lsa_reoriginate_schedule( @@ -1000,7 +1131,10 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode) ospf_opaque_lsa_refresh_schedule(&lsa); break; case FLUSH_THIS_LSA: - UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED); + if (OspfRI.scope == OSPF_OPAQUE_AREA_LSA) + UNSET_FLAG(ai->flags, RIFLG_LSA_ENGAGED); + else + UNSET_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED); ospf_opaque_lsa_flush_schedule(&lsa); break; } @@ -1014,7 +1148,7 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa) /* Sanity Check */ if (lsa == NULL) { - flog_warn(EC_OSPF_LSA, "OSPF-RI (%s): Abort! LSA is NULL", + flog_warn(EC_OSPF_LSA, "RI (%s): Abort! LSA is NULL", __func__); return -1; } @@ -1356,8 +1490,7 @@ static void ospf_router_info_config_write_router(struct vty *vty) if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) vty_out(vty, " router-info as\n"); else - vty_out(vty, " router-info area %s\n", - inet_ntoa(OspfRI.area_id)); + vty_out(vty, " router-info area\n"); if (OspfRI.pce_info.enabled) { @@ -1405,43 +1538,53 @@ static void ospf_router_info_config_write_router(struct vty *vty) /*------------------------------------------------------------------------* * Followings are vty command functions. *------------------------------------------------------------------------*/ +/* Simple wrapper schedule RI LSA action in function of the scope */ +static void ospf_router_info_schedule(enum lsa_opcode opcode) +{ + struct listnode *node, *nnode; + struct ospf_ri_area_info *ai; + + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { + if (CHECK_FLAG(OspfRI.as_flags, RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule(NULL, opcode); + else if (opcode == REORIGINATE_THIS_LSA) + ospf_router_info_lsa_schedule(NULL, opcode); + } else { + for (ALL_LIST_ELEMENTS(OspfRI.area_info, node, nnode, ai)) { + if (CHECK_FLAG(ai->flags, RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule(ai, opcode); + } + } +} DEFUN (router_info, router_info_area_cmd, - "router-info <as|area A.B.C.D>", + "router-info <as|area [A.B.C.D]>", OSPF_RI_STR "Enable the Router Information functionality with AS flooding scope\n" "Enable the Router Information functionality with Area flooding scope\n" - "OSPF area ID in IP format\n") + "OSPF area ID in IP format (deprecated)\n") { - int idx_ipv4 = 2; - char *area = (argc == 3) ? argv[idx_ipv4]->arg : NULL; - + int idx_mode = 1; uint8_t scope; if (OspfRI.enabled) return CMD_SUCCESS; /* Check and get Area value if present */ - if (area) { - if (!inet_aton(area, &OspfRI.area_id)) { - vty_out(vty, "%% specified Area ID %s is invalid\n", - area); - return CMD_WARNING_CONFIG_FAILED; - } - scope = OSPF_OPAQUE_AREA_LSA; - } else { - OspfRI.area_id.s_addr = 0; + if (strncmp(argv[idx_mode]->arg, "as", 2) == 0) scope = OSPF_OPAQUE_AS_LSA; - } + else + scope = OSPF_OPAQUE_AREA_LSA; /* First start to register Router Information callbacks */ - if ((ospf_router_info_register(scope)) != 0) { + if (!OspfRI.registered && (ospf_router_info_register(scope)) != 0) { vty_out(vty, "%% Unable to register Router Information callbacks."); flog_err( EC_OSPF_INIT_FAIL, - "Unable to register Router Information callbacks. Abort!"); + "RI (%s): Unable to register Router Information callbacks. Abort!", + __func__); return CMD_WARNING_CONFIG_FAILED; } @@ -1463,14 +1606,8 @@ DEFUN (router_info, initialize_params(&OspfRI); - /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) { - zlog_debug("RI-> Refresh LSA following configuration"); - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); - } else { - zlog_debug("RI-> Initial origination following configuration"); - ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA); - } + /* Originate or Refresh RI LSA if already engaged */ + ospf_router_info_schedule(REORIGINATE_THIS_LSA); return CMD_SUCCESS; } @@ -1488,8 +1625,7 @@ DEFUN (no_router_info, if (IS_DEBUG_OSPF_EVENT) zlog_debug("RI-> Router Information: ON -> OFF"); - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(FLUSH_THIS_LSA); + ospf_router_info_schedule(FLUSH_THIS_LSA); OspfRI.enabled = false; @@ -1533,8 +1669,7 @@ DEFUN (pce_address, set_pce_address(value, pi); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); } return CMD_SUCCESS; @@ -1552,8 +1687,7 @@ DEFUN (no_pce_address, unset_param(&OspfRI.pce_info.pce_address); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; } @@ -1583,8 +1717,7 @@ DEFUN (pce_path_scope, set_pce_path_scope(scope, pi); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); } return CMD_SUCCESS; @@ -1602,8 +1735,7 @@ DEFUN (no_pce_path_scope, unset_param(&OspfRI.pce_info.pce_address); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; } @@ -1641,8 +1773,7 @@ DEFUN (pce_domain, set_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; } @@ -1671,8 +1802,7 @@ DEFUN (no_pce_domain, unset_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; } @@ -1711,8 +1841,7 @@ DEFUN (pce_neigbhor, set_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; } @@ -1741,8 +1870,7 @@ DEFUN (no_pce_neighbor, unset_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; } @@ -1773,8 +1901,7 @@ DEFUN (pce_cap_flag, set_pce_cap_flag(cap, pce); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); } return CMD_SUCCESS; @@ -1791,8 +1918,7 @@ DEFUN (no_pce_cap_flag, unset_param(&OspfRI.pce_info.pce_cap_flag); /* Refresh RI LSA if already engaged */ - if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) - ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + ospf_router_info_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; } diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h index 26bcc1b62a..84511ac5e7 100644 --- a/ospfd/ospf_ri.h +++ b/ospfd/ospf_ri.h @@ -170,7 +170,71 @@ struct ri_pce_subtlv_cap_flag { /* Structure to share flooding scope info for Segment Routing */ struct scope_info { uint8_t scope; - struct in_addr area_id; + struct list *areas; +}; + +/* Flags to manage the Router Information LSA. */ +#define RIFLG_LSA_INACTIVE 0x0 +#define RIFLG_LSA_ENGAGED 0x1 +#define RIFLG_LSA_FORCED_REFRESH 0x2 + +/* Store Router Information PCE TLV and SubTLV in network byte order. */ +struct ospf_pce_info { + bool enabled; + struct ri_tlv_pce pce_header; + struct ri_pce_subtlv_address pce_address; + struct ri_pce_subtlv_path_scope pce_scope; + struct list *pce_domain; + struct list *pce_neighbor; + struct ri_pce_subtlv_cap_flag pce_cap_flag; +}; + +/* + * Store Router Information Segment Routing TLV and SubTLV + * in network byte order + */ +struct ospf_ri_sr_info { + bool enabled; + /* Algorithms supported by the node */ + struct ri_sr_tlv_sr_algorithm algo; + /* + * Segment Routing Global Block i.e. label range + * Only one range supported in this code + */ + struct ri_sr_tlv_sid_label_range range; + /* Maximum SID Depth supported by the node */ + struct ri_sr_tlv_node_msd msd; +}; + +/* Store area information to flood LSA per area */ +struct ospf_ri_area_info { + + uint32_t flags; + + /* area pointer if flooding is Type 10 Null if flooding is AS scope */ + struct ospf_area *area; +}; + +/* Following structure are internal use only. */ +struct ospf_router_info { + bool enabled; + + uint8_t registered; + uint8_t scope; + /* LSA flags are only used when scope is AS flooding */ + uint32_t as_flags; + + /* List of area info to flood RI LSA */ + struct list *area_info; + + /* Store Router Information Capabilities LSA */ + struct ri_tlv_router_cap router_cap; + + /* Store PCE capability LSA */ + struct ospf_pce_info pce_info; + + /* Store SR capability LSA */ + struct ospf_ri_sr_info sr_info; }; /* Prototypes. */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 02698d770a..16347f1c5b 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -2398,16 +2398,16 @@ DEFUN (no_ospf_mpls_te_inter_as, zlog_debug("MPLS-TE: Inter-AS support OFF"); if ((OspfMplsTE.enabled) && (OspfMplsTE.inter_as != Off)) { - OspfMplsTE.inter_as = Off; /* Flush all Inter-AS LSA */ for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) if (IS_INTER_AS(lp->type) && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); - } - /* Deregister the Callbacks for Inter-AS support */ - ospf_mpls_te_unregister(); + /* Deregister the Callbacks for Inter-AS support */ + ospf_mpls_te_unregister(); + OspfMplsTE.inter_as = Off; + } return CMD_SUCCESS; } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 35f719fa54..cd78551cb4 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1458,7 +1458,7 @@ DEFUNSH_HIDDEN(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd, } #endif -DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni (1-16777215)", +DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni " CMD_VNI_RANGE, "VXLAN Network Identifier\n" "VNI number\n") { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 4fff376377..263cb3d22c 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -68,9 +68,6 @@ static void vty_show_ip_route_summary(struct vty *vty, static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table); -/* VNI range as per RFC 7432 */ -#define CMD_VNI_RANGE "(1-16777215)" - DEFUN (ip_multicast_mode, ip_multicast_mode_cmd, "ip multicast rpf-lookup-mode <urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix>", diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 0bc1ea50bb..d372d3e832 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -148,8 +148,7 @@ static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client, static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr); static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, uint8_t flags, uint32_t seq); -static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr, - uint8_t flags); +static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr); static zebra_vni_t *zvni_map_vlan(struct interface *ifp, struct interface *br_if, vlanid_t vid); static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); @@ -2305,6 +2304,7 @@ static int zvni_remote_neigh_update(zebra_vni_t *zvni, UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); + ZEBRA_NEIGH_SET_ACTIVE(n); n->r_vtep_ip = zmac->fwd_info.r_vtep_ip; } @@ -2407,7 +2407,7 @@ static void zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) &wctx->r_vtep_ip))) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { zvni_mac_send_del_to_client(wctx->zvni->vni, - &mac->macaddr, mac->flags); + &mac->macaddr); } if (wctx->uninstall) @@ -2494,18 +2494,10 @@ static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, /* * Inform BGP about local MAC deletion. */ -static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr, - uint8_t mac_flags) +static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr) { - uint8_t flags = 0; - - if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY)) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW)) - SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); - - return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, - 0, ZEBRA_MACIP_DEL); + return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */, + 0 /* seq */, ZEBRA_MACIP_DEL); } /* @@ -4304,6 +4296,10 @@ static void process_remote_macip_add(vni_t vni, } } + /* Remove local MAC from BGP. */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + zvni_mac_send_del_to_client(zvni->vni, macaddr); + /* Set "auto" and "remote" forwarding info. */ UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); @@ -4324,6 +4320,7 @@ static void process_remote_macip_add(vni_t vni, /* Install the entry. */ zvni_mac_install(zvni, mac); + } /* Update seq number. */ @@ -4522,6 +4519,13 @@ static void process_remote_macip_del(vni_t vni, } else { if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zvni_process_neigh_on_remote_mac_del(zvni, mac); + /* + * the remote sequence number in the auto mac entry + * needs to be reset to 0 as the mac entry may have + * been removed on all VTEPs (including + * the originating one) + */ + mac->rem_seq = 0; /* If all remote neighbors referencing a remote MAC * go away, we need to uninstall the MAC. @@ -5730,7 +5734,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, ifp->ifindex, vni); /* Remove MAC from BGP. */ - zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); + zvni_mac_send_del_to_client(zvni->vni, macaddr); /* * If there are no neigh associated with the mac delete the mac @@ -5841,7 +5845,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, zvni_process_neigh_on_local_mac_del(zvni, mac); /* Remove MAC from BGP. */ - zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags); + zvni_mac_send_del_to_client(zvni->vni, macaddr); /* * If there are no neigh associated with the mac delete the mac |
