diff options
82 files changed, 2528 insertions, 346 deletions
diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index 86f8bc721e..d10d418572 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -251,7 +251,7 @@ void babelz_zebra_init(void) install_element(CONFIG_NODE, &debug_babel_cmd); install_element(CONFIG_NODE, &no_debug_babel_cmd); - install_element(VIEW_NODE, &show_debugging_babel_cmd); + install_element(ENABLE_NODE, &show_debugging_babel_cmd); } void diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 15ecffdc72..016339ef83 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3998,19 +3998,19 @@ DEFUN(show_bgp_l2vpn_evpn_route, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "Display Detailed Information\n" - "Specify Route type\n" - "EAD (Type-1) route\n" - "EAD (Type-1) route\n" - "MAC-IP (Type-2) route\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n" - "Multicast (Type-3) route\n" - "Ethernet Segment (Type-4) route\n" - "Ethernet Segment (Type-4) route\n" - "Prefix (Type-5) route\n" - "Prefix (Type-5) route\n" + EVPN_TYPE_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_4_HELP_STR + EVPN_TYPE_4_HELP_STR + EVPN_TYPE_5_HELP_STR + EVPN_TYPE_5_HELP_STR JSON_STR) { struct bgp *bgp; @@ -4074,15 +4074,15 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n" - "Specify Route type\n" - "EAD (Type-1) route\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n" - "Ethernet Segment route\n" - "Prefix route\n" + EVPN_RT_HELP_STR + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_4_HELP_STR + EVPN_TYPE_5_HELP_STR JSON_STR) { struct bgp *bgp; @@ -4151,9 +4151,9 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n" + EVPN_RT_HELP_STR + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR "MAC\n" "MAC address (e.g., 00:e0:ec:20:12:62)\n" "IP\n" @@ -4227,7 +4227,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_esi, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "Ethernet Segment Identifier\n" "ESI ID\n" JSON_STR) @@ -4273,13 +4273,13 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "VNI number\n" - "Specify Route type\n" - "EAD (Type-1) route\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n" + EVPN_TYPE_HELP_STR + EVPN_TYPE_1_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR "Remote VTEP\n" "Remote VTEP IP address\n" JSON_STR) @@ -4349,7 +4349,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_macip, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "VNI number\n" "MAC\n" @@ -4419,10 +4419,10 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "VNI number\n" - "Multicast (Type-3) route\n" + EVPN_TYPE_3_HELP_STR "Originating Router IP address\n" JSON_STR) { @@ -4477,7 +4477,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all, BGP_STR L2VPN_HELP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "All VNIs\n" "Print Detailed Output\n" @@ -4602,7 +4602,7 @@ DEFUN(show_bgp_l2vpn_evpn_import_rt, return CMD_SUCCESS; } -DEFPY(test_es_add, +DEFPY_HIDDEN(test_es_add, test_es_add_cmd, "[no$no] test es NAME$esi_str [state NAME$state_str]", NO_STR @@ -4652,7 +4652,7 @@ DEFPY(test_es_add, return CMD_SUCCESS; } -DEFPY(test_es_vni_add, +DEFPY_HIDDEN(test_es_vni_add, test_es_vni_add_cmd, "[no$no] test es NAME$esi_str vni (1-16777215)$vni", NO_STR @@ -4706,30 +4706,30 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd, ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd, "show bgp evpn route [detail] [type <macip|multicast>]", SHOW_STR BGP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "Display Detailed Information\n" - "Specify Route type\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n") + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR) ALIAS_HIDDEN( show_bgp_l2vpn_evpn_route_rd, show_bgp_evpn_route_rd_cmd, "show bgp evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast>]", SHOW_STR BGP_STR EVPN_HELP_STR - "EVPN route information\n" - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n" - "Specify Route type\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n") + EVPN_RT_HELP_STR + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR) ALIAS_HIDDEN( show_bgp_l2vpn_evpn_route_rd_macip, show_bgp_evpn_route_rd_macip_cmd, "show bgp evpn route rd ASN:NN_OR_IP-ADDRESS:NN mac WORD [ip WORD]", SHOW_STR BGP_STR EVPN_HELP_STR - "EVPN route information\n" - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n" + EVPN_RT_HELP_STR + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR "MAC\n" "MAC address (e.g., 00:e0:ec:20:12:62)\n" "IP\n" @@ -4739,12 +4739,12 @@ ALIAS_HIDDEN( show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd, "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" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "VNI number\n" - "Specify Route type\n" - "MAC-IP (Type-2) route\n" - "Multicast (Type-3) route\n" + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR "Remote VTEP\n" "Remote VTEP IP address\n") @@ -4752,7 +4752,7 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip, show_bgp_evpn_route_vni_macip_cmd, "show bgp evpn route vni " CMD_VNI_RANGE " mac WORD [ip WORD]", SHOW_STR BGP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "VNI number\n" "MAC\n" @@ -4764,16 +4764,16 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast, show_bgp_evpn_route_vni_multicast_cmd, "show bgp evpn route vni " CMD_VNI_RANGE " multicast A.B.C.D", SHOW_STR BGP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "VNI number\n" - "Multicast (Type-3) route\n" + EVPN_TYPE_3_HELP_STR "Originating Router IP address\n") ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd, "show bgp evpn route vni all [detail] [vtep A.B.C.D]", SHOW_STR BGP_STR EVPN_HELP_STR - "EVPN route information\n" + EVPN_RT_HELP_STR "VXLAN Network Identifier\n" "All VNIs\n" "Print Detailed Output\n" @@ -4854,8 +4854,8 @@ DEFUN_NOSH (exit_vni, DEFUN (bgp_evpn_vrf_rd, bgp_evpn_vrf_rd_cmd, "rd ASN:NN_OR_IP-ADDRESS:NN", - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n") + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR) { int ret; struct prefix_rd prd; @@ -4883,8 +4883,8 @@ DEFUN (no_bgp_evpn_vrf_rd, no_bgp_evpn_vrf_rd_cmd, "no rd ASN:NN_OR_IP-ADDRESS:NN", NO_STR - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n") + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR) { int ret; struct prefix_rd prd; @@ -4919,7 +4919,7 @@ DEFUN (no_bgp_evpn_vrf_rd_without_val, no_bgp_evpn_vrf_rd_without_val_cmd, "no rd", NO_STR - "Route Distinguisher\n") + EVPN_RT_DIST_HELP_STR) { struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); @@ -4939,8 +4939,8 @@ DEFUN (no_bgp_evpn_vrf_rd_without_val, DEFUN (bgp_evpn_vni_rd, bgp_evpn_vni_rd_cmd, "rd ASN:NN_OR_IP-ADDRESS:NN", - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n") + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR) { struct prefix_rd prd; struct bgp *bgp = VTY_GET_CONTEXT(bgp); @@ -4975,8 +4975,8 @@ DEFUN (no_bgp_evpn_vni_rd, no_bgp_evpn_vni_rd_cmd, "no rd ASN:NN_OR_IP-ADDRESS:NN", NO_STR - "Route Distinguisher\n" - "ASN:XX or A.B.C.D:XX\n") + EVPN_RT_DIST_HELP_STR + EVPN_ASN_IP_HELP_STR) { struct prefix_rd prd; struct bgp *bgp = VTY_GET_CONTEXT(bgp); @@ -5018,7 +5018,7 @@ DEFUN (no_bgp_evpn_vni_rd_without_val, no_bgp_evpn_vni_rd_without_val_cmd, "no rd", NO_STR - "Route Distinguisher\n") + EVPN_RT_DIST_HELP_STR) { struct bgp *bgp = VTY_GET_CONTEXT(bgp); VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); @@ -5249,7 +5249,7 @@ DEFUN (no_bgp_evpn_vrf_rt, "import and export\n" "import\n" "export\n" - "ASN:XX or A.B.C.D:XX\n") + EVPN_ASN_IP_HELP_STR) { struct bgp *bgp = VTY_GET_CONTEXT(bgp); int rt_type, found_ecomdel; @@ -5413,7 +5413,7 @@ DEFUN (no_bgp_evpn_vni_rt, "import and export\n" "import\n" "export\n" - "ASN:XX or A.B.C.D:XX\n") + EVPN_ASN_IP_HELP_STR) { struct bgp *bgp = VTY_GET_CONTEXT(bgp); VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); diff --git a/bgpd/bgp_nb.c b/bgpd/bgp_nb.c index b9fff124df..551bdb0c2b 100644 --- a/bgpd/bgp_nb.c +++ b/bgpd/bgp_nb.c @@ -30,8 +30,8 @@ const struct frr_yang_module_info frr_bgp_info = { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp", .cbs = { .cli_show = cli_show_router_bgp, - .create = bgp_create, - .destroy = bgp_destroy, + .create = bgp_router_create, + .destroy = bgp_router_destroy, } }, { diff --git a/bgpd/bgp_nb.h b/bgpd/bgp_nb.h index 097b40d7b7..341666c7ed 100644 --- a/bgpd/bgp_nb.h +++ b/bgpd/bgp_nb.h @@ -26,8 +26,8 @@ extern const struct frr_yang_module_info frr_bgp_info; /* prototypes */ -int bgp_create(struct nb_cb_create_args *args); -int bgp_destroy(struct nb_cb_destroy_args *args); +int bgp_router_create(struct nb_cb_create_args *args); +int bgp_router_destroy(struct nb_cb_destroy_args *args); int bgp_global_local_as_modify(struct nb_cb_modify_args *args); int bgp_global_router_id_modify(struct nb_cb_modify_args *args); int bgp_global_router_id_destroy(struct nb_cb_destroy_args *args); diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index ba7c5714bb..f01325577c 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -62,7 +62,7 @@ int routing_control_plane_protocols_name_validate( * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp */ -int bgp_create(struct nb_cb_create_args *args) +int bgp_router_create(struct nb_cb_create_args *args) { const struct lyd_node *vrf_dnode; struct bgp *bgp; @@ -107,8 +107,8 @@ int bgp_create(struct nb_cb_create_args *args) if (ret == BGP_ERR_INSTANCE_MISMATCH) { snprintf( args->errmsg, args->errmsg_len, - "BGP instance name and AS number mismatch\nBGP instance is already running; AS is %u", - as); + "BGP instance name and AS number mismatch\nBGP instance is already running; AS is %u, input-as %u", + bgp->as, as); return NB_ERR_INCONSISTENCY; } @@ -132,7 +132,7 @@ int bgp_create(struct nb_cb_create_args *args) return NB_OK; } -int bgp_destroy(struct nb_cb_destroy_args *args) +int bgp_router_destroy(struct nb_cb_destroy_args *args) { struct bgp *bgp; @@ -140,6 +140,9 @@ int bgp_destroy(struct nb_cb_destroy_args *args) case NB_EV_VALIDATE: bgp = nb_running_get_entry(args->dnode, NULL, false); + if (!bgp) + return NB_OK; + if (bgp->l3vni) { snprintf(args->errmsg, args->errmsg_len, "Please unconfigure l3vni %u", bgp->l3vni); @@ -186,16 +189,42 @@ int bgp_global_local_as_modify(struct nb_cb_modify_args *args) { struct bgp *bgp; as_t as; + const struct lyd_node *vrf_dnode; + const char *vrf_name; + const char *name = NULL; + enum bgp_instance_type inst_type; + int ret; + bool is_view_inst = false; switch (args->event) { case NB_EV_VALIDATE: as = yang_dnode_get_uint32(args->dnode, NULL); - bgp = nb_running_get_entry_non_rec(args->dnode, NULL, false); - if (bgp && bgp->as != as) { - snprintf(args->errmsg, args->errmsg_len, - "BGP instance is already running; AS is %u", - bgp->as); + inst_type = BGP_INSTANCE_TYPE_DEFAULT; + + vrf_dnode = yang_dnode_get_parent(args->dnode, + "control-plane-protocol"); + vrf_name = yang_dnode_get_string(vrf_dnode, "./vrf"); + + if (strmatch(vrf_name, VRF_DEFAULT_NAME)) { + name = NULL; + } else { + name = vrf_name; + inst_type = BGP_INSTANCE_TYPE_VRF; + } + + is_view_inst = yang_dnode_get_bool(args->dnode, + "../instance-type-view"); + if (is_view_inst) + inst_type = BGP_INSTANCE_TYPE_VIEW; + + ret = bgp_lookup_by_as_name_type(&bgp, &as, name, inst_type); + if (ret == BGP_ERR_INSTANCE_MISMATCH) { + snprintf( + args->errmsg, args->errmsg_len, + "BGP instance name and AS number mismatch\nBGP instance is already running; input-as %u", + as); + return NB_ERR_VALIDATION; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 43ba4ceef6..8977b1651a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3167,7 +3167,8 @@ bool bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT); - if (pcount > (pcount * peer->pmax_threshold[afi][safi] / 100)) { + if (pcount + > (peer->pmax[afi][safi] * peer->pmax_threshold[afi][safi] / 100)) { if (CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD) && !always) @@ -12995,10 +12996,6 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer, if (use_json) SET_FLAG(show_flags, BGP_SHOW_OPT_JSON); - /* labeled-unicast routes live in the unicast table */ - if (safi == SAFI_LABELED_UNICAST) - safi = SAFI_UNICAST; - if (!peer || !peer->afc[afi][safi]) { if (use_json) { json_object *json_no = NULL; @@ -13014,6 +13011,10 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer, return CMD_WARNING; } + /* labeled-unicast routes live in the unicast table */ + if (safi == SAFI_LABELED_UNICAST) + safi = SAFI_UNICAST; + return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, show_flags); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 38dad59e60..c8a3c28523 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1222,12 +1222,9 @@ DEFUN_YANG_NOSH(router_bgp, vty_out(vty, "%% Please specify ASN and VRF\n"); return CMD_WARNING_CONFIG_FAILED; } - /* unset the auto created flag as the user config is now present - */ - UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO); snprintf(base_xpath, sizeof(base_xpath), FRR_BGP_GLOBAL_XPATH, - "frr-bgp:bgp", "bgp", name ? name : VRF_DEFAULT_NAME); + "frr-bgp:bgp", "bgp", VRF_DEFAULT_NAME); nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); snprintf(as_str, 12, "%d", bgp->as); @@ -1239,6 +1236,7 @@ DEFUN_YANG_NOSH(router_bgp, NB_OP_MODIFY, "true"); } + nb_cli_pending_commit_check(vty); ret = nb_cli_apply_changes(vty, base_xpath); if (ret == CMD_SUCCESS) { VTY_PUSH_XPATH(BGP_NODE, base_xpath); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 30566b2c16..3e2ca70a02 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3238,12 +3238,10 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id, return bgp_check_main_socket(create, bgp); } -/* Called from VTY commands. */ -int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, - enum bgp_instance_type inst_type) +int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name, + enum bgp_instance_type inst_type) { struct bgp *bgp; - struct vrf *vrf = NULL; /* Multiple instance check. */ if (name) @@ -3251,7 +3249,6 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, else bgp = bgp_get_default(); - /* Already exists. */ if (bgp) { if (bgp->as != *as) { *as = bgp->as; @@ -3262,6 +3259,27 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, *bgp_val = bgp; return BGP_SUCCESS; } + *bgp_val = NULL; + + return BGP_SUCCESS; +} + +/* Called from VTY commands. */ +int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, + enum bgp_instance_type inst_type) +{ + struct bgp *bgp; + struct vrf *vrf = NULL; + int ret = 0; + + ret = bgp_lookup_by_as_name_type(bgp_val, as, name, inst_type); + switch (ret) { + case BGP_ERR_INSTANCE_MISMATCH: + return ret; + case BGP_SUCCESS: + if (*bgp_val) + return ret; + } bgp = bgp_create(as, name, inst_type); if (bgp_option_check(BGP_OPT_NO_ZEBRA) && name) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 3e3c6fc9e3..00f1d5acc9 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -2181,6 +2181,9 @@ extern struct peer *peer_new(struct bgp *bgp); extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, const char *ip_str, bool use_json); +extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, + const char *name, + enum bgp_instance_type inst_type); /* Hooks */ DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer)) diff --git a/configure.ac b/configure.ac index 3cc74c4110..8e86ba87ff 100755 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,13 @@ AC_ARG_WITH([yangmodelsdir], [AS_HELP_STRING([--with-yangmodelsdir=DIR], [yang m ]) AC_SUBST([yangmodelsdir]) +AC_ARG_WITH([vici-socket], [AS_HELP_STRING([--with-vici-socket=PATH], [vici-socket (/var/run/charon.vici)])], [ + vici_socket="$withval" +], [ + vici_socket="/var/run/charon.vici" +]) +AC_DEFINE_UNQUOTED([VICI_SOCKET], ["$vici_socket"], [StrongSWAN vici socket path]) + AC_ARG_ENABLE(tcmalloc, AS_HELP_STRING([--enable-tcmalloc], [Turn on tcmalloc]), [case "${enableval}" in @@ -2512,6 +2519,7 @@ group for vty sockets : ${enable_vty_group} config file mask : ${enable_configfile_mask} log file mask : ${enable_logfile_mask} zebra protobuf enabled : ${enable_protobuf:-no} +vici socket path : ${vici_socket} The above user and group must have read/write access to the state file directory and to the config files in the config file directory." diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index f345464a35..4183ac6480 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -779,13 +779,12 @@ necessary replacements. .. _style-exceptions: Exceptions -^^^^^^^^^^ +"""""""""" FRR project code comes from a variety of sources, so there are some stylistic exceptions in place. They are organized here by branch. -For ``master`` -"""""""""""""" +For ``master``: BSD coding style applies to: @@ -797,8 +796,7 @@ BSD coding style applies to: - Indents are 4 spaces - Function return types are on their own line -For ``stable/3.0`` and ``stable/2.0`` -""""""""""""""""""""""""""""""""""""" +For ``stable/3.0`` and ``stable/2.0``: GNU coding style apply to the following parts: @@ -816,6 +814,21 @@ BSD coding style applies to: - ``ldpd/`` + +Python Code +^^^^^^^^^^^ + +Format all Python code with `black <https://github.com/psf/black>`_. + +In a line:: + + python3 -m black <file.py> + +Run this on any Python files you modify before committing. + +FRR's Python code has been formatted with black version 19.10b. + + YANG ^^^^ diff --git a/doc/manpages/frr-zebra.rst b/doc/manpages/frr-zebra.rst index cfb368bf44..722b011ecd 100644 --- a/doc/manpages/frr-zebra.rst +++ b/doc/manpages/frr-zebra.rst @@ -25,10 +25,6 @@ OPTIONS available for the |DAEMON| command: Runs in batch mode, zebra parses its config and exits. -.. option:: -k, --keep_kernel - - On startup, don't delete self inserted routes. - .. option:: -s, --nl-bufsize <netlink-buffer-size> Set netlink receive buffer size. There are cases where zebra daemon can't handle flood of netlink messages from kernel. If you ever see "recvmsg overrun" messages in zebra log, you are in trouble. diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 0fd33eace8..ee06578b7c 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -380,6 +380,10 @@ options to the configuration script. Look for YANG modules in `dir` [`prefix`/share/yang]. Note that the FRR YANG modules will be installed here. +.. option:: --with-vici-socket <path> + + Set StrongSWAN vici interface socket path [/var/run/charon.vici]. + Python dependency, documentation and tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 010526b637..b66774ca0e 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -853,6 +853,50 @@ Redistribution .. index:: no router zebra .. clicmd:: no router zebra +Graceful Restart Helper +======================= + +.. index:: graceful-restart helper-only [A.B.C.D] +.. clicmd:: graceful-restart helper-only [A.B.C.D] + +.. index:: no graceful-restart helper-only [A.B.C.D] +.. clicmd:: no graceful-restart helper-only [A.B.C.D] + + Configure Graceful Restart (RFC 3623) helper support. + By default, helper support is disabled for all neighbours. + This config enables/disables helper support on this router + for all neighbours. + To enable/disable helper support for a specific + neighbour, the router-id (A.B.C.D) has to be specified. + +.. index:: graceful-restart helper strict-lsa-checking +.. clicmd:: graceful-restart helper strict-lsa-checking + +.. index:: no graceful-restart helper strict-lsa-checking +.. clicmd:: no graceful-restart helper strict-lsa-checking + + If 'strict-lsa-checking' is configured then the helper will + abort the Graceful Restart when a LSA change occurs which + affects the restarting router. + By default 'strict-lsa-checking' is enabled" + +.. index:: graceful-restart helper supported-grace-time +.. clicmd:: graceful-restart helper supported-grace-time + +.. index:: no graceful-restart helper supported-grace-time +.. clicmd:: no graceful-restart helper supported-grace-time + + Supports as HELPER for configured grace period. + +.. index:: graceful-restart helper planned-only +.. clicmd:: graceful-restart helper planned-only + +.. index:: no graceful-restart helper planned-only +.. clicmd:: no graceful-restart helper planned-only + + It helps to support as HELPER only for planned + restarts. By default, it supports both planned and + unplanned outages. .. _showing-ospf-information: @@ -918,6 +962,12 @@ Showing Information Show the OSPF routing table, as determined by the most recent SPF calculation. +.. index:: show ip ospf graceful-restart helper [detail] [json] +.. clicmd:: show ip ospf graceful-restart helper [detail] [json] + + Displays the Grcaeful Restart Helper details including helper + config changes. + .. _opaque-lsa: Opaque LSA @@ -1218,10 +1268,17 @@ Debugging OSPF Show debug information of ZEBRA API +.. index:: debug ospf graceful-restart helper +.. clicmd:: debug ospf graceful-restart helper + +.. index:: no debug ospf graceful-restart helper +.. clicmd:: no debug ospf graceful-restart helper + + Enable/disable debug information for OSPF Graceful Restart Helper + .. index:: show debugging ospf .. clicmd:: show debugging ospf - OSPF Configuration Examples =========================== diff --git a/doc/user/pim.rst b/doc/user/pim.rst index b33ca3f2f4..b0a90bfc48 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -337,10 +337,10 @@ caution. Most of the time this will not be necessary. Insert into the Multicast Rib Route A.B.C.D/M using the specified INTERFACE. The distance can be specified as well if desired. -.. _msdp-configuration +.. _msdp-configuration: Multicast Source Discovery Protocol (MSDP) Configuration -==================== +======================================================== .. index:: ip msdp mesh-group [WORD] member A.B.C.D .. clicmd:: ip msdp mesh-group [WORD] member A.B.C.D diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index d6988095e5..695e1318ae 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -71,13 +71,14 @@ DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)) int isis_if_new_hook(struct interface *); int isis_if_delete_hook(struct interface *); -struct isis_circuit *isis_circuit_new(void) +struct isis_circuit *isis_circuit_new(struct isis *isis) { struct isis_circuit *circuit; int i; circuit = XCALLOC(MTYPE_ISIS_CIRCUIT, sizeof(struct isis_circuit)); + circuit->isis = isis; /* * Default values */ @@ -626,8 +627,8 @@ int isis_circuit_up(struct isis_circuit *circuit) } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - circuit->circuit_id = isis_circuit_id_gen(circuit->area->isis, - circuit->interface); + circuit->circuit_id = + isis_circuit_id_gen(circuit->isis, circuit->interface); if (!circuit->circuit_id) { flog_err( EC_ISIS_CONFIG, @@ -811,7 +812,7 @@ void isis_circuit_down(struct isis_circuit *circuit) circuit->lsp_regenerate_pending[0] = 0; circuit->lsp_regenerate_pending[1] = 0; - _ISIS_CLEAR_FLAG(circuit->area->isis->circuit_ids_used, + _ISIS_CLEAR_FLAG(circuit->isis->circuit_ids_used, circuit->circuit_id); circuit->circuit_id = 0; } else if (circuit->circ_type == CIRCUIT_T_P2P) { diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 5766d1962f..48afd24b6d 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -79,6 +79,7 @@ struct isis_circuit_arg { struct isis_circuit { int state; uint8_t circuit_id; /* l1/l2 bcast CircuitID */ + struct isis *isis; struct isis_area *area; /* back pointer to the area */ struct interface *interface; /* interface info from z */ int fd; /* IS-IS l1/2 socket */ @@ -163,7 +164,7 @@ struct isis_circuit { DECLARE_QOBJ_TYPE(isis_circuit) void isis_circuit_init(void); -struct isis_circuit *isis_circuit_new(void); +struct isis_circuit *isis_circuit_new(struct isis *isis); void isis_circuit_del(struct isis_circuit *circuit); struct isis_circuit *circuit_lookup_by_ifp(struct interface *ifp, struct list *list); diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index 929b4c26e8..736d8d63f9 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -65,6 +65,7 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) { int old_state; struct isis *isis = NULL; + struct isis_area *area = NULL; old_state = circuit ? circuit->state : C_STATE_NA; if (IS_DEBUG_EVENTS) @@ -77,21 +78,22 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) assert(circuit == NULL); switch (event) { case ISIS_ENABLE: - circuit = isis_circuit_new(); - isis_circuit_configure(circuit, - (struct isis_area *)arg); + area = arg; + + circuit = isis_circuit_new(area->isis); + isis_circuit_configure(circuit, area); circuit->state = C_STATE_CONF; break; case IF_UP_FROM_Z: - circuit = isis_circuit_new(); - isis_circuit_if_add(circuit, (struct interface *)arg); - isis = isis_lookup_by_vrfid(circuit->interface->vrf_id); + isis = isis_lookup_by_vrfid(((struct interface *)arg)->vrf_id); if (isis == NULL) { zlog_warn( " %s : ISIS routing instance not found", __func__); break; } + circuit = isis_circuit_new(isis); + isis_circuit_if_add(circuit, (struct interface *)arg); listnode_add(isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; @@ -117,7 +119,7 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) circuit->state = C_STATE_UP; isis_event_circuit_state_change(circuit, circuit->area, 1); - listnode_delete(circuit->area->isis->init_circ_list, + listnode_delete(circuit->isis->init_circ_list, circuit); break; case IF_UP_FROM_Z: @@ -129,15 +131,8 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) break; case IF_DOWN_FROM_Z: isis_circuit_if_del(circuit, (struct interface *)arg); - isis = isis_lookup_by_vrfid(circuit->interface->vrf_id); - if (isis == NULL) { - zlog_warn( - "%s : ISIS routing instance not found", - __func__); - break; - } - - listnode_delete(isis->init_circ_list, circuit); + listnode_delete(circuit->isis->init_circ_list, + circuit); isis_circuit_del(circuit); circuit = NULL; break; @@ -152,6 +147,7 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) case IF_UP_FROM_Z: isis_circuit_if_add(circuit, (struct interface *)arg); if (isis_circuit_up(circuit) != ISIS_OK) { + isis_circuit_if_del(circuit, (struct interface *)arg); flog_err( EC_ISIS_CONFIG, "Could not bring up %s because of invalid config.", @@ -183,21 +179,13 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) zlog_warn("circuit already connected"); break; case ISIS_DISABLE: + isis = circuit->isis; isis_circuit_down(circuit); isis_circuit_deconfigure(circuit, (struct isis_area *)arg); circuit->state = C_STATE_INIT; isis_event_circuit_state_change( circuit, (struct isis_area *)arg, 0); - - isis = isis_lookup_by_vrfid(circuit->interface->vrf_id); - if (isis == NULL) { - zlog_warn( - "%s : ISIS routing instance not found", - __func__); - break; - } - listnode_add(isis->init_circ_list, circuit); break; case IF_DOWN_FROM_Z: diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c index 318fb9fab8..3324d74e0f 100644 --- a/isisd/isis_dr.c +++ b/isisd/isis_dr.c @@ -225,7 +225,7 @@ int isis_dr_resign(struct isis_circuit *circuit, int level) THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); circuit->lsp_regenerate_pending[level - 1] = 0; - memcpy(id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN); + memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID(id) = circuit->circuit_id; LSP_FRAGMENT(id) = 0; lsp_purge_pseudo(id, circuit, level); @@ -278,7 +278,7 @@ int isis_dr_commence(struct isis_circuit *circuit, int level) /* there was a dr elected, purge its LSPs from the db */ lsp_purge_pseudo(old_dr, circuit, level); } - memcpy(circuit->u.bc.l1_desig_is, circuit->area->isis->sysid, + memcpy(circuit->u.bc.l1_desig_is, circuit->isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; @@ -300,7 +300,7 @@ int isis_dr_commence(struct isis_circuit *circuit, int level) /* there was a dr elected, purge its LSPs from the db */ lsp_purge_pseudo(old_dr, circuit, level); } - memcpy(circuit->u.bc.l2_desig_is, circuit->area->isis->sysid, + memcpy(circuit->u.bc.l2_desig_is, circuit->isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 1af6f417dc..7abfbe63cc 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1611,7 +1611,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level) || (circuit->u.bc.is_dr[level - 1] == 0)) return ISIS_ERROR; - memcpy(lsp_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN); + memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN); LSP_FRAGMENT(lsp_id) = 0; LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id; @@ -1671,7 +1671,7 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level) || (circuit->u.bc.is_dr[level - 1] == 0)) return ISIS_ERROR; - memcpy(lsp_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN); + memcpy(lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id; LSP_FRAGMENT(lsp_id) = 0; @@ -1728,7 +1728,7 @@ static int lsp_l1_refresh_pseudo(struct thread *thread) if ((circuit->u.bc.is_dr[0] == 0) || (circuit->is_type & IS_LEVEL_1) == 0) { - memcpy(id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN); + memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID(id) = circuit->circuit_id; LSP_FRAGMENT(id) = 0; lsp_purge_pseudo(id, circuit, IS_LEVEL_1); @@ -1750,7 +1750,7 @@ static int lsp_l2_refresh_pseudo(struct thread *thread) if ((circuit->u.bc.is_dr[1] == 0) || (circuit->is_type & IS_LEVEL_2) == 0) { - memcpy(id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN); + memcpy(id, circuit->isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID(id) = circuit->circuit_id; LSP_FRAGMENT(id) = 0; lsp_purge_pseudo(id, circuit, IS_LEVEL_2); diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 2c7e79be56..d5f4c605c4 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -2135,11 +2135,11 @@ int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args) vrf_name = yang_dnode_get_string(args->dnode, NULL); circuit = circuit_scan_by_ifp(ifp); - if (circuit && circuit->area && circuit->area->isis - && strcmp(circuit->area->isis->name, vrf_name)) { + if (circuit && circuit->area && circuit->isis + && strcmp(circuit->isis->name, vrf_name)) { snprintf(args->errmsg, args->errmsg_len, "ISIS circuit is already defined on vrf %s", - circuit->area->isis->name); + circuit->isis->name); return NB_ERR_VALIDATION; } } @@ -2805,7 +2805,7 @@ int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args) if (circuit == NULL || circuit->area == NULL) return NB_ERR_VALIDATION; - if (circuit->area->isis->vrf_id != VRF_DEFAULT) { + if (circuit->isis->vrf_id != VRF_DEFAULT) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; @@ -2817,7 +2817,7 @@ int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args) case NB_EV_APPLY: circuit = nb_running_get_entry(args->dnode, NULL, true); ldp_sync_enable = yang_dnode_get_bool(args->dnode, NULL); - isis = circuit->area->isis; + isis = circuit->isis; if (circuit->ldp_sync_info == NULL) isis_ldp_sync_if_init(circuit, isis); @@ -2873,7 +2873,7 @@ int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args) if (circuit == NULL || circuit->area == NULL) return NB_ERR_VALIDATION; - if (circuit->area->isis->vrf_id != VRF_DEFAULT) { + if (circuit->isis->vrf_id != VRF_DEFAULT) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; @@ -2885,7 +2885,7 @@ int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args) case NB_EV_APPLY: circuit = nb_running_get_entry(args->dnode, NULL, true); holddown = yang_dnode_get_uint16(args->dnode, NULL); - isis = circuit->area->isis; + isis = circuit->isis; if (circuit->ldp_sync_info == NULL) isis_ldp_sync_if_init(circuit, isis); @@ -2912,7 +2912,7 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args) || circuit->area == NULL) return NB_ERR_VALIDATION; - if (circuit->area->isis->vrf_id != VRF_DEFAULT) { + if (circuit->isis->vrf_id != VRF_DEFAULT) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; @@ -2923,7 +2923,7 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args) break; case NB_EV_APPLY: circuit = nb_running_get_entry(args->dnode, NULL, true); - isis = circuit->area->isis; + isis = circuit->isis; ldp_sync_info = circuit->ldp_sync_info; UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 43b9f6685e..d6f2571178 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -76,8 +76,7 @@ static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit, lenp = stream_get_endp(circuit->snd_stream); stream_putw(circuit->snd_stream, 0); /* PDU length */ - stream_put(circuit->snd_stream, circuit->area->isis->sysid, - ISIS_SYS_ID_LEN); + stream_put(circuit->snd_stream, circuit->isis->sysid, ISIS_SYS_ID_LEN); stream_putc(circuit->snd_stream, circuit->idx); stream_putc(circuit->snd_stream, 9); /* code */ stream_putc(circuit->snd_stream, 16); /* len */ @@ -143,8 +142,8 @@ static int process_p2p_hello(struct iih_info *iih) } if (tw_adj->neighbor_set - && (memcmp(tw_adj->neighbor_id, - iih->circuit->area->isis->sysid, ISIS_SYS_ID_LEN) + && (memcmp(tw_adj->neighbor_id, iih->circuit->isis->sysid, + ISIS_SYS_ID_LEN) || tw_adj->neighbor_circuit_id != (uint32_t)iih->circuit->idx)) { @@ -728,7 +727,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, goto out; } - if (!memcmp(iih.sys_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN)) { + if (!memcmp(iih.sys_id, circuit->isis->sysid, ISIS_SYS_ID_LEN)) { zlog_warn( "ISIS-Adj (%s): Received IIH with own sysid - discard", circuit->area->area_tag); @@ -1044,7 +1043,7 @@ dontcheckadj: ack_lsp(&hdr, circuit, level); goto out; /* FIXME: do we need a purge? */ } else { - if (memcmp(hdr.lsp_id, circuit->area->isis->sysid, + if (memcmp(hdr.lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN)) { /* LSP by some other system -> do 7.3.16.4 b) */ /* 7.3.16.4 b) 1) */ @@ -1139,8 +1138,7 @@ dontcheckadj: } /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a * purge */ - if (memcmp(hdr.lsp_id, circuit->area->isis->sysid, ISIS_SYS_ID_LEN) - == 0) { + if (memcmp(hdr.lsp_id, circuit->isis->sysid, ISIS_SYS_ID_LEN) == 0) { if (!lsp) { /* 7.3.16.4: initiate a purge */ lsp_purge_non_exist(level, &hdr, circuit->area); @@ -1427,7 +1425,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, entry = entry->next) { struct isis_lsp *lsp = lsp_search(&circuit->area->lspdb[level - 1], entry->id); - bool own_lsp = !memcmp(entry->id, circuit->area->isis->sysid, + bool own_lsp = !memcmp(entry->id, circuit->isis->sysid, ISIS_SYS_ID_LEN); if (lsp) { /* 7.3.15.2 b) 1) is this LSP newer */ @@ -1468,7 +1466,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, * insert it and set SSN on it */ if (entry->rem_lifetime && entry->checksum && entry->seqno - && memcmp(entry->id, circuit->area->isis->sysid, + && memcmp(entry->id, circuit->isis->sysid, ISIS_SYS_ID_LEN)) { struct isis_lsp *lsp0 = NULL; @@ -1679,11 +1677,11 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa) if (pdu_type != FS_LINK_STATE /* FS PDU doesn't contain max area addr field */ && max_area_addrs != 0 - && max_area_addrs != circuit->area->isis->max_area_addrs) { + && max_area_addrs != circuit->isis->max_area_addrs) { flog_err( EC_ISIS_PACKET, "maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %hhu while the parameter for this IS is %u", - max_area_addrs, circuit->area->isis->max_area_addrs); + max_area_addrs, circuit->isis->max_area_addrs); circuit->max_area_addr_mismatches++; #ifndef FABRICD /* send northbound notification */ @@ -1792,8 +1790,7 @@ static void put_hello_hdr(struct isis_circuit *circuit, int level, fill_fixed_hdr(pdu_type, circuit->snd_stream); stream_putc(circuit->snd_stream, circuit->is_type); - stream_put(circuit->snd_stream, circuit->area->isis->sysid, - ISIS_SYS_ID_LEN); + stream_put(circuit->snd_stream, circuit->isis->sysid, ISIS_SYS_ID_LEN); uint32_t holdtime = circuit->hello_multiplier[level - 1] * circuit->hello_interval[level - 1]; @@ -2064,8 +2061,7 @@ int send_csnp(struct isis_circuit *circuit, int level) size_t len_pointer = stream_get_endp(circuit->snd_stream); stream_putw(circuit->snd_stream, 0); - stream_put(circuit->snd_stream, circuit->area->isis->sysid, - ISIS_SYS_ID_LEN); + stream_put(circuit->snd_stream, circuit->isis->sysid, ISIS_SYS_ID_LEN); /* with zero circuit id - ref 9.10, 9.11 */ stream_putc(circuit->snd_stream, 0); @@ -2242,8 +2238,7 @@ static int send_psnp(int level, struct isis_circuit *circuit) size_t len_pointer = stream_get_endp(circuit->snd_stream); stream_putw(circuit->snd_stream, 0); /* length is filled in later */ - stream_put(circuit->snd_stream, circuit->area->isis->sysid, - ISIS_SYS_ID_LEN); + stream_put(circuit->snd_stream, circuit->isis->sysid, ISIS_SYS_ID_LEN); stream_putc(circuit->snd_stream, circuit->idx); struct isis_passwd *passwd = (level == ISIS_LEVEL1) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 15b51589ae..9ed868e795 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -85,9 +85,12 @@ static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS) static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS) { + struct isis_circuit *circuit; struct connected *c; +#ifdef EXTREME_DEBUG struct prefix *p; char buf[PREFIX2STR_BUFFER]; +#endif /* EXTREME_DEBUG */ c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, vrf_id); @@ -95,25 +98,29 @@ static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS) if (c == NULL) return 0; +#ifdef EXTREME_DEBUG p = c->address; - prefix2str(p, buf, sizeof(buf)); -#ifdef EXTREME_DEBUG + if (p->family == AF_INET) zlog_debug("connected IP address %s", buf); if (p->family == AF_INET6) zlog_debug("connected IPv6 address %s", buf); #endif /* EXTREME_DEBUG */ - if (if_is_operative(c->ifp)) - isis_circuit_add_addr(circuit_scan_by_ifp(c->ifp), c); + + if (if_is_operative(c->ifp)) { + circuit = circuit_scan_by_ifp(c->ifp); + if (circuit) + isis_circuit_add_addr(circuit, c); + } return 0; } static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS) { + struct isis_circuit *circuit; struct connected *c; - struct interface *ifp; #ifdef EXTREME_DEBUG struct prefix *p; char buf[PREFIX2STR_BUFFER]; @@ -125,8 +132,6 @@ static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS) if (c == NULL) return 0; - ifp = c->ifp; - #ifdef EXTREME_DEBUG p = c->address; prefix2str(p, buf, sizeof(buf)); @@ -137,8 +142,12 @@ static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS) zlog_debug("disconnected IPv6 address %s", buf); #endif /* EXTREME_DEBUG */ - if (if_is_operative(ifp)) - isis_circuit_del_addr(circuit_scan_by_ifp(ifp), c); + if (if_is_operative(c->ifp)) { + circuit = circuit_scan_by_ifp(c->ifp); + if (circuit) + isis_circuit_del_addr(circuit, c); + } + connected_free(&c); return 0; diff --git a/lib/command.h b/lib/command.h index dc148a92a8..677d4b2dad 100644 --- a/lib/command.h +++ b/lib/command.h @@ -452,6 +452,17 @@ struct cmd_node { #define GR_NEIGHBOR_HELPER_CMD "Graceful Restart Helper command for a neighbor\n" #define NO_GR_NEIGHBOR_HELPER_CMD "Undo Graceful Restart Helper command for a neighbor\n" +/* EVPN help Strings */ +#define EVPN_RT_HELP_STR "EVPN route information\n" +#define EVPN_RT_DIST_HELP_STR "Route Distinguisher\n" +#define EVPN_ASN_IP_HELP_STR "ASN:XX or A.B.C.D:XX\n" +#define EVPN_TYPE_HELP_STR "Specify Route type\n" +#define EVPN_TYPE_1_HELP_STR "EAD (Type-1) route\n" +#define EVPN_TYPE_2_HELP_STR "MAC-IP (Type-2) route\n" +#define EVPN_TYPE_3_HELP_STR "Multicast (Type-3) route\n" +#define EVPN_TYPE_4_HELP_STR "Ethernet Segment (Type-4) route\n" +#define EVPN_TYPE_5_HELP_STR "Prefix (Type-5) route\n" + /* Prototypes. */ extern void install_node(struct cmd_node *node); extern void install_default(enum node_type); diff --git a/nhrpd/README.nhrpd b/nhrpd/README.nhrpd index 569b3f4463..8bb5f69bea 100644 --- a/nhrpd/README.nhrpd +++ b/nhrpd/README.nhrpd @@ -126,7 +126,8 @@ Integration with strongSwan Contrary to opennhrp, Quagga/NHRP has tight integration with IKE daemon. Currently strongSwan is supported using the VICI protocol. strongSwan -is connected using UNIX socket (hardcoded now as /var/run/charon.vici). +is connected using UNIX socket (default /var/run/charon.vici use configure +argument --with-vici-socket= to change). Thus nhrpd needs to be run as user that can open that file. Currently, you will need patched strongSwan. The working tree is at: diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index fe681b4052..27b7bece48 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -1109,11 +1109,12 @@ void nhrp_config_init(void) access_list_init(); /* global commands */ - install_element(VIEW_NODE, &show_debugging_nhrp_cmd); install_element(VIEW_NODE, &show_ip_nhrp_cmd); install_element(VIEW_NODE, &show_dmvpn_cmd); install_element(ENABLE_NODE, &clear_nhrp_cmd); + install_element(ENABLE_NODE, &show_debugging_nhrp_cmd); + install_element(ENABLE_NODE, &debug_nhrp_cmd); install_element(ENABLE_NODE, &no_debug_nhrp_cmd); diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 2dc05a4aa7..86554f53dc 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -478,7 +478,7 @@ static int vici_reconnect(struct thread *t) if (vici->fd >= 0) return 0; - fd = sock_open_unix("/var/run/charon.vici"); + fd = sock_open_unix(VICI_SOCKET); if (fd < 0) { debugf(NHRP_DEBUG_VICI, "%s: failure connecting VICI socket: %s", __func__, diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 71ca5afcd2..10a92414b9 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1006,9 +1006,9 @@ static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id) /* When an area is unstubified, flood all the external LSAs in the area */ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; - for (ALL_LSDB(oa->ospf6->lsdb, lsa)) { + for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) { if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) { zlog_debug("%s: Flooding AS-External LSA %s", __func__, lsa->name); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index fabcc426ea..72e40676a0 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -31,10 +31,10 @@ #include "ospf6_lsa.h" #include "ospf6_lsdb.h" +#include "ospf6_top.h" #include "ospf6_network.h" #include "ospf6_message.h" #include "ospf6_route.h" -#include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" @@ -906,7 +906,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) uint8_t default_iftype; struct timeval res, now; char duration[32]; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; default_iftype = ospf6_default_iftype(ifp); @@ -977,7 +977,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n", oi->lsupdate_list->count, duration, (oi->thread_send_lsupdate ? "on" : "off")); - for (ALL_LSDB(oi->lsupdate_list, lsa)) + for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); timerclear(&res); @@ -987,7 +987,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp) vty_out(vty, " %d Pending LSAs for LSAck in Time %s [thread %s]\n", oi->lsack_list->count, duration, (oi->thread_send_lsack ? "on" : "off")); - for (ALL_LSDB(oi->lsack_list, lsa)) + for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); ospf6_bfd_show_info(vty, oi->bfd_info, 1); return 0; diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 9e7479c797..058284f5e9 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -601,10 +601,10 @@ struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *lsa) } /* increment reference counter of struct ospf6_lsa */ -void ospf6_lsa_lock(struct ospf6_lsa *lsa) +struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa) { lsa->lock++; - return; + return lsa; } /* decrement reference counter of struct ospf6_lsa */ diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index a85d7b0603..cd873e2f00 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -226,8 +226,8 @@ ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header); extern void ospf6_lsa_delete(struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *); -extern void ospf6_lsa_lock(struct ospf6_lsa *); -extern struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *); +extern struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa); +extern struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa); extern int ospf6_lsa_expire(struct thread *); extern int ospf6_lsa_refresh(struct thread *); diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index b551dbdfa6..db6f9a7801 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -298,12 +298,12 @@ struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend, void ospf6_lsdb_remove_all(struct ospf6_lsdb *lsdb) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; if (lsdb == NULL) return; - for (ALL_LSDB(lsdb, lsa)) + for (ALL_LSDB(lsdb, lsa, lsanext)) ospf6_lsdb_remove(lsa, lsdb); } @@ -319,9 +319,9 @@ void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa) int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb) { int reschedule = 0; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; - for (ALL_LSDB(lsdb, lsa)) { + for (ALL_LSDB(lsdb, lsa, lsanext)) { if (!OSPF6_LSA_IS_MAXAGE(lsa)) continue; if (lsa->retrans_count != 0) { diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index 3b32e3ecf6..457e3dc4e4 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -66,11 +66,19 @@ extern struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend, lsa; \ lsa = ospf6_lsdb_next(iterend, lsa) -#define ALL_LSDB(lsdb, lsa) \ +/* + * Since we are locking the lsa in ospf6_lsdb_head + * and then unlocking it in lspf6_lsa_lock, when + * we cache the next pointer we need to increment + * the lock for the lsa so we don't accidently free + * it really early. + */ +#define ALL_LSDB(lsdb, lsa, lsanext) \ const struct route_node *iterend = \ ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); \ - lsa; \ - lsa = ospf6_lsdb_next(iterend, lsa) + (lsa) != NULL &&ospf6_lsa_lock(lsa) \ + && ((lsanext) = ospf6_lsdb_next(iterend, (lsa)), 1); \ + ospf6_lsa_unlock(lsa), (lsa) = (lsanext) extern void ospf6_lsdb_remove_all(struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index eb8c414d9b..07089d8774 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -31,10 +31,10 @@ #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" +#include "ospf6_top.h" #include "ospf6_network.h" #include "ospf6_message.h" -#include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_neighbor.h" #include "ospf6_interface.h" @@ -1792,7 +1792,7 @@ int ospf6_dbdesc_send(struct thread *thread) struct ospf6_header *oh; struct ospf6_dbdesc *dbdesc; uint8_t *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; struct in6_addr *dst; on = (struct ospf6_neighbor *)THREAD_ARG(thread); @@ -1833,7 +1833,7 @@ int ospf6_dbdesc_send(struct thread *thread) /* if this is not initial one, set LSA headers in dbdesc */ p = (uint8_t *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc)); if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)) { - for (ALL_LSDB(on->dbdesc_list, lsa)) { + for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) { ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay); @@ -1867,7 +1867,7 @@ int ospf6_dbdesc_send(struct thread *thread) int ospf6_dbdesc_send_newone(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; unsigned int size = 0; on = (struct ospf6_neighbor *)THREAD_ARG(thread); @@ -1877,7 +1877,7 @@ int ospf6_dbdesc_send_newone(struct thread *thread) structure) so that ospf6_send_dbdesc () can send those LSAs */ size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc); - for (ALL_LSDB(on->summary_list, lsa)) { + for (ALL_LSDB(on->summary_list, lsa, lsanext)) { if (size + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock(lsa); @@ -1908,7 +1908,7 @@ int ospf6_lsreq_send(struct thread *thread) struct ospf6_header *oh; struct ospf6_lsreq_entry *e; uint8_t *p; - struct ospf6_lsa *lsa, *last_req; + struct ospf6_lsa *lsa, *lsanext, *last_req; on = (struct ospf6_neighbor *)THREAD_ARG(thread); on->thread_send_lsreq = (struct thread *)NULL; @@ -1935,7 +1935,7 @@ int ospf6_lsreq_send(struct thread *thread) /* set Request entries in lsreq */ p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); - for (ALL_LSDB(on->request_list, lsa)) { + for (ALL_LSDB(on->request_list, lsa, lsanext)) { /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsreq_entry) > ospf6_packet_max(on->ospf6_if)) { @@ -2020,7 +2020,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) struct ospf6_lsupdate *lsupdate; uint8_t *p; int lsa_cnt; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); on->thread_send_lsupdate = (struct thread *)NULL; @@ -2045,7 +2045,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) /* lsupdate_list lists those LSA which doesn't need to be retransmitted. remove those from the list */ - for (ALL_LSDB(on->lsupdate_list, lsa)) { + for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) { /* MTU check */ if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header)) > ospf6_packet_max(on->ospf6_if)) { @@ -2097,7 +2097,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate)); lsa_cnt = 0; - for (ALL_LSDB(on->retrans_list, lsa)) { + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { /* MTU check */ if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header)) > ospf6_packet_max(on->ospf6_if)) { @@ -2202,7 +2202,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread) struct ospf6_lsupdate *lsupdate; uint8_t *p; int lsa_cnt; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; oi = (struct ospf6_interface *)THREAD_ARG(thread); oi->thread_send_lsupdate = (struct thread *)NULL; @@ -2228,7 +2228,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread) p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate)); lsa_cnt = 0; - for (ALL_LSDB(oi->lsupdate_list, lsa)) { + for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) { /* MTU check */ if ((p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE(lsa->header))) > ospf6_packet_max(oi)) { @@ -2288,7 +2288,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) struct ospf6_neighbor *on; struct ospf6_header *oh; uint8_t *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; int lsa_cnt = 0; on = (struct ospf6_neighbor *)THREAD_ARG(thread); @@ -2311,7 +2311,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); - for (ALL_LSDB(on->lsack_list, lsa)) { + for (ALL_LSDB(on->lsack_list, lsa, lsanext)) { /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { @@ -2366,7 +2366,7 @@ int ospf6_lsack_send_interface(struct thread *thread) struct ospf6_interface *oi; struct ospf6_header *oh; uint8_t *p; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; int lsa_cnt = 0; oi = (struct ospf6_interface *)THREAD_ARG(thread); @@ -2390,7 +2390,7 @@ int ospf6_lsack_send_interface(struct thread *thread) p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header)); - for (ALL_LSDB(oi->lsack_list, lsa)) { + for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) { /* MTU check */ if (p - sendbuf + sizeof(struct ospf6_lsa_header) > ospf6_packet_max(oi)) { diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 92a3c9e1ad..f8676e0c13 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -118,11 +118,11 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, void ospf6_neighbor_delete(struct ospf6_neighbor *on) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -293,7 +293,7 @@ int twoway_received(struct thread *thread) int negotiation_done(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -307,13 +307,13 @@ int negotiation_done(struct thread *thread) /* clear ls-list */ ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } /* Interface scoped LSAs */ - for (ALL_LSDB(on->ospf6_if->lsdb, lsa)) { + for (ALL_LSDB(on->ospf6_if->lsdb, lsa, lsanext)) { if (OSPF6_LSA_IS_MAXAGE(lsa)) { ospf6_increment_retrans_count(lsa); ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); @@ -322,7 +322,7 @@ int negotiation_done(struct thread *thread) } /* Area scoped LSAs */ - for (ALL_LSDB(on->ospf6_if->area->lsdb, lsa)) { + for (ALL_LSDB(on->ospf6_if->area->lsdb, lsa, lsanext)) { if (OSPF6_LSA_IS_MAXAGE(lsa)) { ospf6_increment_retrans_count(lsa); ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); @@ -331,7 +331,7 @@ int negotiation_done(struct thread *thread) } /* AS scoped LSAs */ - for (ALL_LSDB(on->ospf6_if->area->ospf6->lsdb, lsa)) { + for (ALL_LSDB(on->ospf6_if->area->ospf6->lsdb, lsa, lsanext)) { if (OSPF6_LSA_IS_MAXAGE(lsa)) { ospf6_increment_retrans_count(lsa); ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list); @@ -427,7 +427,7 @@ int loading_done(struct thread *thread) int adj_ok(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -452,7 +452,7 @@ int adj_ok(struct thread *thread) OSPF6_NEIGHBOR_EVENT_ADJ_OK); ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -464,7 +464,7 @@ int adj_ok(struct thread *thread) int seqnumber_mismatch(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -483,7 +483,7 @@ int seqnumber_mismatch(struct thread *thread) ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -501,7 +501,7 @@ int seqnumber_mismatch(struct thread *thread) int bad_lsreq(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -520,7 +520,7 @@ int bad_lsreq(struct thread *thread) ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -538,7 +538,7 @@ int bad_lsreq(struct thread *thread) int oneway_received(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -555,7 +555,7 @@ int oneway_received(struct thread *thread) ospf6_lsdb_remove_all(on->summary_list); ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa)) { + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { ospf6_decrement_retrans_count(lsa); ospf6_lsdb_remove(lsa, on->retrans_list); } @@ -685,7 +685,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, char drouter[16], bdrouter[16]; char linklocal_addr[64], duration[32]; struct timeval now, res; - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; inet_ntop(AF_INET6, &on->linklocal_addr, linklocal_addr, sizeof(linklocal_addr)); @@ -715,15 +715,15 @@ static void ospf6_neighbor_show_detail(struct vty *vty, (unsigned long)ntohl(on->dbdesc_seqnum)); vty_out(vty, " Summary-List: %d LSAs\n", on->summary_list->count); - for (ALL_LSDB(on->summary_list, lsa)) + for (ALL_LSDB(on->summary_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); vty_out(vty, " Request-List: %d LSAs\n", on->request_list->count); - for (ALL_LSDB(on->request_list, lsa)) + for (ALL_LSDB(on->request_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); vty_out(vty, " Retrans-List: %d LSAs\n", on->retrans_list->count); - for (ALL_LSDB(on->retrans_list, lsa)) + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); timerclear(&res); @@ -733,7 +733,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, vty_out(vty, " %d Pending LSAs for DbDesc in Time %s [thread %s]\n", on->dbdesc_list->count, duration, (on->thread_send_dbdesc ? "on" : "off")); - for (ALL_LSDB(on->dbdesc_list, lsa)) + for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); timerclear(&res); @@ -743,7 +743,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, vty_out(vty, " %d Pending LSAs for LSReq in Time %s [thread %s]\n", on->request_list->count, duration, (on->thread_send_lsreq ? "on" : "off")); - for (ALL_LSDB(on->request_list, lsa)) + for (ALL_LSDB(on->request_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); timerclear(&res); @@ -754,7 +754,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n", on->lsupdate_list->count, duration, (on->thread_send_lsupdate ? "on" : "off")); - for (ALL_LSDB(on->lsupdate_list, lsa)) + for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); timerclear(&res); @@ -764,7 +764,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, vty_out(vty, " %d Pending LSAs for LSAck in Time %s [thread %s]\n", on->lsack_list->count, duration, (on->thread_send_lsack ? "on" : "off")); - for (ALL_LSDB(on->lsack_list, lsa)) + for (ALL_LSDB(on->lsack_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); ospf6_bfd_show_info(vty, on->bfd_info, 0); diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index abbb180d45..6c83881bf4 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -30,9 +30,9 @@ #include "libospf.h" #include "ospf6_proto.h" +#include "ospf6_top.h" #include "ospf6_network.h" #include "ospf6d.h" -#include "ospf6_top.h" struct in6_addr allspfrouters6; struct in6_addr alldrouters6; diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index eeef0514f3..d11a611c49 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -21,7 +21,6 @@ #ifndef OSPF6_NETWORK_H #define OSPF6_NETWORK_H -struct ospf6 *ospf6; extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 57cc055296..6e24be6a1e 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -637,7 +637,7 @@ static uint8_t *ospfv3GeneralGroup(struct variable *v, oid *name, { uint16_t sum; uint32_t count; - struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa *lsa = NULL, *lsanext; /* Check whether the instance identifier is valid */ if (smux_header_generic(v, name, length, exact, var_len, write_method) @@ -679,7 +679,7 @@ static uint8_t *ospfv3GeneralGroup(struct variable *v, oid *name, case OSPFv3ASSCOPELSACHECKSUMSUM: if (ospf6) { sum = 0; - for (ALL_LSDB(ospf6->lsdb, lsa)) + for (ALL_LSDB(ospf6->lsdb, lsa, lsanext)) sum += ntohs(lsa->header->checksum); return SNMP_INTEGER(sum); } @@ -733,7 +733,7 @@ static uint8_t *ospfv3AreaEntry(struct variable *v, oid *name, size_t *length, WriteMethod **write_method) { struct ospf6_area *oa, *area = NULL; - struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa *lsa = NULL, *lsanext; uint32_t area_id = 0; uint32_t count; uint16_t sum; @@ -808,7 +808,7 @@ static uint8_t *ospfv3AreaEntry(struct variable *v, oid *name, size_t *length, return SNMP_INTEGER(area->lsdb->count); case OSPFv3AREASCOPELSACKSUMSUM: sum = 0; - for (ALL_LSDB(area->lsdb, lsa)) + for (ALL_LSDB(area->lsdb, lsa, lsanext)) sum += ntohs(lsa->header->checksum); return SNMP_INTEGER(sum); case OSPFv3AREASUMMARY: @@ -1044,7 +1044,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, ifindex_t ifindex = 0; unsigned int instid = 0; struct ospf6_interface *oi = NULL; - struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa *lsa = NULL, *lsanext; struct interface *iif; struct listnode *i; struct list *ifslist; @@ -1171,7 +1171,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, return SNMP_INTEGER(oi->lsdb->count); case OSPFv3IFLINKLSACKSUMSUM: sum = 0; - for (ALL_LSDB(oi->lsdb, lsa)) + for (ALL_LSDB(oi->lsdb, lsa, lsanext)) sum += ntohs(lsa->header->checksum); return SNMP_INTEGER(sum); case OSPFv3IFDEMANDNBRPROBE: diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index e5eb8d74eb..bb6a050976 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -1082,9 +1082,9 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, void ospf6_remove_temp_router_lsa(struct ospf6_area *area) { - struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa *lsa = NULL, *lsanext; - for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa)) { + for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa, lsanext)) { if (IS_OSPF6_DEBUG_SPF(PROCESS)) zlog_debug( "%s Remove LSA %s lsa->lock %u lsdb count %u", diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index e904482391..151ed2bf29 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -27,6 +27,7 @@ #include "plist.h" #include "ospf6_proto.h" +#include "ospf6_top.h" #include "ospf6_network.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" @@ -34,7 +35,6 @@ #include "ospf6_route.h" #include "ospf6_zebra.h" #include "ospf6_spf.h" -#include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" @@ -1236,7 +1236,7 @@ void ospf6_init(void) install_element_ospf6_clear_interface(); - install_element(VIEW_NODE, &show_debugging_ospf6_cmd); + install_element(ENABLE_NODE, &show_debugging_ospf6_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd); diff --git a/ospfclient/ospf_apiclient.c b/ospfclient/ospf_apiclient.c index da390e3c70..fb8ad3e60a 100644 --- a/ospfclient/ospf_apiclient.c +++ b/ospfclient/ospf_apiclient.c @@ -49,6 +49,7 @@ #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_api.h" +#include "ospfd/ospf_errors.h" #include "ospf_apiclient.h" @@ -564,12 +565,19 @@ static void ospf_apiclient_handle_lsa_update(struct ospf_apiclient *oclient, { struct msg_lsa_change_notify *cn; struct lsa_header *lsa; - int lsalen; + uint16_t lsalen; cn = (struct msg_lsa_change_notify *)STREAM_DATA(msg->s); /* Extract LSA from message */ lsalen = ntohs(cn->data.length); + if (lsalen > OSPF_MAX_LSA_SIZE) { + flog_warn( + EC_OSPF_LARGE_LSA, + "%s: message received size: %d is greater than a LSA size: %d", + __func__, lsalen, OSPF_MAX_LSA_SIZE); + return; + } lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen); memcpy(lsa, &(cn->data), lsalen); @@ -589,12 +597,19 @@ static void ospf_apiclient_handle_lsa_delete(struct ospf_apiclient *oclient, { struct msg_lsa_change_notify *cn; struct lsa_header *lsa; - int lsalen; + uint16_t lsalen; cn = (struct msg_lsa_change_notify *)STREAM_DATA(msg->s); /* Extract LSA from message */ lsalen = ntohs(cn->data.length); + if (lsalen > OSPF_MAX_LSA_SIZE) { + flog_warn( + EC_OSPF_LARGE_LSA, + "%s: message received size: %d is greater than a LSA size: %d", + __func__, lsalen, OSPF_MAX_LSA_SIZE); + return; + } lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen); memcpy(lsa, &(cn->data), lsalen); diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index e8798e023e..7fd1b5c64e 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -41,6 +41,9 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_network.h" +#ifndef VTYSH_EXTRACT_PL +#include "ospfd/ospf_dump_clippy.c" +#endif /* Configuration debug option variables. */ unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; @@ -55,6 +58,7 @@ unsigned long conf_debug_ospf_ext = 0; unsigned long conf_debug_ospf_sr = 0; unsigned long conf_debug_ospf_defaultinfo = 0; unsigned long conf_debug_ospf_ldp_sync = 0; +unsigned long conf_debug_ospf_gr = 0; /* Enable debug option variables -- valid only session. */ unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; @@ -69,6 +73,7 @@ unsigned long term_debug_ospf_ext = 0; unsigned long term_debug_ospf_sr = 0; unsigned long term_debug_ospf_defaultinfo; unsigned long term_debug_ospf_ldp_sync; +unsigned long term_debug_ospf_gr = 0; const char *ospf_redist_string(unsigned int route_type) { @@ -1501,6 +1506,26 @@ DEFUN(no_debug_ospf_ldp_sync, if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF(ldp_sync, LDP_SYNC); TERM_DEBUG_OFF(ldp_sync, LDP_SYNC); + + return CMD_SUCCESS; +} + +DEFPY (debug_ospf_gr, + debug_ospf_gr_cmd, + "[no$no] debug ospf graceful-restart helper", + NO_STR + DEBUG_STR OSPF_STR + "Gracefull restart\n" + "Helper Information\n") +{ + if (vty->node == CONFIG_NODE) + CONF_DEBUG_ON(gr, GR_HELPER); + + if (!no) + TERM_DEBUG_ON(gr, GR_HELPER); + else + TERM_DEBUG_OFF(gr, GR_HELPER); + return CMD_SUCCESS; } @@ -1667,6 +1692,10 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf) if (IS_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC) vty_out(vty, " OSPF ldp-sync debugging is on\n"); + /* Show debug status for GR helper. */ + if (IS_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER) + vty_out(vty, " OSPF Graceful Restart Helper debugging is on\n"); + vty_out(vty, "\n"); return CMD_SUCCESS; @@ -1853,6 +1882,13 @@ static int config_write_debug(struct vty *vty) vty_out(vty, "debug ospf%s ldp-sync\n", str); write = 1; } + + /* debug ospf gr helper */ + if (IS_CONF_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER) { + vty_out(vty, "debug ospf%s graceful-restart helper\n", str); + write = 1; + } + return write; } @@ -1882,6 +1918,7 @@ void ospf_debug_init(void) install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd); install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd); install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd); + install_element(ENABLE_NODE, &debug_ospf_gr_cmd); install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd); install_element(ENABLE_NODE, &debug_ospf_packet_cmd); @@ -1922,6 +1959,7 @@ void ospf_debug_init(void) install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd); install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd); install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd); + install_element(CONFIG_NODE, &debug_ospf_gr_cmd); install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd); install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd); diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index faae27e2cf..a2df4ff22c 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -62,6 +62,9 @@ #define OSPF_DEBUG_DEFAULTINFO 0x20 #define OSPF_DEBUG_LDP_SYNC 0x40 +#define OSPF_DEBUG_GR_HELPER 0x01 +#define OSPF_DEBUG_GR 0x03 + /* Macro for setting debug option. */ #define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) #define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b) @@ -109,6 +112,7 @@ #define IS_DEBUG_OSPF_DEFAULT_INFO IS_DEBUG_OSPF(defaultinfo, DEFAULTINFO) #define IS_DEBUG_OSPF_LDP_SYNC IS_DEBUG_OSPF(ldp_sync, LDP_SYNC) +#define IS_DEBUG_OSPF_GR_HELPER IS_DEBUG_OSPF(gr, GR_HELPER) #define IS_CONF_DEBUG_OSPF_PACKET(a, b) \ (conf_debug_ospf_packet[a] & OSPF_DEBUG_##b) @@ -130,6 +134,7 @@ extern unsigned long term_debug_ospf_ext; extern unsigned long term_debug_ospf_sr; extern unsigned long term_debug_ospf_defaultinfo; extern unsigned long term_debug_ospf_ldp_sync; +extern unsigned long term_debug_ospf_gr; /* Message Strings. */ extern char *ospf_lsa_type_str[]; diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index e96b31e3f4..7d461d4587 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -337,6 +337,45 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr, SET_FLAG(new->flags, OSPF_LSA_RECEIVED); (void)ospf_lsa_is_self_originated(ospf, new); /* Let it set the flag */ + /* Received Grace LSA */ + if (IS_GRACE_LSA(new)) { + + if (IS_LSA_MAXAGE(new)) { + + /* Handling Max age grace LSA.*/ + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Received a maxage GRACE-LSA from router %s", + __PRETTY_FUNCTION__, + inet_ntoa(new->data->adv_router)); + + if (current) { + ospf_process_maxage_grace_lsa(ospf, new, nbr); + } else { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Grace LSA doesn't exist in lsdb, so discarding grace lsa", + __PRETTY_FUNCTION__); + return -1; + } + } else { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Received a GRACE-LSA from router %s", + __PRETTY_FUNCTION__, + inet_ntoa(new->data->adv_router)); + + if (ospf_process_grace_lsa(ospf, new, nbr) + == OSPF_GR_NOT_HELPER) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Not moving to HELPER role, So discarding grace LSA", + __PRETTY_FUNCTION__); + return -1; + } + } + } + /* Install the new LSA in the link state database (replacing the current database copy). This may cause the routing table calculation to be scheduled. In addition, diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c new file mode 100644 index 0000000000..a7b20d1f07 --- /dev/null +++ b/ospfd/ospf_gr_helper.c @@ -0,0 +1,964 @@ +/* + * OSPF Graceful Restart helper functions. + * + * Copyright (C) 2020-21 Vmware, Inc. + * Rajesh Kumar Girada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "linklist.h" +#include "prefix.h" +#include "if.h" +#include "table.h" +#include "vty.h" +#include "filter.h" +#include "log.h" +#include "jhash.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_spf.h" +#include "ospfd/ospf_flood.h" +#include "ospfd/ospf_route.h" +#include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_dump.h" +#include "ospfd/ospf_errors.h" +#include "ospfd/ospf_nsm.h" +#include "ospfd/ospf_ism.h" +#include "ospfd/ospf_gr_helper.h" + +const char *ospf_exit_reason_desc[] = { + "Unknown reason", + "Helper inprogress", + "Topology Change", + "Grace timer expairy", + "Successful graceful restart", +}; + +const char *ospf_restart_reason_desc[] = { + "Unknown restart", + "Software restart", + "Software reload/upgrade", + "Switch to redundant control processor", +}; + +const char *ospf_rejected_reason_desc[] = { + "Unknown reason", + "Helper support disabled", + "Neighbour is not in FULL state", + "Supports only planned restart but received for unplanned", + "Topo change due to change in lsa rxmt list", + "LSA age is more than Grace interval", +}; + +static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa); +static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr); + +static unsigned int ospf_enable_rtr_hash_key(const void *data) +{ + const struct advRtr *rtr = data; + + return jhash_1word(rtr->advRtrAddr.s_addr, 0); +} + +static bool ospf_enable_rtr_hash_cmp(const void *d1, const void *d2) +{ + const struct advRtr *rtr1 = (struct advRtr *)d1; + const struct advRtr *rtr2 = (struct advRtr *)d2; + + return (rtr1->advRtrAddr.s_addr == rtr2->advRtrAddr.s_addr); +} + +static void *ospf_enable_rtr_hash_alloc(void *p) +{ + struct advRtr *rid; + + rid = XCALLOC(MTYPE_OSPF_GR_HELPER, sizeof(struct advRtr)); + rid->advRtrAddr.s_addr = ((struct in_addr *)p)->s_addr; + + return rid; +} + +static void ospf_disable_rtr_hash_free(void *rtr) +{ + XFREE(MTYPE_OSPF_GR_HELPER, rtr); +} + +static void ospf_enable_rtr_hash_destroy(struct ospf *ospf) +{ + if (ospf->enable_rtr_list == NULL) + return; + + hash_clean(ospf->enable_rtr_list, ospf_disable_rtr_hash_free); + hash_free(ospf->enable_rtr_list); + ospf->enable_rtr_list = NULL; +} + +/* + * Initialize GR helper config data structures. + * + * OSPF + * OSPF pointer + * + * Returns: + * Nothing + */ +void ospf_gr_helper_init(struct ospf *ospf) +{ + int rc; + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, GR Helper init.", __PRETTY_FUNCTION__); + + ospf->is_helper_supported = OSPF_GR_FALSE; + ospf->strict_lsa_check = OSPF_GR_TRUE; + ospf->only_planned_restart = OSPF_GR_FALSE; + ospf->supported_grace_time = OSPF_MAX_GRACE_INTERVAL; + ospf->last_exit_reason = OSPF_GR_HELPER_EXIT_NONE; + ospf->active_restarter_cnt = 0; + + ospf->enable_rtr_list = + hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp, + "OSPF enable router hash"); + + rc = ospf_register_opaque_functab( + OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, show_ospf_grace_lsa_info, NULL, NULL, + NULL, NULL); + if (rc != 0) { + flog_warn(EC_OSPF_OPAQUE_REGISTRATION, + "%s: Failed to register Grace LSA functions", + __func__); + } +} + +/* + * De-Initialize GR helper config data structures. + * + * OSPF + * OSPF pointer + * + * Returns: + * Nothing + */ +void ospf_gr_helper_stop(struct ospf *ospf) +{ + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, GR helper deinit.", __PRETTY_FUNCTION__); + + ospf_enable_rtr_hash_destroy(ospf); + + ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA); +} + +/* + * Extracting tlv info from GRACE LSA. + * + * lsa + * ospf grace lsa + * + * Returns: + * interval : grace interval. + * addr : RESTARTER address. + * reason : Restarting reason. + */ +static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa, + uint32_t *interval, + struct in_addr *addr, uint8_t *reason) +{ + struct lsa_header *lsah = NULL; + struct tlv_header *tlvh = NULL; + struct grace_tlv_graceperiod *grace_period; + struct grace_tlv_restart_reason *gr_reason; + struct grace_tlv_restart_addr *restart_addr; + uint16_t length = 0; + int sum = 0; + + lsah = (struct lsa_header *)lsa->data; + + length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + + for (tlvh = TLV_HDR_TOP(lsah); sum < length; + tlvh = TLV_HDR_NEXT(tlvh)) { + switch (ntohs(tlvh->type)) { + case GRACE_PERIOD_TYPE: + grace_period = (struct grace_tlv_graceperiod *)tlvh; + *interval = ntohl(grace_period->interval); + sum += TLV_SIZE(tlvh); + + /* Check if grace interval is valid */ + if (*interval > OSPF_MAX_GRACE_INTERVAL + || *interval < OSPF_MIN_GRACE_INTERVAL) + return OSPF_GR_FAILURE; + break; + case RESTART_REASON_TYPE: + gr_reason = (struct grace_tlv_restart_reason *)tlvh; + *reason = gr_reason->reason; + sum += TLV_SIZE(tlvh); + + if (*reason >= OSPF_GR_INVALID_REASON_CODE) + return OSPF_GR_FAILURE; + break; + case RESTARTER_IP_ADDR_TYPE: + restart_addr = (struct grace_tlv_restart_addr *)tlvh; + addr->s_addr = restart_addr->addr.s_addr; + sum += TLV_SIZE(tlvh); + break; + default: + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Malformed packet.Invalid TLV type:%d", + __PRETTY_FUNCTION__, ntohs(tlvh->type)); + return OSPF_GR_FAILURE; + } + } + + return OSPF_GR_SUCCESS; +} + +/* + * Grace timer expiry handler. + * HELPER aborts its role at grace timer expiry. + * + * thread + * thread pointer + * + * Returns: + * Nothing + */ +static int ospf_handle_grace_timer_expiry(struct thread *thread) +{ + struct ospf_neighbor *nbr = THREAD_ARG(thread); + + nbr->gr_helper_info.t_grace_timer = NULL; + + ospf_gr_helper_exit(nbr, OSPF_GR_HELPER_GRACE_TIMEOUT); + return OSPF_GR_SUCCESS; +} + +/* + * Process Grace LSA.If it is eligible move to HELPER role. + * Ref rfc3623 section 3.1 + * + * ospf + * OSPF pointer. + * + * lsa + * Grace LSA received from RESTARTER. + * + * nbr + * ospf neighbour which requets the router to act as + * HELPER. + * + * Returns: + * status. + * If supported as HELPER : OSPF_GR_HELPER_INPROGRESS + * If Not supported as HELPER : OSPF_GR_HELPER_NONE + */ +int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa, + struct ospf_neighbor *nbr) +{ + struct in_addr restart_addr = {0}; + uint8_t restart_reason = 0; + uint32_t grace_interval = 0; + uint32_t actual_grace_interval = 0; + struct advRtr lookup; + struct ospf_neighbor *restarter = NULL; + struct ospf_interface *oi = nbr->oi; + int ret; + + + /* Extract the grace lsa packet fields */ + ret = ospf_extract_grace_lsa_fields(lsa, &grace_interval, &restart_addr, + &restart_reason); + if (ret != OSPF_GR_SUCCESS) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, Wrong Grace LSA packet.", + __PRETTY_FUNCTION__); + return OSPF_GR_NOT_HELPER; + } + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Grace LSA received from %s, grace interval:%u, restartreason :%s", + __PRETTY_FUNCTION__, inet_ntoa(restart_addr), + grace_interval, ospf_restart_reason_desc[restart_reason]); + + /* Incase of broadcast links, if RESTARTER is DR_OTHER, + * grace LSA might be received from DR, so need to get + * actual neighbour info , here RESTARTER. + */ + if (oi->type != OSPF_IFTYPE_POINTOPOINT) { + restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restart_addr); + + if (!restarter) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Restarter is not a nbr(%s) for this router.", + __PRETTY_FUNCTION__, + inet_ntoa(restart_addr)); + return OSPF_GR_NOT_HELPER; + } + } else + restarter = nbr; + + /* Verify Helper enabled globally */ + if (!ospf->is_helper_supported) { + /* Verify that Helper support is enabled for the + * current neighbour router-id. + */ + lookup.advRtrAddr.s_addr = restarter->router_id.s_addr; + + if (!hash_lookup(ospf->enable_rtr_list, &lookup)) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, HELPER support is disabled, So not a HELPER", + __PRETTY_FUNCTION__); + restarter->gr_helper_info.rejected_reason = + OSPF_HELPER_SUPPORT_DISABLED; + return OSPF_GR_NOT_HELPER; + } + } + + + /* Check neighbour is in FULL state and + * became a adjacency. + */ + if (!IS_NBR_STATE_FULL(restarter)) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, This Neighbour %s is not in FULL state.", + __PRETTY_FUNCTION__, inet_ntoa(restarter->src)); + restarter->gr_helper_info.rejected_reason = + OSPF_HELPER_NOT_A_VALID_NEIGHBOUR; + return OSPF_GR_NOT_HELPER; + } + + /* Based on the restart reason from grace lsa + * check the current router is supporting or not + */ + if (ospf->only_planned_restart + && !OSPF_GR_IS_PLANNED_RESTART(restart_reason)) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Router supports only planned restarts but received the GRACE LSA for an unplanned restart.", + __PRETTY_FUNCTION__); + restarter->gr_helper_info.rejected_reason = + OSPF_HELPER_PLANNED_ONLY_RESTART; + return OSPF_GR_NOT_HELPER; + } + + /* Check the retranmission list of this + * neighbour, check any change in lsas. + */ + if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter) + && ospf_check_change_in_rxmt_list(restarter)) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Changed LSA in Rxmt list. So not Helper.", + __PRETTY_FUNCTION__); + restarter->gr_helper_info.rejected_reason = + OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST; + return OSPF_GR_NOT_HELPER; + } + + /*LSA age must be less than the grace period */ + if (ntohs(lsa->data->ls_age) >= grace_interval) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Grace LSA age(%d) is more than the graceinterval(%d)", + __PRETTY_FUNCTION__, lsa->data->ls_age, + grace_interval); + restarter->gr_helper_info.rejected_reason = + OSPF_HELPER_LSA_AGE_MORE; + return OSPF_GR_NOT_HELPER; + } + + /* check supported grace period configured + * if configured, use this to start the grace + * timer otherwise use the interval received + * in grace LSA packet. + */ + actual_grace_interval = grace_interval; + if (grace_interval > ospf->supported_grace_time) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Received grace period %d is larger than supported grace %d", + __PRETTY_FUNCTION__, grace_interval, + ospf->supported_grace_time); + actual_grace_interval = ospf->supported_grace_time; + } + + if (OSPF_GR_IS_ACTIVE_HELPER(restarter)) { + if (restarter->gr_helper_info.t_grace_timer) + THREAD_OFF(restarter->gr_helper_info.t_grace_timer); + + if (ospf->active_restarter_cnt > 0) + ospf->active_restarter_cnt--; + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer", + __PRETTY_FUNCTION__); + } else { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, This Router becomes a HELPER for the neighbour %s", + __PRETTY_FUNCTION__, inet_ntoa(restarter->src)); + } + + /* Became a Helper to the RESTART neighbour. + * Change the helper status. + */ + restarter->gr_helper_info.gr_helper_status = OSPF_GR_ACTIVE_HELPER; + restarter->gr_helper_info.recvd_grace_period = grace_interval; + restarter->gr_helper_info.actual_grace_period = actual_grace_interval; + restarter->gr_helper_info.gr_restart_reason = restart_reason; + restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE; + + /* Incremnet the active restarer count */ + ospf->active_restarter_cnt++; + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, Grace timer started.interval:%d", + __PRETTY_FUNCTION__, actual_grace_interval); + + /* Start the grace timer */ + thread_add_timer(master, ospf_handle_grace_timer_expiry, restarter, + actual_grace_interval, + &restarter->gr_helper_info.t_grace_timer); + + return OSPF_GR_ACTIVE_HELPER; +} + +/* + * API to check any change in the neighbor's + * retransmission list. + * + * nbr + * ospf neighbor + * + * Returns: + * TRUE - if any change in the lsa. + * FALSE - no change in the lsas. + */ +static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr) +{ + struct route_node *rn; + struct ospf_lsa *lsa; + struct route_table *tbl; + + tbl = nbr->ls_rxmt.type[OSPF_ROUTER_LSA].db; + LSDB_LOOP (tbl, rn, lsa) + if (lsa->to_be_acknowledged) + return OSPF_GR_TRUE; + tbl = nbr->ls_rxmt.type[OSPF_NETWORK_LSA].db; + LSDB_LOOP (tbl, rn, lsa) + if (lsa->to_be_acknowledged) + return OSPF_GR_TRUE; + + tbl = nbr->ls_rxmt.type[OSPF_SUMMARY_LSA].db; + LSDB_LOOP (tbl, rn, lsa) + if (lsa->to_be_acknowledged) + return OSPF_GR_TRUE; + + tbl = nbr->ls_rxmt.type[OSPF_ASBR_SUMMARY_LSA].db; + LSDB_LOOP (tbl, rn, lsa) + if (lsa->to_be_acknowledged) + return OSPF_GR_TRUE; + + tbl = nbr->ls_rxmt.type[OSPF_AS_EXTERNAL_LSA].db; + LSDB_LOOP (tbl, rn, lsa) + if (lsa->to_be_acknowledged) + return OSPF_GR_TRUE; + + tbl = nbr->ls_rxmt.type[OSPF_AS_NSSA_LSA].db; + LSDB_LOOP (tbl, rn, lsa) + if (lsa->to_be_acknowledged) + return OSPF_GR_TRUE; + + return OSPF_GR_FALSE; +} + +/* + * Actions to be taken when topo change detected + * HELPER will exit upon topo change. + * + * ospf + * ospf pointer + * lsa + * topo change occured due to this lsa type (1 to 5 and 7) + * + * Returns: + * Nothing + */ +void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa) +{ + struct listnode *node; + struct ospf_interface *oi; + + if (!ospf->active_restarter_cnt) + return; + + /* Topo change not required to be hanlded if strict + * LSA check is disbaled for this router. + */ + if (!ospf->strict_lsa_check) + return; + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Topo change detected due to lsa LSID:%s type:%d", + __PRETTY_FUNCTION__, inet_ntoa(lsa->data->id), + lsa->data->type); + + lsa->to_be_acknowledged = OSPF_GR_TRUE; + + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + struct route_node *rn = NULL; + + if (ospf_interface_neighbor_count(oi) == 0) + continue; + + /* Ref rfc3623 section 3.2.3.b + * If change due to external LSA and if the area is + * stub, then it is not a topo change. Since Type-5 + * lsas will not be flooded in stub area. + */ + if ((oi->area->external_routing == OSPF_AREA_STUB) + && (lsa->data->type == OSPF_AS_EXTERNAL_LSA)) { + continue; + } + + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + struct ospf_neighbor *nbr = NULL; + + if (!rn->info) + continue; + + nbr = rn->info; + + if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) + ospf_gr_helper_exit(nbr, + OSPF_GR_HELPER_TOPO_CHG); + } + } +} + +/* + * Api to exit from HELPER role to take all actions + * required at exit. + * Ref rfc3623 section 3.2 + * + * ospf + * OSPF pointer. + * + * nbr + * OSPF neighbour for which it is acting as HELPER. + * + * reason + * The reason for exiting from HELPER. + * + * Returns: + * Nothing. + */ +void ospf_gr_helper_exit(struct ospf_neighbor *nbr, + enum ospf_helper_exit_reason reason) +{ + struct ospf_interface *oi = nbr->oi; + struct ospf *ospf = oi->ospf; + + if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) + return; + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, Exiting from HELPER support to %s, due to %s", + __PRETTY_FUNCTION__, inet_ntoa(nbr->src), + ospf_exit_reason_desc[reason]); + + /* Reset helper status*/ + nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER; + nbr->gr_helper_info.helper_exit_reason = reason; + nbr->gr_helper_info.actual_grace_period = 0; + nbr->gr_helper_info.recvd_grace_period = 0; + nbr->gr_helper_info.gr_restart_reason = 0; + ospf->last_exit_reason = reason; + + if (ospf->active_restarter_cnt <= 0) { + zlog_err( + "OSPF GR-Helper: active_restarter_cnt should be greater than zero here."); + return; + } + /* Decrement active Restarter count */ + ospf->active_restarter_cnt--; + + /* If the exit not triggered due to grace timer + * expairy , stop the grace timer. + */ + if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT) + THREAD_OFF(nbr->gr_helper_info.t_grace_timer); + + /* check exit triggered due to successful completion + * of graceful restart. + * If no, bringdown the neighbour. + */ + if (reason != OSPF_GR_HELPER_COMPLETED) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Failed GR exit, so bringing down the neighbour", + __PRETTY_FUNCTION__); + OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); + } + + /*Recalculate the DR for the network segment */ + ospf_dr_election(oi); + + /* Originate a router LSA */ + ospf_router_lsa_update_area(oi->area); + + /* Originate network lsa if it is an DR in the LAN */ + if (oi->state == ISM_DR) + ospf_network_lsa_update(oi); +} + +/* + * Process Maxage Grace LSA. + * It is a indication for successful completion of GR. + * If router acting as HELPER, It exits from helper role. + * + * ospf + * OSPF pointer. + * + * lsa + * Grace LSA received from RESTARTER. + * + * nbr + * ospf neighbour which requets the router to act as + * HELPER. + * + * Returns: + * Nothing. + */ +void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa, + struct ospf_neighbor *nbr) +{ + struct in_addr restartAddr = {0}; + uint8_t restartReason = 0; + uint32_t graceInterval = 0; + struct ospf_neighbor *restarter = NULL; + struct ospf_interface *oi = nbr->oi; + int ret; + + /* Extract the grace lsa packet fields */ + ret = ospf_extract_grace_lsa_fields(lsa, &graceInterval, &restartAddr, + &restartReason); + if (ret != OSPF_GR_SUCCESS) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, Wrong Grace LSA packet.", + __PRETTY_FUNCTION__); + return; + } + + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, GraceLSA received for neighbour %s.", + __PRETTY_FUNCTION__, inet_ntoa(restartAddr)); + + /* In case of broadcast links, if RESTARTER is DR_OTHER, + * grace LSA might be received from DR, so fetching the + * actual neighbour information using restarter address. + */ + if (oi->type != OSPF_IFTYPE_POINTOPOINT) { + restarter = ospf_nbr_lookup_by_addr(oi->nbrs, &restartAddr); + + if (!restarter) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Restarter is not a neighbour for this router.", + __PRETTY_FUNCTION__); + return; + } + } else { + restarter = nbr; + } + + ospf_gr_helper_exit(restarter, OSPF_GR_HELPER_COMPLETED); +} + +/* Configuration handlers */ +/* + * Disable/Enable HELPER support on router level. + * + * ospf + * OSPFpointer. + * + * status + * TRUE/FALSE + * + * Returns: + * Nothing. + */ +void ospf_gr_helper_support_set(struct ospf *ospf, bool support) +{ + struct ospf_interface *oi; + struct listnode *node; + struct advRtr lookup; + + if (ospf->is_helper_supported == support) + return; + + ospf->is_helper_supported = support; + + /* If helper support disabled, cease HELPER role for all + * supporting neighbors. + */ + if (support == OSPF_GR_FALSE) { + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + struct route_node *rn = NULL; + + if (ospf_interface_neighbor_count(oi) == 0) + continue; + + for (rn = route_top(oi->nbrs); rn; + rn = route_next(rn)) { + struct ospf_neighbor *nbr = NULL; + + if (!rn->info) + continue; + + nbr = rn->info; + + lookup.advRtrAddr.s_addr = + nbr->router_id.s_addr; + /* check if helper support enabled for the + * correspodning routerid.If enabled, dont + * dont exit from helper role. + */ + if (hash_lookup(ospf->enable_rtr_list, &lookup)) + continue; + + if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) + ospf_gr_helper_exit( + nbr, OSPF_GR_HELPER_TOPO_CHG); + } + } + } +} + +/* + * Enable/Disable HELPER support on a specified advertagement + * router. + * + * ospf + * OSPF pointer. + * + * advRtr + * HELPER support for given Advertisement Router. + * + * support + * True - Enable Helper Support. + * False - Disable Helper Support. + * + * Returns: + * Nothing. + */ + +void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf, + struct in_addr *advrtr, + bool support) +{ + struct advRtr temp; + struct advRtr *rtr; + struct ospf_interface *oi; + struct listnode *node; + + temp.advRtrAddr.s_addr = advrtr->s_addr; + + if (support == OSPF_GR_FALSE) { + /*Delete the routerid from the enable router hash table */ + rtr = hash_lookup(ospf->enable_rtr_list, &temp); + + if (rtr) { + hash_release(ospf->enable_rtr_list, rtr); + ospf_disable_rtr_hash_free(rtr); + } + + /* If helper support is enabled globally + * no action is required. + */ + if (ospf->is_helper_supported) + return; + + /* Cease the HELPER role fore neighbours from the + * specified advertisement router. + */ + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + struct route_node *rn = NULL; + + if (ospf_interface_neighbor_count(oi) == 0) + continue; + + for (rn = route_top(oi->nbrs); rn; + rn = route_next(rn)) { + struct ospf_neighbor *nbr = NULL; + + if (!rn->info) + continue; + + nbr = rn->info; + + if (nbr->router_id.s_addr != advrtr->s_addr) + continue; + + if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) + ospf_gr_helper_exit( + nbr, OSPF_GR_HELPER_TOPO_CHG); + } + } + + } else { + /* Add the routerid to the enable router hash table */ + hash_get(ospf->enable_rtr_list, &temp, + ospf_enable_rtr_hash_alloc); + } +} + +/* + * Api to enable/disable strict lsa check on the HELPER. + * + * ospf + * OSPF pointer. + * + * enabled + * True - disable the lsa check. + * False - enable the strict lsa check. + * + * Returns: + * Nothing. + */ +void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool enabled) +{ + if (ospf->strict_lsa_check == enabled) + return; + + ospf->strict_lsa_check = enabled; +} + +/* + * Api to set the supported grace interval in this router. + * + * ospf + * OSPF pointer. + * + * interval + * The supported grace interval.. + * + * Returns: + * Nothing. + */ +void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf, + uint32_t interval) +{ + ospf->supported_grace_time = interval; +} + +/* + * Api to set the supported restart reason. + * + * ospf + * OSPF pointer. + * + * planned_only + * True: support only planned restart. + * False: support for planned/unplanned restarts. + * + * Returns: + * Nothing. + */ +void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf, + bool planned_only) +{ + ospf->only_planned_restart = planned_only; +} + +/* + * Api to display the grace LSA information. + * + * vty + * vty pointer. + * lsa + * Grace LSA. + * json + * json object + * + * Returns: + * Nothing. + */ +static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa) +{ + struct lsa_header *lsah = NULL; + struct tlv_header *tlvh = NULL; + struct grace_tlv_graceperiod *gracePeriod; + struct grace_tlv_restart_reason *grReason; + struct grace_tlv_restart_addr *restartAddr; + uint16_t length = 0; + int sum = 0; + + lsah = (struct lsa_header *)lsa->data; + + length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + + vty_out(vty, " TLV info:\n"); + + for (tlvh = TLV_HDR_TOP(lsah); sum < length; + tlvh = TLV_HDR_NEXT(tlvh)) { + switch (ntohs(tlvh->type)) { + case GRACE_PERIOD_TYPE: + gracePeriod = (struct grace_tlv_graceperiod *)tlvh; + sum += TLV_SIZE(tlvh); + + vty_out(vty, " Grace period:%d\n", + ntohl(gracePeriod->interval)); + break; + case RESTART_REASON_TYPE: + grReason = (struct grace_tlv_restart_reason *)tlvh; + sum += TLV_SIZE(tlvh); + + vty_out(vty, " Restart reason:%s\n", + ospf_restart_reason_desc[grReason->reason]); + break; + case RESTARTER_IP_ADDR_TYPE: + restartAddr = (struct grace_tlv_restart_addr *)tlvh; + sum += TLV_SIZE(tlvh); + + vty_out(vty, " Restarter address:%s\n", + inet_ntoa(restartAddr->addr)); + break; + default: + break; + } + } +} diff --git a/ospfd/ospf_gr_helper.h b/ospfd/ospf_gr_helper.h new file mode 100644 index 0000000000..4e83028fe6 --- /dev/null +++ b/ospfd/ospf_gr_helper.h @@ -0,0 +1,179 @@ +/* + * OSPF Graceful Restart helper functions. + * + * Copyright (C) 2020-21 Vmware, Inc. + * Rajesh Kumar Girada + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_OSPF_GR_HELPER_H +#define _ZEBRA_OSPF_GR_HELPER_H + +#define OSPF_GR_NOT_HELPER 0 +#define OSPF_GR_ACTIVE_HELPER 1 + +#define OSPF_GR_HELPER_NO_LSACHECK 0 +#define OSPF_GR_HELPER_LSACHECK 1 + +#define OSPF_MAX_GRACE_INTERVAL 1800 +#define OSPF_MIN_GRACE_INTERVAL 1 + +enum ospf_helper_exit_reason { + OSPF_GR_HELPER_EXIT_NONE = 0, + OSPF_GR_HELPER_INPROGRESS, + OSPF_GR_HELPER_TOPO_CHG, + OSPF_GR_HELPER_GRACE_TIMEOUT, + OSPF_GR_HELPER_COMPLETED +}; + +enum ospf_gr_restart_reason { + OSPF_GR_UNKNOWN_RESTART = 0, + OSPF_GR_SW_RESTART = 1, + OSPF_GR_SW_UPGRADE = 2, + OSPF_GR_SWITCH_REDUNDANT_CARD = 3, + OSPF_GR_INVALID_REASON_CODE = 4 +}; + +enum ospf_gr_helper_rejected_reason { + OSPF_HELPER_REJECTED_NONE, + OSPF_HELPER_SUPPORT_DISABLED, + OSPF_HELPER_NOT_A_VALID_NEIGHBOUR, + OSPF_HELPER_PLANNED_ONLY_RESTART, + OSPF_HELPER_TOPO_CHANGE_RTXMT_LIST, + OSPF_HELPER_LSA_AGE_MORE +}; + +/* Ref RFC3623 appendex-A */ +/* Grace period TLV */ +#define GRACE_PERIOD_TYPE 1 +#define GRACE_PERIOD_LENGTH 4 + +struct grace_tlv_graceperiod { + struct tlv_header header; + uint32_t interval; +}; + +/* Restart reason TLV */ +#define RESTART_REASON_TYPE 2 +#define RESTART_REASON_LENGTH 1 + +struct grace_tlv_restart_reason { + struct tlv_header header; + uint8_t reason; + uint8_t reserved[3]; +}; + +/* Restarter ip address TLV */ +#define RESTARTER_IP_ADDR_TYPE 3 +#define RESTARTER_IP_ADDR_LEN 4 + +struct grace_tlv_restart_addr { + struct tlv_header header; + struct in_addr addr; +}; + +struct ospf_helper_info { + + /* Grace interval received from + * Restarting Router. + */ + uint32_t recvd_grace_period; + + /* Grace interval used for grace + * gracetimer. + */ + uint32_t actual_grace_period; + + /* Grace timer,This Router acts as + * helper until this timer until + * this timer expires*/ + struct thread *t_grace_timer; + + /* Helper status */ + uint32_t gr_helper_status; + + /* Helper exit reason*/ + enum ospf_helper_exit_reason helper_exit_reason; + + /* Planned/Unplanned restart*/ + enum ospf_gr_restart_reason gr_restart_reason; + + /* Helper rejected reason */ + enum ospf_gr_helper_rejected_reason rejected_reason; +}; + +struct advRtr { + struct in_addr advRtrAddr; +}; + +#define OSPF_HELPER_ENABLE_RTR_COUNT(ospf) (ospf->enable_rtr_list->count) + +/* Check for planned restart */ +#define OSPF_GR_IS_PLANNED_RESTART(reason) \ + ((reason == OSPF_GR_SW_RESTART) || (reason == OSPF_GR_SW_UPGRADE)) + +/* Check the router is HELPER for current neighbour */ +#define OSPF_GR_IS_ACTIVE_HELPER(N) \ + ((N)->gr_helper_info.gr_helper_status == OSPF_GR_ACTIVE_HELPER) + +/* Check the LSA is GRACE LSA */ +#define IS_GRACE_LSA(lsa) \ + ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) \ + && (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)) \ + == OPAQUE_TYPE_GRACE_LSA)) + +/* Check neighbour is in FULL state */ +#define IS_NBR_STATE_FULL(nbr) (nsm_should_adj(nbr) && (nbr->state == NSM_Full)) + +/* Check neighbour is DR_OTHER and state is 2_WAY */ +#define IS_NBR_STATE_2_WAY_WITH_DROTHER(nbr) \ + ((ospf_get_nbr_ism_role(nbr) == ISM_DROther) \ + && (nbr->state == NSM_TwoWay)) + +#define OSPF_GR_FALSE false +#define OSPF_GR_TRUE true + +#define OSPF_GR_SUCCESS 1 +#define OSPF_GR_FAILURE 0 +#define OSPF_GR_INVALID -1 + +extern const char *ospf_exit_reason_desc[]; +extern const char *ospf_restart_reason_desc[]; +extern const char *ospf_rejected_reason_desc[]; + +extern void ospf_gr_helper_init(struct ospf *ospf); +extern void ospf_gr_helper_stop(struct ospf *ospf); +extern int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa, + struct ospf_neighbor *nbr); +extern void ospf_gr_helper_exit(struct ospf_neighbor *nbr, + enum ospf_helper_exit_reason reason); +extern void ospf_process_maxage_grace_lsa(struct ospf *ospf, + struct ospf_lsa *lsa, + struct ospf_neighbor *nbr); +extern void ospf_helper_handle_topo_chg(struct ospf *ospf, + struct ospf_lsa *lsa); +extern void ospf_gr_helper_support_set(struct ospf *ospf, bool support); +extern void ospf_gr_helper_support_set_per_routerid(struct ospf *ospf, + struct in_addr *rid, + bool support); +extern void ospf_gr_helper_lsa_check_set(struct ospf *ospf, bool lsacheck); +extern void ospf_gr_helper_supported_gracetime_set(struct ospf *ospf, + uint32_t interval); +extern void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf, + bool planned_only); +#endif /* _ZEBRA_OSPF_HELPER_H */ diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 6bfdb1e9e0..3d2c28b1e4 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -796,9 +796,36 @@ int ospf_if_up(struct ospf_interface *oi) int ospf_if_down(struct ospf_interface *oi) { + struct ospf *ospf; + if (oi == NULL) return 0; + ospf = oi->ospf; + + /* Cease the HELPER role for all the neighbours + * of this interface. + */ + if (ospf->is_helper_supported) { + struct route_node *rn = NULL; + + if (ospf_interface_neighbor_count(oi)) { + for (rn = route_top(oi->nbrs); rn; + rn = route_next(rn)) { + struct ospf_neighbor *nbr = NULL; + + if (!rn->info) + continue; + + nbr = rn->info; + + if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) + ospf_gr_helper_exit( + nbr, OSPF_GR_HELPER_TOPO_CHG); + } + } + } + OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown); /* delete position in router LSA */ oi->lsa_pos_beg = 0; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 86712c6198..e9faa415fe 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -201,7 +201,7 @@ static void ospf_dr_change(struct ospf *ospf, struct route_table *nbrs) } } -static int ospf_dr_election(struct ospf_interface *oi) +int ospf_dr_election(struct ospf_interface *oi) { struct in_addr old_dr, old_bdr; int old_state, new_state; diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h index 8d21403695..67ea4c4684 100644 --- a/ospfd/ospf_ism.h +++ b/ospfd/ospf_ism.h @@ -99,6 +99,7 @@ extern int ospf_ism_event(struct thread *); extern void ism_change_status(struct ospf_interface *, int); extern int ospf_hello_timer(struct thread *thread); +extern int ospf_dr_election(struct ospf_interface *oi); DECLARE_HOOK(ospf_ism_change, (struct ospf_interface * oi, int state, int oldstate), diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 8095219146..0200bf5e26 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -164,6 +164,7 @@ struct ospf_lsa *ospf_lsa_new(void) new->tv_orig = new->tv_recv; new->refresh_list = -1; new->vrf_id = VRF_DEFAULT; + new->to_be_acknowledged = 0; return new; } @@ -2578,8 +2579,19 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi, /* Do comparision and record if recalc needed. */ rt_recalc = 0; - if (old == NULL || ospf_lsa_different(old, lsa)) + if (old == NULL || ospf_lsa_different(old, lsa)) { + /* Ref rfc3623 section 3.2.3 + * Installing new lsa or change in the existing LSA + * or flushing existing LSA leads to topo change + * and trigger SPF caculation. + * So, router should be aborted from HELPER role + * if it is detected as TOPO change. + */ + if (CHECK_LSA_TYPE_1_TO_5_OR_7(lsa->data->type)) + ospf_helper_handle_topo_chg(ospf, lsa); + rt_recalc = 1; + } /* Sequence number check (Section 14.1 of rfc 2328) diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 4033659bff..90f7b53632 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -119,6 +119,9 @@ struct ospf_lsa { /* VRF Id */ vrf_id_t vrf_id; + + /*For topo chg detection in HELPER role*/ + bool to_be_acknowledged; }; /* OSPF LSA Link Type. */ @@ -221,6 +224,11 @@ struct as_external_lsa { if (!(T)) \ (T) = thread_add_timer(master, (F), 0, 2) +#define CHECK_LSA_TYPE_1_TO_5_OR_7(type) \ + ((type == OSPF_ROUTER_LSA) || (type == OSPF_NETWORK_LSA) \ + || (type == OSPF_SUMMARY_LSA) || (type == OSPF_ASBR_SUMMARY_LSA) \ + || (type == OSPF_AS_EXTERNAL_LSA) || (type == OSPF_AS_NSSA_LSA)) + /* Prototypes. */ /* XXX: Eek, time functions, similar are in lib/thread.c */ extern struct timeval int2tv(int); diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index c4dc0136ed..d102fddf86 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -56,3 +56,4 @@ 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") +DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper") diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index 861de64c25..58f23aa9c7 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -55,5 +55,6 @@ DECLARE_MTYPE(OSPF_ROUTER_INFO) DECLARE_MTYPE(OSPF_PCE_PARAMS) DECLARE_MTYPE(OSPF_SR_PARAMS) DECLARE_MTYPE(OSPF_EXT_PARAMS) +DECLARE_MTYPE(OSPF_GR_HELPER) #endif /* _QUAGGA_OSPF_MEMORY_H */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index 46dfc505ef..b0ff40afe5 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -43,6 +43,7 @@ #include "ospfd/ospf_flood.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_bfd.h" +#include "ospfd/ospf_gr_helper.h" /* Fill in the the 'key' as appropriate to retrieve the entry for nbr * from the ospf_interface's nbrs table. Indexed by interface address @@ -99,6 +100,14 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->crypt_seqnum = 0; ospf_bfd_info_nbr_create(oi, nbr); + + /* Initialize GR Helper info*/ + nbr->gr_helper_info.recvd_grace_period = 0; + nbr->gr_helper_info.actual_grace_period = 0; + nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER; + nbr->gr_helper_info.helper_exit_reason = OSPF_GR_HELPER_EXIT_NONE; + nbr->gr_helper_info.gr_restart_reason = OSPF_GR_UNKNOWN_RESTART; + return nbr; } @@ -142,6 +151,8 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) ospf_bfd_info_free(&nbr->bfd_info); + OSPF_NSM_TIMER_OFF(nbr->gr_helper_info.t_grace_timer); + nbr->oi = NULL; XFREE(MTYPE_OSPF_NEIGHBOR, nbr); } diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 91dfc7a276..758693e289 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -22,6 +22,7 @@ #ifndef _ZEBRA_OSPF_NEIGHBOR_H #define _ZEBRA_OSPF_NEIGHBOR_H +#include <ospfd/ospf_gr_helper.h> #include <ospfd/ospf_packet.h> /* Neighbor Data Structure */ @@ -88,6 +89,9 @@ struct ospf_neighbor { /* BFD information */ void *bfd_info; + + /* ospf graceful restart HELPER info */ + struct ospf_helper_info gr_helper_info; }; /* Macros. */ @@ -113,5 +117,4 @@ extern struct ospf_neighbor *ospf_nbr_lookup_by_addr(struct route_table *, extern struct ospf_neighbor *ospf_nbr_lookup_by_routerid(struct route_table *, struct in_addr *); extern void ospf_renegotiate_optional_capabilities(struct ospf *top); - #endif /* _ZEBRA_OSPF_NEIGHBOR_H */ diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index 3a1547978a..28aec41eba 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -201,7 +201,6 @@ int ospf_sock_init(struct ospf *ospf) flog_err(EC_LIB_SOCKET, "Can't set IP_HDRINCL option for fd %d: %s", ospf_sock, safe_strerror(errno)); - close(ospf_sock); break; } #elif defined(IPTOS_PREC_INTERNETCONTROL) @@ -213,7 +212,6 @@ int ospf_sock_init(struct ospf *ospf) flog_err(EC_LIB_SOCKET, "can't set sockopt IP_TOS %d to socket %d: %s", tos, ospf_sock, safe_strerror(errno)); - close(ospf_sock); /* Prevent sd leak. */ break; } #else /* !IPTOS_PREC_INTERNETCONTROL */ diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index dffbfb7d17..2931831826 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -70,7 +70,15 @@ static int ospf_inactivity_timer(struct thread *thread) IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), ospf_get_name(nbr->oi->ospf)); - OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); + /* Dont trigger NSM_InactivityTimer event , if the current + * router acting as HELPER for this neighbour. + */ + if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) + OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); + else if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug( + "%s, Acting as HELPER for this neighbour, So inactivitytimer event will not be fired.", + __PRETTY_FUNCTION__); return 0; } @@ -144,7 +152,7 @@ static void nsm_timer_set(struct ospf_neighbor *nbr) /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with * the given neighbour */ -static int nsm_should_adj(struct ospf_neighbor *nbr) +int nsm_should_adj(struct ospf_neighbor *nbr) { struct ospf_interface *oi = nbr->oi; @@ -689,7 +697,11 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) lookup_msg(ospf_nsm_state_msg, old_state, NULL), lookup_msg(ospf_nsm_state_msg, state, NULL)); - ospf_router_lsa_update_area(oi->area); + /* Dont originate router LSA if the current + * router is acting as a HELPER for this neighbour. + */ + if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) + ospf_router_lsa_update_area(oi->area); if (oi->type == OSPF_IFTYPE_VIRTUALLINK) { vl_area = ospf_area_lookup_by_area_id( @@ -699,15 +711,21 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) ospf_router_lsa_update_area(vl_area); } - /* Originate network-LSA. */ - if (oi->state == ISM_DR) { - if (oi->network_lsa_self && oi->full_nbrs == 0) { - ospf_lsa_flush_area(oi->network_lsa_self, - oi->area); - ospf_lsa_unlock(&oi->network_lsa_self); - oi->network_lsa_self = NULL; - } else - ospf_network_lsa_update(oi); + /* Dont originate/flush network LSA if the current + * router is acting as a HELPER for this neighbour. + */ + if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) { + /* Originate network-LSA. */ + if (oi->state == ISM_DR) { + if (oi->network_lsa_self + && oi->full_nbrs == 0) { + ospf_lsa_flush_area( + oi->network_lsa_self, oi->area); + ospf_lsa_unlock(&oi->network_lsa_self); + oi->network_lsa_self = NULL; + } else + ospf_network_lsa_update(oi); + } } } diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h index dcfba84d8b..c219ba7386 100644 --- a/ospfd/ospf_nsm.h +++ b/ospfd/ospf_nsm.h @@ -81,7 +81,7 @@ extern void ospf_check_nbr_loading(struct ospf_neighbor *); extern int ospf_db_summary_isempty(struct ospf_neighbor *); extern int ospf_db_summary_count(struct ospf_neighbor *); extern void ospf_db_summary_clear(struct ospf_neighbor *); - +extern int nsm_should_adj(struct ospf_neighbor *nbr); DECLARE_HOOK(ospf_nsm_change, (struct ospf_neighbor * on, int state, int oldstate), (on, state, oldstate)) diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 61aae695b3..160982a238 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -54,6 +54,7 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_errors.h" #include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_gr_helper.h" /* * OSPF Fragmentation / fragmented writes @@ -1058,7 +1059,16 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh, OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_TwoWayReceived); nbr->options |= hello->options; } else { - OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_OneWayReceived); + /* If the router is DR_OTHER, RESTARTER will not wait + * until it receives the hello from it if it receives + * from DR and BDR. + * So, helper might receives ONW_WAY hello from + * RESTARTER. So not allowing to change the state if it + * receives one_way hellow when it acts as HELPER for + * that specific neighbor. + */ + if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) + OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_OneWayReceived); /* Set neighbor information. */ nbr->priority = hello->priority; nbr->d_router = hello->d_router; @@ -4262,6 +4272,12 @@ void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf_interface *oi = nbr->oi; + if (IS_GRACE_LSA(lsa)) { + if (IS_DEBUG_OSPF_GR_HELPER) + zlog_debug("%s, Sending GRACE ACK to Restarter.", + __PRETTY_FUNCTION__); + } + if (listcount(oi->ls_ack_direct.ls_ack) == 0) oi->ls_ack_direct.dst = nbr->address.u.prefix4; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 8099b0160c..87c1c91afb 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -5121,6 +5121,71 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, " Thread Link State Update Retransmission %s\n\n", nbr->t_ls_upd != NULL ? "on" : "off"); + if (!use_json) { + vty_out(vty, " Graceful restart Helper info:\n"); + + if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) { + vty_out(vty, + " Graceful Restart HELPER Status : Inprogress.\n"); + + vty_out(vty, + " Graceful Restart grace period time: %d (seconds).\n", + nbr->gr_helper_info.recvd_grace_period); + vty_out(vty, " Graceful Restart reason: %s.\n", + ospf_restart_reason_desc + [nbr->gr_helper_info + .gr_restart_reason]); + } else { + vty_out(vty, + " Graceful Restart HELPER Status : None\n"); + } + + if (nbr->gr_helper_info.rejected_reason + != OSPF_HELPER_REJECTED_NONE) + vty_out(vty, " Helper rejected reason: %s.\n", + ospf_rejected_reason_desc + [nbr->gr_helper_info.rejected_reason]); + + if (nbr->gr_helper_info.helper_exit_reason + != OSPF_GR_HELPER_EXIT_NONE) + vty_out(vty, " Last helper exit reason: %s.\n\n", + ospf_exit_reason_desc + [nbr->gr_helper_info + .helper_exit_reason]); + else + vty_out(vty, "\n"); + } else { + json_object_string_add(json_neigh, "grHelperStatus", + OSPF_GR_IS_ACTIVE_HELPER(nbr) ? + "Inprogress" + : "None"); + if (OSPF_GR_IS_ACTIVE_HELPER(nbr)) { + json_object_int_add( + json_neigh, "graceInterval", + nbr->gr_helper_info.recvd_grace_period); + json_object_string_add( + json_neigh, "grRestartReason", + ospf_restart_reason_desc + [nbr->gr_helper_info + .gr_restart_reason]); + } + + if (nbr->gr_helper_info.rejected_reason + != OSPF_HELPER_REJECTED_NONE) + json_object_string_add( + json_neigh, "helperRejectReason", + ospf_rejected_reason_desc + [nbr->gr_helper_info.rejected_reason]); + + if (nbr->gr_helper_info.helper_exit_reason + != OSPF_GR_HELPER_EXIT_NONE) + json_object_string_add( + json_neigh, "helperExitReason", + ospf_exit_reason_desc + [nbr->gr_helper_info + .helper_exit_reason]); + } + ospf_bfd_show_info(vty, nbr->bfd_info, json_neigh, use_json, 0); if (use_json) @@ -8070,12 +8135,25 @@ DEFUN (ip_ospf_area, ospf = ospf_lookup_instance(instance); if (instance && ospf == NULL) { + /* + * At this point we know we have received + * an instance and there is no ospf instance + * associated with it. This means we are + * in a situation where we have an + * ospf command that is setup for a different + * process(instance). We need to safely + * remove the command from ourselves and + * allow the other instance(process) handle + * the configuration command. + */ params = IF_DEF_PARAMS(ifp); if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { UNSET_IF_PARAM(params, if_area); ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - ospf_interface_area_unset(ospf, ifp); - ospf->if_ospf_cli_count--; + if (ospf) { + ospf_interface_area_unset(ospf, ifp); + ospf->if_ospf_cli_count--; + } } return CMD_NOT_MY_INSTANCE; } @@ -8167,7 +8245,7 @@ DEFUN (no_ip_ospf_area, else ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance && ospf == NULL) return CMD_NOT_MY_INSTANCE; argv_find(argv, argc, "area", &idx); @@ -8197,8 +8275,11 @@ DEFUN (no_ip_ospf_area, ospf_if_update_params((ifp), (addr)); } - ospf_interface_area_unset(ospf, ifp); - ospf->if_ospf_cli_count--; + if (ospf) { + ospf_interface_area_unset(ospf, ifp); + ospf->if_ospf_cli_count--; + } + return CMD_SUCCESS; } @@ -8988,6 +9069,487 @@ DEFUN (no_ospf_proactive_arp, return CMD_SUCCESS; } +/* Graceful Restart HELPER Commands */ +DEFPY(ospf_gr_helper_enable, ospf_gr_helper_enable_cmd, + "graceful-restart helper-only [A.B.C.D]", + "OSPF Graceful Restart\n" + "Enable Helper support\n" + "Advertising router id\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + struct in_addr addr; + int ret; + + if (argc == 3) { + ret = inet_aton(argv[2]->arg, &addr); + if (!ret) { + vty_out(vty, + "Please specify the valid routerid address.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ospf_gr_helper_support_set_per_routerid(ospf, &addr, OSPF_GR_TRUE); + return CMD_SUCCESS; + } + + ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE); + + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_enable, + no_ospf_gr_helper_enable_cmd, + "no graceful-restart helper-only [A.B.C.D]", + NO_STR + "OSPF Graceful Restart\n" + "Disable Helper support\n" + "Advertising router id\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + struct in_addr addr; + int ret; + + if (argc == 4) { + ret = inet_aton(argv[3]->arg, &addr); + if (!ret) { + vty_out(vty, + "Please specify the valid routerid address.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ospf_gr_helper_support_set_per_routerid(ospf, &addr, + OSPF_GR_FALSE); + return CMD_SUCCESS; + } + + ospf_gr_helper_support_set(ospf, OSPF_GR_FALSE); + return CMD_SUCCESS; +} + +DEFPY(ospf_gr_helper_enable_lsacheck, + ospf_gr_helper_enable_lsacheck_cmd, + "graceful-restart helper strict-lsa-checking", + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Enable strict LSA check\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_TRUE); + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_enable_lsacheck, + no_ospf_gr_helper_enable_lsacheck_cmd, + "no graceful-restart helper strict-lsa-checking", + NO_STR + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Disable strict LSA check\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_FALSE); + return CMD_SUCCESS; +} + +DEFPY(ospf_gr_helper_supported_grace_time, + ospf_gr_helper_supported_grace_time_cmd, + "graceful-restart helper supported-grace-time (10-1800)$interval", + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported grace timer\n" + "Grace interval(in seconds)\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_supported_gracetime_set(ospf, interval); + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_supported_grace_time, + no_ospf_gr_helper_supported_grace_time_cmd, + "no graceful-restart helper supported-grace-time (10-1800)$interval", + NO_STR + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported grace timer\n" + "Grace interval(in seconds)\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_supported_gracetime_set(ospf, OSPF_MAX_GRACE_INTERVAL); + return CMD_SUCCESS; +} + +DEFPY(ospf_gr_helper_planned_only, + ospf_gr_helper_planned_only_cmd, + "graceful-restart helper planned-only", + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported only planned restart\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_TRUE); + + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_planned_only, + no_ospf_gr_helper_planned_only_cmd, + "no graceful-restart helper planned-only", + NO_STR + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported only for planned restart\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_FALSE); + + return CMD_SUCCESS; +} + +static int ospf_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *backet, + void *arg) +{ + struct advRtr *rtr = backet->data; + struct vty *vty = (struct vty *)arg; + static unsigned int count; + + vty_out(vty, "%-6s,", inet_ntoa(rtr->advRtrAddr)); + count++; + + if (count % 5 == 0) + vty_out(vty, "\n"); + + return HASHWALK_CONTINUE; +} + +static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf, + uint8_t use_vrf, json_object *json, + bool uj, bool detail) +{ + struct listnode *node; + struct ospf_interface *oi; + json_object *json_vrf = NULL; + + if (uj) { + if (use_vrf) + json_vrf = json_object_new_object(); + else + json_vrf = json; + } + + if (ospf->instance) { + if (uj) + json_object_int_add(json, "ospfInstance", + ospf->instance); + else + vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); + } + + ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); + + if (uj) { + if (use_vrf) { + if (ospf->vrf_id == VRF_DEFAULT) + json_object_object_add(json, "default", + json_vrf); + else + json_object_object_add(json, ospf->name, + json_vrf); + } + } else + vty_out(vty, "\n"); + + /* Show Router ID. */ + if (uj) { + json_object_string_add(json_vrf, "routerId", + inet_ntoa(ospf->router_id)); + } else { + vty_out(vty, "\n OSPF Router with ID (%s)\n\n", + inet_ntoa(ospf->router_id)); + } + + if (!uj) { + + if (ospf->is_helper_supported) + vty_out(vty, + " Graceful restart helper support enabled.\n"); + else + vty_out(vty, + " Graceful restart helper support disabled.\n"); + + if (ospf->strict_lsa_check) + vty_out(vty, " Strict LSA check is enabled.\n"); + else + vty_out(vty, " Strict LSA check is disabled.\n"); + + if (ospf->only_planned_restart) + vty_out(vty, + " Helper supported for planned restarts only.\n"); + else + vty_out(vty, + " Helper supported for Planned and Unplanned Restarts.\n"); + + vty_out(vty, + " Supported Graceful restart interval: %d(in seconds).\n", + ospf->supported_grace_time); + + if (OSPF_HELPER_ENABLE_RTR_COUNT(ospf)) { + vty_out(vty, " Enable Router list:\n"); + vty_out(vty, " "); + hash_walk(ospf->enable_rtr_list, + ospf_print_vty_helper_dis_rtr_walkcb, vty); + vty_out(vty, "\n\n"); + } + + if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) { + vty_out(vty, " Last Helper exit Reason :%s\n", + ospf_exit_reason_desc[ospf->last_exit_reason]); + } + + if (ospf->active_restarter_cnt) + vty_out(vty, + " Number of Active neighbours in graceful restart: %d\n", + ospf->active_restarter_cnt); + else + vty_out(vty, "\n"); + + } else { + json_object_string_add( + json_vrf, "helperSupport", + (ospf->is_helper_supported) ? "Enabled" : "Disabled"); + json_object_string_add(json_vrf, "strictLsaCheck", + (ospf->strict_lsa_check) ? "Enabled" + : "Disabled"); + json_object_string_add( + json_vrf, "restartSupoort", + (ospf->only_planned_restart) + ? "Planned Restart only" + : "Planned and Unplanned Restarts"); + + json_object_int_add(json_vrf, "supportedGracePeriod", + ospf->supported_grace_time); + + if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) + json_object_string_add( + json_vrf, "LastExitReason", + ospf_exit_reason_desc[ospf->last_exit_reason]); + + if (ospf->active_restarter_cnt) + json_object_int_add(json_vrf, "activeRestarterCnt", + ospf->active_restarter_cnt); + } + + + if (detail) { + int cnt = 1; + json_object *json_neighbors = NULL; + + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + struct route_node *rn; + struct ospf_neighbor *nbr; + json_object *json_neigh; + + if (ospf_interface_neighbor_count(oi) == 0) + continue; + + if (uj) { + json_object_object_get_ex(json_vrf, "Neighbors", + &json_neighbors); + if (!json_neighbors) { + json_neighbors = + json_object_new_object(); + json_object_object_add(json_vrf, + "Neighbors", + json_neighbors); + } + } + + for (rn = route_top(oi->nbrs); rn; + rn = route_next(rn)) { + + if (!rn->info) + continue; + + nbr = rn->info; + + if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) + continue; + + if (!uj) { + vty_out(vty, " Neighbour %d :\n", cnt); + vty_out(vty, " Address : %s\n", + inet_ntoa(nbr->address.u + .prefix4)); + vty_out(vty, " Routerid : %s\n", + inet_ntoa(nbr->router_id)); + vty_out(vty, + " Received Grace period : %d(in seconds).\n", + nbr->gr_helper_info + .recvd_grace_period); + vty_out(vty, + " Actual Grace period : %d(in seconds)\n", + nbr->gr_helper_info + .actual_grace_period); + vty_out(vty, + " Remaining GraceTime:%ld(in seconds).\n", + thread_timer_remain_second( + nbr->gr_helper_info + .t_grace_timer)); + vty_out(vty, + " Graceful Restart reason: %s.\n\n", + ospf_restart_reason_desc + [nbr->gr_helper_info + .gr_restart_reason]); + cnt++; + } else { + json_neigh = json_object_new_object(); + json_object_string_add( + json_neigh, "srcAddr", + inet_ntoa(nbr->src)); + + json_object_string_add( + json_neigh, "routerid", + inet_ntoa(nbr->router_id)); + json_object_int_add( + json_neigh, + "recvdGraceInterval", + nbr->gr_helper_info + .recvd_grace_period); + json_object_int_add( + json_neigh, + "actualGraceInterval", + nbr->gr_helper_info + .actual_grace_period); + json_object_int_add( + json_neigh, "remainGracetime", + thread_timer_remain_second( + nbr->gr_helper_info + .t_grace_timer)); + json_object_string_add( + json_neigh, "restartReason", + ospf_restart_reason_desc + [nbr->gr_helper_info + .gr_restart_reason]); + json_object_object_add( + json_neighbors, + inet_ntoa(nbr->src), + json_neigh); + } + } + } + } + + return CMD_SUCCESS; +} + +DEFPY (show_ip_ospf_gr_helper, + show_ip_ospf_gr_helper_cmd, + "show ip ospf [vrf <NAME|all>] graceful-restart helper [detail] [json]", + SHOW_STR + IP_STR + "OSPF information\n" + VRF_CMD_HELP_STR + "All VRFs\n" + "OSPF Graceful Restart\n" + "Helper details in the router\n" + "Detailed informtion\n" + JSON_STR) +{ + char *vrf_name = NULL; + bool all_vrf = false; + int ret = CMD_SUCCESS; + int idx_vrf = 0; + int idx = 0; + uint8_t use_vrf = 0; + bool uj = use_json(argc, argv); + struct ospf *ospf = NULL; + json_object *json = NULL; + struct listnode *node = NULL; + int inst = 0; + bool detail = false; + + OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + + if (argv_find(argv, argc, "detail", &idx)) + detail = true; + + if (uj) + json = json_object_new_object(); + + /* vrf input is provided */ + if (vrf_name) { + use_vrf = 1; + + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { + if (!ospf->oi_running) + continue; + + ret = ospf_show_gr_helper_details( + vty, ospf, use_vrf, json, uj, detail); + } + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return ret; + } + + ospf = ospf_lookup_by_inst_name(inst, vrf_name); + + if (ospf == NULL || !ospf->oi_running) { + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else + vty_out(vty, "%% OSPF instance not found\n"); + + return CMD_SUCCESS; + } + + } else { + /* Default Vrf */ + ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); + + if (ospf == NULL || !ospf->oi_running) { + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else + vty_out(vty, "%% OSPF instance not found\n"); + + return CMD_SUCCESS; + } + + ospf_show_gr_helper_details(vty, ospf, use_vrf, json, uj, + detail); + } + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} +/* Graceful Restart HELPER commands end */ + static void config_write_stub_router(struct vty *vty, struct ospf *ospf) { struct listnode *ln; @@ -10310,6 +10872,41 @@ static int config_write_ospf_redistribute(struct vty *vty, struct ospf *ospf) return 0; } +static int ospf_cfg_write_helper_dis_rtr_walkcb(struct hash_bucket *backet, + void *arg) +{ + struct advRtr *rtr = backet->data; + struct vty *vty = (struct vty *)arg; + + vty_out(vty, " graceful-restart helper-only %s\n", + inet_ntoa(rtr->advRtrAddr)); + return HASHWALK_CONTINUE; +} + +static int config_write_ospf_gr_helper(struct vty *vty, struct ospf *ospf) +{ + if (ospf->is_helper_supported) + vty_out(vty, " graceful-restart helper-only\n"); + + if (!ospf->strict_lsa_check) + vty_out(vty, " no graceful-restart helper strict-lsa-checking\n"); + + if (ospf->only_planned_restart) + vty_out(vty, " graceful-restart helper planned-only\n"); + + if (ospf->supported_grace_time != OSPF_MAX_GRACE_INTERVAL) + vty_out(vty, + " graceful-restart helper supported-grace-time %d\n", + ospf->supported_grace_time); + + if (OSPF_HELPER_ENABLE_RTR_COUNT(ospf)) { + hash_walk(ospf->enable_rtr_list, + ospf_cfg_write_helper_dis_rtr_walkcb, vty); + } + + return 0; +} + static int config_write_ospf_default_metric(struct vty *vty, struct ospf *ospf) { if (ospf->default_metric != -1) @@ -10477,6 +11074,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf) /* Redistribute information print. */ config_write_ospf_redistribute(vty, ospf); + /* Print gr helper configs */ + config_write_ospf_gr_helper(vty, ospf); + /* passive-interface print. */ if (ospf->passive_interface_default == OSPF_IF_PASSIVE) vty_out(vty, " passive-interface default\n"); @@ -10620,6 +11220,9 @@ void ospf_vty_show_init(void) /* "show ip ospf vrfs" commands. */ install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd); + + /* "show ip ospf gr-helper details" command */ + install_element(VIEW_NODE, &show_ip_ospf_gr_helper_cmd); } @@ -10735,6 +11338,16 @@ static void ospf_vty_zebra_init(void) install_element(OSPF_NODE, &no_ospf_distance_cmd); install_element(OSPF_NODE, &no_ospf_distance_ospf_cmd); install_element(OSPF_NODE, &ospf_distance_ospf_cmd); + + /*Ospf garcefull restart helper configurations */ + install_element(OSPF_NODE, &ospf_gr_helper_enable_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_enable_cmd); + install_element(OSPF_NODE, &ospf_gr_helper_enable_lsacheck_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_enable_lsacheck_cmd); + install_element(OSPF_NODE, &ospf_gr_helper_supported_grace_time_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_supported_grace_time_cmd); + install_element(OSPF_NODE, &ospf_gr_helper_planned_only_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_planned_only_cmd); #if 0 install_element (OSPF_NODE, &ospf_distance_source_cmd); install_element (OSPF_NODE, &no_ospf_distance_source_cmd); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index cc5839a810..aa063a0759 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -59,6 +59,7 @@ #include "ospfd/ospf_flood.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_ldp_sync.h" +#include "ospfd/ospf_gr_helper.h" DEFINE_QOBJ_TYPE(ospf) @@ -309,6 +310,8 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) new->proactive_arp = OSPF_PROACTIVE_ARP_DEFAULT; + ospf_gr_helper_init(new); + QOBJ_REG(new, ospf); new->fd = -1; @@ -766,6 +769,9 @@ static void ospf_finish_final(struct ospf *ospf) list_delete(&ospf->areas); list_delete(&ospf->oi_write_q); + /* Reset GR helper data structers */ + ospf_gr_helper_stop(ospf); + close(ospf->fd); stream_free(ospf->ibuf); ospf->fd = -1; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 55bc64317e..5009355d48 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -319,7 +319,41 @@ struct ospf { /* Redistributed external information. */ struct list *external[ZEBRA_ROUTE_MAX + 1]; -#define EXTERNAL_INFO(E) (E->external_info) +#define EXTERNAL_INFO(E) (E->external_info) + + /* Gracefull restart Helper supported configs*/ + /* Supported grace interval*/ + uint32_t supported_grace_time; + + /* Helper support + * Supported : True + * Not Supported : False. + */ + bool is_helper_supported; + + /* Support for strict LSA check. + * if it is set,Helper aborted + * upon a TOPO change. + */ + bool strict_lsa_check; + + /* Support as HELPER only for + * planned restarts. + */ + bool only_planned_restart; + + /* This list contains the advertisement + * routerids which are not support for HELPERs. + */ + struct hash *enable_rtr_list; + + /* HELPER for number of active + * RESTARTERs. + */ + uint16_t active_restarter_cnt; + + /* last HELPER exit reason */ + uint32_t last_exit_reason; /* MPLS LDP-IGP Sync */ struct ldp_sync_info_cmd ldp_sync_cmd; diff --git a/ospfd/subdir.am b/ospfd/subdir.am index e586937478..1a807ea12b 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -57,6 +57,7 @@ ospfd_libfrrospf_a_SOURCES = \ ospfd/ospf_vty.c \ ospfd/ospf_zebra.c \ ospfd/ospfd.c \ + ospfd/ospf_gr_helper.c \ # end if OSPFD @@ -78,6 +79,7 @@ endif clippy_scan += \ ospfd/ospf_vty.c \ ospfd/ospf_ldp_sync.c \ + ospfd/ospf_dump.c \ # end noinst_HEADERS += \ @@ -102,6 +104,7 @@ noinst_HEADERS += \ ospfd/ospf_te.h \ ospfd/ospf_vty.h \ ospfd/ospf_zebra.h \ + ospfd/ospf_gr_helper.h \ # end ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM) diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 9f966f617f..c423668ebd 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -1145,9 +1145,9 @@ void pbr_vty_init(void) /* debug */ install_node(&debug_node); - install_element(VIEW_NODE, &debug_pbr_cmd); + install_element(ENABLE_NODE, &debug_pbr_cmd); install_element(CONFIG_NODE, &debug_pbr_cmd); - install_element(VIEW_NODE, &show_debugging_pbr_cmd); + install_element(ENABLE_NODE, &show_debugging_pbr_cmd); install_default(PBRMAP_NODE); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 6256774464..38123cc8f6 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -11236,7 +11236,6 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_mroute_summary_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_rib_cmd); install_element(VIEW_NODE, &show_ip_ssmpingd_cmd); - install_element(VIEW_NODE, &show_debugging_pim_cmd); install_element(VIEW_NODE, &show_ip_pim_nexthop_cmd); install_element(VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd); install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd); @@ -11252,6 +11251,8 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &clear_ip_pim_oil_cmd); install_element(ENABLE_NODE, &clear_ip_pim_statistics_cmd); + install_element(ENABLE_NODE, &show_debugging_pim_cmd); + install_element(ENABLE_NODE, &debug_igmp_cmd); install_element(ENABLE_NODE, &no_debug_igmp_cmd); install_element(ENABLE_NODE, &debug_igmp_events_cmd); diff --git a/ripd/ripd.c b/ripd/ripd.c index bcf73e8f89..389a54f224 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3422,6 +3422,8 @@ static void rip_distribute_update_all_wrapper(struct access_list *notused) /* Delete all added rip route. */ void rip_clean(struct rip *rip) { + rip_interfaces_clean(rip); + if (rip->enabled) rip_instance_disable(rip); @@ -3443,7 +3445,6 @@ void rip_clean(struct rip *rip) route_table_finish(rip->enable_network); vector_free(rip->passive_nondefault); list_delete(&rip->offset_list_master); - rip_interfaces_clean(rip); route_table_finish(rip->distance_table); RB_REMOVE(rip_instance_head, &rip_instances, rip); diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c index 54edb17ecc..539c01b3ec 100644 --- a/ripngd/ripng_debug.c +++ b/ripngd/ripng_debug.c @@ -218,7 +218,7 @@ void ripng_debug_init(void) install_node(&debug_node); - install_element(VIEW_NODE, &show_debugging_ripng_cmd); + install_element(ENABLE_NODE, &show_debugging_ripng_cmd); install_element(ENABLE_NODE, &debug_ripng_events_cmd); install_element(ENABLE_NODE, &debug_ripng_packet_cmd); diff --git a/ripngd/ripng_nb_config.c b/ripngd/ripng_nb_config.c index 85f378bc9e..25bf65f7aa 100644 --- a/ripngd/ripng_nb_config.c +++ b/ripngd/ripng_nb_config.c @@ -163,7 +163,7 @@ int ripngd_instance_default_information_originate_modify( ripng = nb_running_get_entry(args->dnode, NULL, true); default_information = yang_dnode_get_bool(args->dnode, NULL); - str2prefix_ipv6("::/0", &p); + (void)str2prefix_ipv6("::/0", &p); if (default_information) { ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0); diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 8a7950daf4..c2eb7c6ee4 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2533,6 +2533,8 @@ static void ripng_distribute_update_all_wrapper(struct access_list *notused) /* delete all the added ripng routes. */ void ripng_clean(struct ripng *ripng) { + ripng_interface_clean(ripng); + if (ripng->enabled) ripng_instance_disable(ripng); @@ -2554,7 +2556,6 @@ void ripng_clean(struct ripng *ripng) agg_table_finish(ripng->enable_network); vector_free(ripng->passive_interface); list_delete(&ripng->offset_list_master); - ripng_interface_clean(ripng); RB_REMOVE(ripng_instance_head, &ripng_instances, ripng); XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name); diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index d062f027ab..0c3bf7af78 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -716,7 +716,7 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &send_opaque_reg_cmd); install_element(ENABLE_NODE, &neigh_discover_cmd); - install_element(VIEW_NODE, &show_debugging_sharpd_cmd); + install_element(ENABLE_NODE, &show_debugging_sharpd_cmd); return; } diff --git a/staticd/static_routes.c b/staticd/static_routes.c index d6aab296c9..d105b2123f 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -283,6 +283,7 @@ static_add_nexthop(struct route_node *rn, struct static_path *pn, safi_t safi, break; case STATIC_BLACKHOLE: + nh->bh_type = STATIC_BLACKHOLE_NULL; break; case STATIC_IFNAME: ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id); diff --git a/staticd/static_vty.c b/staticd/static_vty.c index f5bc9df649..6608811cc6 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -1167,7 +1167,7 @@ void static_vty_init(void) install_element(CONFIG_NODE, &ipv6_route_cmd); install_element(VRF_NODE, &ipv6_route_vrf_cmd); - install_element(VIEW_NODE, &show_debugging_static_cmd); - install_element(VIEW_NODE, &debug_staticd_cmd); + install_element(ENABLE_NODE, &show_debugging_static_cmd); + install_element(ENABLE_NODE, &debug_staticd_cmd); install_element(CONFIG_NODE, &debug_staticd_cmd); } diff --git a/tests/ospf6d/test_lsdb.c b/tests/ospf6d/test_lsdb.c index 24821febe6..c5bdcd3d13 100644 --- a/tests/ospf6d/test_lsdb.c +++ b/tests/ospf6d/test_lsdb.c @@ -134,9 +134,10 @@ DEFPY(lsdb_walk, lsdb_walk_cmd, "LSDB\n" "walk entries\n") { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa, *lsanext; + unsigned cnt = 0; - for (ALL_LSDB(lsdb, lsa)) { + for (ALL_LSDB(lsdb, lsa, lsanext)) { lsa_show_oneline(vty, lsa); cnt++; } diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 2e9c4901bc..6e8e749092 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -1,6 +1,6 @@ # Skip pytests example directory [pytest] -norecursedirs = .git example-test example-topojson-test lib docker evpn_type5_test_topo1 +norecursedirs = .git example-test example-topojson-test lib docker [topogen] # Default configuration values diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index 3165ea119a..7d9cea3adc 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -775,8 +775,8 @@ void vrrp_vty_init(void) install_element(VIEW_NODE, &vrrp_vrid_show_cmd); install_element(VIEW_NODE, &vrrp_vrid_show_summary_cmd); - install_element(VIEW_NODE, &show_debugging_vrrp_cmd); - install_element(VIEW_NODE, &debug_vrrp_cmd); + install_element(ENABLE_NODE, &show_debugging_vrrp_cmd); + install_element(ENABLE_NODE, &debug_vrrp_cmd); install_element(CONFIG_NODE, &debug_vrrp_cmd); install_element(CONFIG_NODE, &vrrp_autoconfigure_cmd); install_element(CONFIG_NODE, &vrrp_default_cmd); diff --git a/vtysh/.gitignore b/vtysh/.gitignore index c1a39b8a12..118b84407b 100644 --- a/vtysh/.gitignore +++ b/vtysh/.gitignore @@ -1,3 +1,4 @@ vtysh vtysh_cmd.c extract.pl +vtysh_daemons.h diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index aa154f2ecf..8a1e71a37d 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1772,6 +1772,24 @@ DEFUNSH(VTYSH_BGPD, vnc_l2_group, vnc_l2_group_cmd, "vnc l2-group NAME", vty->node = BGP_VNC_L2_GROUP_NODE; return CMD_SUCCESS; } + +DEFUNSH(VTYSH_BGPD, exit_vnc_config, exit_vnc_config_cmd, "exit-vnc", + "Exit from VNC configuration mode\n") +{ + if (vty->node == BGP_VNC_DEFAULTS_NODE + || vty->node == BGP_VNC_NVE_GROUP_NODE + || vty->node == BGP_VNC_L2_GROUP_NODE) + vty->node = BGP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_BGPD, exit_vrf_policy, exit_vrf_policy_cmd, "exit-vrf-policy", + "Exit from VRF policy configuration mode\n") +{ + if (vty->node == BGP_VRF_POLICY_NODE) + vty->node = BGP_NODE; + return CMD_SUCCESS; +} #endif #endif /* HAVE_BGPD */ @@ -2105,17 +2123,6 @@ DEFUNSH(VTYSH_BGPD, exit_vni, exit_vni_cmd, "exit-vni", "Exit from VNI mode\n") return CMD_SUCCESS; } -DEFUNSH(VTYSH_BGPD, exit_vnc_config, exit_vnc_config_cmd, "exit-vnc", - "Exit from VNC configuration mode\n") -{ - if (vty->node == BGP_VNC_DEFAULTS_NODE - || vty->node == BGP_VNC_NVE_GROUP_NODE - || vty->node == BGP_VNC_L2_GROUP_NODE) - vty->node = BGP_NODE; - return CMD_SUCCESS; - -} - DEFUNSH(VTYSH_BGPD, rpki_exit, rpki_exit_cmd, "exit", "Exit current mode and down to previous mode\n") { @@ -2141,14 +2148,6 @@ DEFUNSH(VTYSH_BGPD, bmp_quit, bmp_quit_cmd, "quit", { return bmp_exit(self, vty, argc, argv); } - -DEFUNSH(VTYSH_BGPD, exit_vrf_policy, exit_vrf_policy_cmd, "exit-vrf-policy", - "Exit from VRF policy configuration mode\n") -{ - if (vty->node == BGP_VRF_POLICY_NODE) - vty->node = BGP_NODE; - return CMD_SUCCESS; -} #endif /* HAVE_BGPD */ DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf", @@ -4271,9 +4270,9 @@ void vtysh_init_vty(void) #endif /* debugging */ - install_element(VIEW_NODE, &vtysh_show_debugging_cmd); install_element(VIEW_NODE, &vtysh_show_error_code_cmd); - install_element(VIEW_NODE, &vtysh_show_debugging_hashtable_cmd); + install_element(ENABLE_NODE, &vtysh_show_debugging_cmd); + install_element(ENABLE_NODE, &vtysh_show_debugging_hashtable_cmd); install_element(ENABLE_NODE, &vtysh_debug_all_cmd); install_element(CONFIG_NODE, &vtysh_debug_all_cmd); install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd); diff --git a/zebra/debug.c b/zebra/debug.c index 8c53ab73e4..87a10ea65d 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -671,7 +671,7 @@ void zebra_debug_init(void) install_node(&debug_node); - install_element(VIEW_NODE, &show_debugging_zebra_cmd); + install_element(ENABLE_NODE, &show_debugging_zebra_cmd); install_element(ENABLE_NODE, &debug_zebra_events_cmd); install_element(ENABLE_NODE, &debug_zebra_nht_cmd); diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 11b252fc18..42a5bfd9db 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -411,47 +411,91 @@ void if_get_flags(struct interface *ifp) { int ret; struct ifreq ifreq; -#ifdef HAVE_BSD_LINK_DETECT - struct ifmediareq ifmr; -#endif /* HAVE_BSD_LINK_DETECT */ ifreq_set_name(&ifreq, ifp); ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); if (ret < 0) { flog_err_sys(EC_LIB_SYSTEM_CALL, - "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s", - safe_strerror(errno)); + "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s", + ifp->name, safe_strerror(errno)); return; } -#ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */ - /* Per-default, IFF_RUNNING is held high, unless link-detect says - * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag, - * following practice on Linux and Solaris kernels + if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) + goto out; + + /* Per-default, IFF_RUNNING is held high, unless link-detect + * says otherwise - we abuse IFF_RUNNING inside zebra as a + * link-state flag, following practice on Linux and Solaris + * kernels + */ + +#ifdef SIOCGIFDATA + /* + * BSD gets link state from ifi_link_link in struct if_data. + * All BSD's have this in getifaddrs(3) ifa_data for AF_LINK + * addresses. We can also access it via SIOCGIFDATA. + */ + +#ifdef __NetBSD__ + struct ifdatareq ifdr = {.ifdr_data.ifi_link_state = 0}; + struct if_data *ifdata = &ifdr.ifdr_data; + + strlcpy(ifdr.ifdr_name, ifp->name, sizeof(ifdr.ifdr_name)); + ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf_id); +#else + struct if_data ifd = {.ifi_link_state = 0}; + struct if_data *ifdata = &ifd; + + ifreq.ifr_data = (caddr_t)ifdata; + ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreq, ifp->vrf_id); +#endif + + if (ret == -1) + /* Very unlikely. Did the interface disappear? */ + flog_err_sys(EC_LIB_SYSTEM_CALL, + "if_ioctl(SIOCGIFDATA %s) failed: %s", ifp->name, + safe_strerror(errno)); + else { + if (ifdata->ifi_link_state >= LINK_STATE_UP) + SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN) + /* BSD traditionally treats UNKNOWN as UP */ + SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + else + UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + } + +#elif defined(HAVE_BSD_LINK_DETECT) + /* + * This is only needed for FreeBSD older than FreeBSD-13. + * Valid and active media generally means the link state is + * up, but this is not always the case. + * For example, some BSD's with a net80211 interface in MONITOR + * mode will treat the media as valid and active but the + * link state is down - because we cannot send anything. + * Also, virtual interfaces such as PPP, VLAN, etc generally + * don't support media at all, so the ioctl will just fail. */ - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + struct ifmediareq ifmr = {.ifm_status = 0}; - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { - (void)memset(&ifmr, 0, sizeof(ifmr)); - strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); + strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); - /* Seems not all interfaces implement this ioctl */ - if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1 && - errno != EINVAL) + if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { + if (errno != EINVAL) flog_err_sys(EC_LIB_SYSTEM_CALL, - "if_ioctl(SIOCGIFMEDIA) failed: %s", - safe_strerror(errno)); - else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */ - { - if (ifmr.ifm_status & IFM_ACTIVE) - SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); - else - UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); - } + "if_ioctl(SIOCGIFMEDIA %s) failed: %s", + ifp->name, safe_strerror(errno)); + } else if (ifmr.ifm_status & IFM_AVALID) { /* media state is valid */ + if (ifmr.ifm_status & IFM_ACTIVE) /* media is active */ + SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + else + UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); } #endif /* HAVE_BSD_LINK_DETECT */ +out: if_flags_update(ifp, (ifreq.ifr_flags & 0x0000ffff)); } diff --git a/zebra/main.c b/zebra/main.c index 2afef46bb2..6b6409f845 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -87,7 +87,6 @@ uint32_t nl_rcvbufsize = 4194304; const struct option longopts[] = { {"batch", no_argument, NULL, 'b'}, {"allow_delete", no_argument, NULL, 'a'}, - {"keep_kernel", no_argument, NULL, 'k'}, {"socket", required_argument, NULL, 'z'}, {"ecmp", required_argument, NULL, 'e'}, {"retain", no_argument, NULL, 'r'}, diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index f71065cdcf..a406884187 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -358,6 +358,8 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail) } else { if (!uj) vty_out(vty, "VNI %d doesn't exist\n", vni); + + return; } zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json, detail); } diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 6a76a475e6..860dc5b054 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -722,9 +722,8 @@ zebra_evpn_proc_sync_neigh_update(zebra_evpn_t *zevpn, zebra_neigh_t *n, n->state, false /*force*/); old_bgp_ready = false; } - if (n->mac) - zebra_evpn_local_neigh_deref_mac( - n, false /*send_mac_update*/); + zebra_evpn_local_neigh_deref_mac(n, + false /*send_mac_update*/); } /* clear old fwd info */ n->rem_seq = 0; |
