diff options
111 files changed, 2927 insertions, 976 deletions
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index d6ac88c09b..33e3db2c16 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -549,6 +549,8 @@ static bool community_regexp_include(regex_t *reg, struct community *com, int i) static bool community_regexp_match(struct community *com, regex_t *reg) { const char *str; + char *regstr; + int rv; /* When there is no communities attribute it is treated as empty string. */ @@ -557,12 +559,14 @@ static bool community_regexp_match(struct community *com, regex_t *reg) else str = community_str(com, false); + regstr = bgp_alias2community_str(str); + /* Regular expression match. */ - if (regexec(reg, bgp_alias2community_str(str), 0, NULL, 0) == 0) - return true; + rv = regexec(reg, regstr, 0, NULL, 0); - /* No match. */ - return false; + XFREE(MTYPE_TMP, regstr); + + return rv == 0; } static char *lcommunity_str_get(struct lcommunity *lcom, int i) @@ -619,6 +623,8 @@ static bool lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom, static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg) { const char *str; + char *regstr; + int rv; /* When there is no communities attribute it is treated as empty string. */ @@ -627,12 +633,14 @@ static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg) else str = lcommunity_str(com, false); + regstr = bgp_alias2community_str(str); + /* Regular expression match. */ - if (regexec(reg, bgp_alias2community_str(str), 0, NULL, 0) == 0) - return true; + rv = regexec(reg, regstr, 0, NULL, 0); - /* No match. */ - return false; + XFREE(MTYPE_TMP, regstr); + + return rv == 0; } diff --git a/bgpd/bgp_community_alias.c b/bgpd/bgp_community_alias.c index 5f45e19a3b..793f3ac9ac 100644 --- a/bgpd/bgp_community_alias.c +++ b/bgpd/bgp_community_alias.c @@ -175,22 +175,25 @@ const char *bgp_alias2community(char *alias) * This is a helper to convert already aliased version * of communities into numerical-only format. */ -const char *bgp_alias2community_str(const char *str) +char *bgp_alias2community_str(const char *str) { char **aliases; - int num; + char *comstr; + int num, i; frrstr_split(str, " ", &aliases, &num); - const char *communities[num + 1]; + const char *communities[num]; - for (int i = 0; i < num; i++) { - communities[i] = - XSTRDUP(MTYPE_TMP, bgp_alias2community(aliases[i])); + for (i = 0; i < num; i++) + communities[i] = bgp_alias2community(aliases[i]); + + comstr = frrstr_join(communities, num, " "); + + for (i = 0; i < num; i++) XFREE(MTYPE_TMP, aliases[i]); - } XFREE(MTYPE_TMP, aliases); - return frrstr_join(communities, num, " "); + return comstr; } static int bgp_community_alias_vector_walker(struct hash_bucket *bucket, diff --git a/bgpd/bgp_community_alias.h b/bgpd/bgp_community_alias.h index fc9eb9f9e4..57cde0ad44 100644 --- a/bgpd/bgp_community_alias.h +++ b/bgpd/bgp_community_alias.h @@ -43,7 +43,7 @@ extern void bgp_ca_alias_delete(struct community_alias *ca); extern int bgp_community_alias_write(struct vty *vty); extern const char *bgp_community2alias(char *community); extern const char *bgp_alias2community(char *alias); -extern const char *bgp_alias2community_str(const char *str); +extern char *bgp_alias2community_str(const char *str); extern void bgp_community_alias_command_completion_setup(void); #endif /* FRR_BGP_COMMUNITY_ALIAS_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2b8a2eae3c..f97a791dae 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10728,12 +10728,14 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, const char *com2alias = bgp_community2alias( communities[i]); - if (strcmp(alias, com2alias) - == 0) { + if (!found + && strcmp(alias, com2alias) + == 0) found = true; - break; - } + XFREE(MTYPE_TMP, + communities[i]); } + XFREE(MTYPE_TMP, communities); } if (!found && pi->attr->lcommunity) { @@ -10743,12 +10745,14 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, const char *com2alias = bgp_community2alias( communities[i]); - if (strcmp(alias, com2alias) - == 0) { + if (!found + && strcmp(alias, com2alias) + == 0) found = true; - break; - } + XFREE(MTYPE_TMP, + communities[i]); } + XFREE(MTYPE_TMP, communities); } if (!found) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 11333516c2..5e566f360a 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1189,27 +1189,38 @@ route_match_alias(void *rule, const struct prefix *prefix, void *object) struct bgp_path_info *path = object; char **communities; int num; + bool found; if (path->attr->community) { + found = false; frrstr_split(path->attr->community->str, " ", &communities, &num); for (int i = 0; i < num; i++) { const char *com2alias = bgp_community2alias(communities[i]); - if (strcmp(alias, com2alias) == 0) - return RMAP_MATCH; + if (!found && strcmp(alias, com2alias) == 0) + found = true; + XFREE(MTYPE_TMP, communities[i]); } + XFREE(MTYPE_TMP, communities); + if (found) + return RMAP_MATCH; } if (path->attr->lcommunity) { + found = false; frrstr_split(path->attr->lcommunity->str, " ", &communities, &num); for (int i = 0; i < num; i++) { const char *com2alias = bgp_community2alias(communities[i]); - if (strcmp(alias, com2alias) == 0) - return RMAP_MATCH; + if (!found && strcmp(alias, com2alias) == 0) + found = true; + XFREE(MTYPE_TMP, communities[i]); } + XFREE(MTYPE_TMP, communities); + if (found) + return RMAP_MATCH; } return RMAP_NOMATCH; diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index a8bccecacf..286612da15 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -388,33 +388,25 @@ static int bgpd_sync_callback(struct thread *thread) afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { - struct peer *peer; - struct listnode *peer_listnode; - - for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { - safi_t safi; - - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - if (!peer->bgp->rib[afi][safi]) - continue; + safi_t safi; - struct bgp_dest *match; - struct bgp_dest *node; + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + if (!bgp->rib[afi][safi]) + continue; - match = bgp_table_subtree_lookup( - peer->bgp->rib[afi][safi], prefix); - node = match; + struct bgp_dest *match; + struct bgp_dest *node; - while (node) { - if (bgp_dest_has_bgp_path_info_data( - node)) { - revalidate_bgp_node(node, afi, - safi); - } + match = bgp_table_subtree_lookup(bgp->rib[afi][safi], + prefix); + node = match; - node = bgp_route_next_until(node, - match); + while (node) { + if (bgp_dest_has_bgp_path_info_data(node)) { + revalidate_bgp_node(node, afi, safi); } + + node = bgp_route_next_until(node, match); } } } @@ -429,7 +421,6 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, struct bgp_adj_in *ain; for (ain = bgp_dest->adj_in; ain; ain = ain->next) { - int ret; struct bgp_path_info *path = bgp_dest_get_bgp_path_info(bgp_dest); mpls_label_t *label = NULL; @@ -439,13 +430,10 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, label = path->extra->label; num_labels = path->extra->num_labels; } - ret = bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), + (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, num_labels, 1, NULL); - - if (ret < 0) - return; } } @@ -909,6 +897,12 @@ static int config_write(struct vty *vty) vty_out(vty, "!\n"); vty_out(vty, "rpki\n"); vty_out(vty, " rpki polling_period %d\n", polling_period); + + if (retry_interval != RETRY_INTERVAL_DEFAULT) + vty_out(vty, " rpki retry_interval %d\n", retry_interval); + if (expire_interval != EXPIRE_INTERVAL_DEFAULT) + vty_out(vty, " rpki expire_interval %d\n", expire_interval); + for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { switch (cache->type) { struct tr_tcp_config *tcp_config; diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 55ab493873..c090f3496a 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -258,6 +258,39 @@ Redistribute routes to OSPF6 argument injects the default route regardless of it being present in the router. Metric values and route-map can also be specified optionally. +Graceful Restart Helper +======================= + +.. clicmd:: graceful-restart helper-only [A.B.C.D] + + + Configure Graceful Restart (RFC 5187) 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. + +.. clicmd:: 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" + +.. clicmd:: graceful-restart helper supported-grace-time (10-1800) + + + Supports as HELPER for configured grace period. + +.. clicmd:: 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-ospf6-information: Showing OSPF6 information @@ -351,6 +384,19 @@ Showing OSPF6 information JSON object, with each router having "cost", "isLeafNode" and "children" as arguments. +.. clicmd:: show ipv6 ospf6 graceful-restart helper [detail] [json] + + This command shows the graceful-restart helper details including helper + configuration parameters. + +Debugging OSPF6 +=============== + +.. clicmd:: debug ospf6 graceful-restart + + This command enables/disables debug information for ospf6 graceful restart + helper functionality. + .. _ospf6-debugging: diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 6f9aa289b4..899a6b0078 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -93,7 +93,7 @@ Certain signals have special meanings to *pimd*. down. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. clicmd:: ip pim join-prune-interval (5-600) +.. clicmd:: ip pim join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -101,14 +101,14 @@ Certain signals have special meanings to *pimd*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ip pim keep-alive-timer (31-60000) +.. clicmd:: ip pim keep-alive-timer (1-65535) - Modify the time out value for a S,G flow from 31-60000 seconds. 31 seconds - is chosen for a lower bound because some hardware platforms cannot see data + Modify the time out value for a S,G flow from 1-60000 seconds. If choosing + a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. clicmd:: ip pim packets (1-100) +.. clicmd:: ip pim packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is @@ -116,7 +116,7 @@ Certain signals have special meanings to *pimd*. a large number of pim control packets flowing. This command is vrf aware, to configure for a vrf, enter the vrf submode. -.. clicmd:: ip pim register-suppress-time (5-60000) +.. clicmd:: ip pim register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a @@ -162,7 +162,7 @@ Certain signals have special meanings to *pimd*. the existing IGMP general query timer.If no version is provided in the cli, it will be considered as default v2 query.This is a hidden command. -.. clicmd:: ip igmp watermark-warn (10-60000) +.. clicmd:: ip igmp watermark-warn (1-65535) Configure watermark warning generation for an igmp group limit. Generates warning once the configured group limit is reached while adding new groups. @@ -201,7 +201,7 @@ is in a vrf, enter the interface command with the vrf keyword at the end. Set the DR Priority for the interface. This command is useful to allow the user to influence what node becomes the DR for a lan segment. -.. clicmd:: ip pim hello (1-180) (1-630) +.. clicmd:: ip pim hello (1-65535) (1-65535) Set the pim hello and hold interval for a interface. @@ -227,11 +227,11 @@ is in a vrf, enter the interface command with the vrf keyword at the end. Join multicast group or source-group on an interface. -.. clicmd:: ip igmp query-interval (1-1800) +.. clicmd:: ip igmp query-interval (1-65535) Set the IGMP query interval that PIM will use. -.. clicmd:: ip igmp query-max-response-time (10-250) +.. clicmd:: ip igmp query-max-response-time (1-65535) Set the IGMP query response timeout value. If an report is not returned in the specified time we will assume the S,G or \*,G has timed out. @@ -246,12 +246,12 @@ is in a vrf, enter the interface command with the vrf keyword at the end. or IGMP report is received on this interface and the Group is denied by the prefix-list, PIM will ignore the join or report. -.. clicmd:: ip igmp last-member-query-count (1-7) +.. clicmd:: ip igmp last-member-query-count (1-255) Set the IGMP last member query count. The default value is 2. 'no' form of this command is used to to configure back to the default value. -.. clicmd:: ip igmp last-member-query-interval (1-255) +.. clicmd:: ip igmp last-member-query-interval (1-65535) Set the IGMP last member query interval in deciseconds. The default value is 10 deciseconds. 'no' form of this command is used to to configure back to the @@ -319,17 +319,17 @@ MSDP can be setup in different ways: Commands available for MSDP: -.. clicmd:: ip msdp timers (2-600) (3-600) [(1-600)] +.. clicmd:: ip msdp timers (1-65535) (1-65535) [(1-65535)] Configure global MSDP timers. - First value is the keep-alive interval and it must be less than the - second value which is hold-time. This configures the interval in - seconds between keep-alive messages. The default value is 60 seconds. + First value is the keep-alive interval. This configures the interval in + seconds between keep-alive messages. The default value is 60 seconds. It + should be less than the remote hold time. - Second value is the hold-time and it must be greater than the keep-alive - interval. This configures the interval in seconds before closing a non - responding connection. The default value is 75. + Second value is the hold-time. This configures the interval in seconds before + closing a non responding connection. The default value is 75. This value + should be greater than the remote keep alive time. Third value is the connection retry interval and it is optional. This configures the interval between connection attempts. The default value diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 74a0d795ab..5888492a52 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -178,6 +178,13 @@ enum { RTM_GETVLAN, #define RTM_GETVLAN RTM_GETVLAN + RTM_NEWNEXTHOPBUCKET = 116, +#define RTM_NEWNEXTHOPBUCKET RTM_NEWNEXTHOPBUCKET + RTM_DELNEXTHOPBUCKET, +#define RTM_DELNEXTHOPBUCKET RTM_DELNEXTHOPBUCKET + RTM_GETNEXTHOPBUCKET, +#define RTM_GETNEXTHOPBUCKET RTM_GETNEXTHOPBUCKET + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -283,6 +290,7 @@ enum { #define RTPROT_MROUTED 17 /* Multicast daemon */ #define RTPROT_KEEPALIVED 18 /* Keepalived daemon */ #define RTPROT_BABEL 42 /* Babel daemon */ +#define RTPROT_OPENR 99 /* Open Routing (Open/R) Routes */ #define RTPROT_BGP 186 /* BGP Routes */ #define RTPROT_ISIS 187 /* ISIS Routes */ #define RTPROT_OSPF 188 /* OSPF Routes */ @@ -319,7 +327,11 @@ enum rt_scope_t { #define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */ #define RTM_F_OFFLOAD 0x4000 /* route is offloaded */ #define RTM_F_TRAP 0x8000 /* route is trapping packets */ -#define RTM_F_OFFLOAD_FAILED 0x10000 /* route offload failed */ +#define RTM_F_OFFLOAD_FAILED 0x20000000 /* route offload failed, this value + * is chosen to avoid conflicts with + * other flags defined in + * include/uapi/linux/ipv6_route.h + */ /* Reserved table identifiers */ @@ -397,11 +409,13 @@ struct rtnexthop { #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ #define RTNH_F_ONLINK 4 /* Gateway is forced on link */ -#define RTNH_F_OFFLOAD 8 /* offloaded route */ +#define RTNH_F_OFFLOAD 8 /* Nexthop is offloaded */ #define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ #define RTNH_F_UNRESOLVED 32 /* The entry is unresolved (ipmr) */ +#define RTNH_F_TRAP 64 /* Nexthop is trapping packets */ -#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) +#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | \ + RTNH_F_OFFLOAD | RTNH_F_TRAP) /* Macros to handle hexthops */ @@ -767,12 +781,18 @@ enum { #define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg)) /* tcamsg flags stored in attribute TCA_ROOT_FLAGS * - * TCA_FLAG_LARGE_DUMP_ON user->kernel to request for larger than TCA_ACT_MAX_PRIO - * actions in a dump. All dump responses will contain the number of actions - * being dumped stored in for user app's consumption in TCA_ROOT_COUNT + * TCA_ACT_FLAG_LARGE_DUMP_ON user->kernel to request for larger than + * TCA_ACT_MAX_PRIO actions in a dump. All dump responses will contain the + * number of actions being dumped stored in for user app's consumption in + * TCA_ROOT_COUNT + * + * TCA_ACT_FLAG_TERSE_DUMP user->kernel to request terse (brief) dump that only + * includes essential action info (kind, index, etc.) * */ #define TCA_FLAG_LARGE_DUMP_ON (1 << 0) +#define TCA_ACT_FLAG_LARGE_DUMP_ON TCA_FLAG_LARGE_DUMP_ON +#define TCA_ACT_FLAG_TERSE_DUMP (1 << 1) /* New extended info filters for IFLA_EXT_MASK */ #define RTEXT_FILTER_VF (1 << 0) @@ -780,6 +800,8 @@ enum { #define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) #define RTEXT_FILTER_SKIP_STATS (1 << 3) #define RTEXT_FILTER_MRP (1 << 4) +#define RTEXT_FILTER_CFM_CONFIG (1 << 5) +#define RTEXT_FILTER_CFM_STATUS (1 << 6) /* End of information exported to user level */ diff --git a/lib/command.h b/lib/command.h index 2b50bc2374..c76fc1e8eb 100644 --- a/lib/command.h +++ b/lib/command.h @@ -389,6 +389,7 @@ struct cmd_node { #define SRTE_STR "SR-TE information\n" #define SRTE_COLOR_STR "SR-TE Color information\n" #define NO_STR "Negate a command or set its defaults\n" +#define IGNORED_IN_NO_STR "Ignored value in no form\n" #define REDIST_STR "Redistribute information from another routing protocol\n" #define CLEAR_STR "Reset functions\n" #define RIP_STR "RIP information\n" diff --git a/lib/filter.h b/lib/filter.h index 941fabd38b..d1956ec019 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -207,11 +207,10 @@ struct plist_dup_args { /** Entry action. */ const char *pda_action; -#define PDA_MAX_VALUES 4 - /** Entry XPath for value. */ - const char *pda_xpath[PDA_MAX_VALUES]; - /** Entry value to match. */ - const char *pda_value[PDA_MAX_VALUES]; + bool any; + struct prefix prefix; + int ge; + int le; /** Duplicated entry found in list? */ bool pda_found; diff --git a/lib/filter_cli.c b/lib/filter_cli.c index f030ce1b33..45c7544a3b 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -1196,11 +1196,9 @@ static int plist_remove_if_empty(struct vty *vty, const char *iptype, static int plist_remove(struct vty *vty, const char *iptype, const char *name, const char *seq, const char *action, - const char *prefix_str, const char *ge_str, - const char *le_str) + union prefixconstptr prefix, int ge, int le) { int64_t sseq; - int arg_idx = 0; struct plist_dup_args pda = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 32]; @@ -1225,43 +1223,13 @@ static int plist_remove(struct vty *vty, const char *iptype, const char *name, pda.pda_type = iptype; pda.pda_name = name; pda.pda_action = action; - if (prefix_str) { - if (strmatch(iptype, "ipv4")) { - pda.pda_xpath[arg_idx] = "./ipv4-prefix"; - pda.pda_value[arg_idx] = prefix_str; - arg_idx++; - if (ge_str) { - pda.pda_xpath[arg_idx] = - "./ipv4-prefix-length-greater-or-equal"; - pda.pda_value[arg_idx] = ge_str; - arg_idx++; - } - if (le_str) { - pda.pda_xpath[arg_idx] = - "./ipv4-prefix-length-lesser-or-equal"; - pda.pda_value[arg_idx] = le_str; - arg_idx++; - } - } else { - pda.pda_xpath[arg_idx] = "./ipv6-prefix"; - pda.pda_value[arg_idx] = prefix_str; - arg_idx++; - if (ge_str) { - pda.pda_xpath[arg_idx] = - "./ipv6-prefix-length-greater-or-equal"; - pda.pda_value[arg_idx] = ge_str; - arg_idx++; - } - if (le_str) { - pda.pda_xpath[arg_idx] = - "./ipv6-prefix-length-lesser-or-equal"; - pda.pda_value[arg_idx] = le_str; - arg_idx++; - } - } + if (prefix.p) { + prefix_copy(&pda.prefix, prefix); + apply_mask(&pda.prefix); + pda.ge = ge; + pda.le = le; } else { - pda.pda_xpath[0] = "./any"; - pda.pda_value[0] = ""; + pda.any = true; } if (plist_is_dup(vty->candidate_config->dnode, &pda)) @@ -1298,7 +1266,6 @@ DEFPY_YANG( "Maximum prefix length\n") { int64_t sseq; - int arg_idx = 0; struct plist_dup_args pda = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; @@ -1312,24 +1279,11 @@ DEFPY_YANG( pda.pda_name = name; pda.pda_action = action; if (prefix_str) { - pda.pda_xpath[arg_idx] = "./ipv4-prefix"; - pda.pda_value[arg_idx] = prefix_str; - arg_idx++; - if (ge_str) { - pda.pda_xpath[arg_idx] = - "./ipv4-prefix-length-greater-or-equal"; - pda.pda_value[arg_idx] = ge_str; - arg_idx++; - } - if (le_str) { - pda.pda_xpath[arg_idx] = - "./ipv4-prefix-length-lesser-or-equal"; - pda.pda_value[arg_idx] = le_str; - arg_idx++; - } + prefix_copy(&pda.prefix, prefix); + pda.ge = ge; + pda.le = le; } else { - pda.pda_xpath[0] = "./any"; - pda.pda_value[0] = ""; + pda.any = true; } /* Duplicated entry without sequence, just quit. */ @@ -1408,8 +1362,8 @@ DEFPY_YANG( "Maximum prefix length to be matched\n" "Maximum prefix length\n") { - return plist_remove(vty, "ipv4", name, seq_str, action, prefix_str, - ge_str, le_str); + return plist_remove(vty, "ipv4", name, seq_str, action, + prefix_str ? prefix : NULL, ge, le); } DEFPY_YANG( @@ -1421,7 +1375,7 @@ DEFPY_YANG( PREFIX_LIST_NAME_STR ACCESS_LIST_SEQ_STR) { - return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, NULL, NULL); + return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0); } DEFPY_YANG( @@ -1516,7 +1470,6 @@ DEFPY_YANG( "Minimum prefix length\n") { int64_t sseq; - int arg_idx = 0; struct plist_dup_args pda = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; @@ -1530,24 +1483,11 @@ DEFPY_YANG( pda.pda_name = name; pda.pda_action = action; if (prefix_str) { - pda.pda_xpath[arg_idx] = "./ipv6-prefix"; - pda.pda_value[arg_idx] = prefix_str; - arg_idx++; - if (ge_str) { - pda.pda_xpath[arg_idx] = - "./ipv6-prefix-length-greater-or-equal"; - pda.pda_value[arg_idx] = ge_str; - arg_idx++; - } - if (le_str) { - pda.pda_xpath[arg_idx] = - "./ipv6-prefix-length-lesser-or-equal"; - pda.pda_value[arg_idx] = le_str; - arg_idx++; - } + prefix_copy(&pda.prefix, prefix); + pda.ge = ge; + pda.le = le; } else { - pda.pda_xpath[0] = "./any"; - pda.pda_value[0] = ""; + pda.any = true; } /* Duplicated entry without sequence, just quit. */ @@ -1626,8 +1566,8 @@ DEFPY_YANG( "Minimum prefix length to be matched\n" "Minimum prefix length\n") { - return plist_remove(vty, "ipv6", name, seq_str, action, prefix_str, - ge_str, le_str); + return plist_remove(vty, "ipv6", name, seq_str, action, + prefix_str ? prefix : NULL, ge, le); } DEFPY_YANG( @@ -1639,7 +1579,7 @@ DEFPY_YANG( PREFIX_LIST_NAME_STR ACCESS_LIST_SEQ_STR) { - return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, NULL, NULL); + return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0); } DEFPY_YANG( diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 85805ffa47..80ea7a57cb 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -387,10 +387,50 @@ static bool acl_zebra_is_dup(const struct lyd_node *dnode, return acl_is_dup(entry_dnode, &ada); } +static void plist_dnode_to_prefix(const struct lyd_node *dnode, bool *any, + struct prefix *p, int *ge, int *le) +{ + *any = false; + *ge = 0; + *le = 0; + + if (yang_dnode_exists(dnode, "./any")) { + *any = true; + return; + } + + switch (yang_dnode_get_enum(dnode, "../type")) { + case YPLT_IPV4: + yang_dnode_get_prefix(p, dnode, "./ipv4-prefix"); + if (yang_dnode_exists(dnode, + "./ipv4-prefix-length-greater-or-equal")) + *ge = yang_dnode_get_uint8( + dnode, "./ipv4-prefix-length-greater-or-equal"); + if (yang_dnode_exists(dnode, + "./ipv4-prefix-length-lesser-or-equal")) + *le = yang_dnode_get_uint8( + dnode, "./ipv4-prefix-length-lesser-or-equal"); + break; + case YPLT_IPV6: + yang_dnode_get_prefix(p, dnode, "./ipv6-prefix"); + if (yang_dnode_exists(dnode, + "./ipv6-prefix-length-greater-or-equal")) + *ge = yang_dnode_get_uint8( + dnode, "./ipv6-prefix-length-greater-or-equal"); + if (yang_dnode_exists(dnode, + "./ipv6-prefix-length-lesser-or-equal")) + *le = yang_dnode_get_uint8( + dnode, "./ipv6-prefix-length-lesser-or-equal"); + break; + } +} + static int _plist_is_dup(const struct lyd_node *dnode, void *arg) { struct plist_dup_args *pda = arg; - int idx; + struct prefix p; + int ge, le; + bool any; /* This entry is the caller, so skip it. */ if (pda->pda_entry_dnode @@ -400,19 +440,14 @@ static int _plist_is_dup(const struct lyd_node *dnode, void *arg) if (strcmp(yang_dnode_get_string(dnode, "action"), pda->pda_action)) return YANG_ITER_CONTINUE; - /* Check if all values match. */ - for (idx = 0; idx < PDA_MAX_VALUES; idx++) { - /* No more values. */ - if (pda->pda_xpath[idx] == NULL) - break; + plist_dnode_to_prefix(dnode, &any, &p, &ge, &le); - /* Not same type, just skip it. */ - if (!yang_dnode_exists(dnode, pda->pda_xpath[idx])) + if (pda->any) { + if (!any) return YANG_ITER_CONTINUE; - - /* Check if different value. */ - if (strcmp(yang_dnode_get_string(dnode, pda->pda_xpath[idx]), - pda->pda_value[idx])) + } else { + if (!prefix_same(&pda->prefix, &p) || pda->ge != ge + || pda->le != le) return YANG_ITER_CONTINUE; } @@ -439,17 +474,6 @@ static bool plist_is_dup_nb(const struct lyd_node *dnode) const struct lyd_node *entry_dnode = yang_dnode_get_parent(dnode, "entry"); struct plist_dup_args pda = {}; - int idx = 0, arg_idx = 0; - static const char *entries[] = { - "./ipv4-prefix", - "./ipv4-prefix-length-greater-or-equal", - "./ipv4-prefix-length-lesser-or-equal", - "./ipv6-prefix", - "./ipv6-prefix-length-greater-or-equal", - "./ipv6-prefix-length-lesser-or-equal", - "./any", - NULL - }; /* Initialize. */ pda.pda_type = yang_dnode_get_string(entry_dnode, "../type"); @@ -457,19 +481,8 @@ static bool plist_is_dup_nb(const struct lyd_node *dnode) pda.pda_action = yang_dnode_get_string(entry_dnode, "action"); pda.pda_entry_dnode = entry_dnode; - /* Load all values/XPaths. */ - while (entries[idx] != NULL) { - if (!yang_dnode_exists(entry_dnode, entries[idx])) { - idx++; - continue; - } - - pda.pda_xpath[arg_idx] = entries[idx]; - pda.pda_value[arg_idx] = - yang_dnode_get_string(entry_dnode, entries[idx]); - arg_idx++; - idx++; - } + plist_dnode_to_prefix(entry_dnode, &pda.any, &pda.prefix, &pda.ge, + &pda.le); return plist_is_dup(entry_dnode, &pda); } diff --git a/lib/routemap.c b/lib/routemap.c index 5d45dc1047..594dcf97cb 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1431,7 +1431,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, * the same as the existing configuration then, * ignore the duplicate configuration. */ - if (strcmp(match_arg, rule->rule_str) == 0) { + if (rulecmp(match_arg, rule->rule_str) == 0) { if (cmd->func_free) (*cmd->func_free)(compile); diff --git a/lib/subdir.am b/lib/subdir.am index 714af43238..dab5fb9e83 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -144,7 +144,6 @@ vtysh_scan += \ lib/log_vty.c \ lib/nexthop_group.c \ lib/plist.c \ - lib/resolver.c \ lib/routemap.c \ lib/routemap_cli.c \ lib/spf_backoff.c \ @@ -335,6 +334,7 @@ lib_libfrrsnmp_la_SOURCES = \ if CARES lib_LTLIBRARIES += lib/libfrrcares.la pkginclude_HEADERS += lib/resolver.h +vtysh_scan += lib/resolver.c endif lib_libfrrcares_la_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index b7cbc13b72..5cf879b8cf 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1514,8 +1514,6 @@ static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6, uint32_t id) { struct ospf6_lsa *lsa; - struct ospf6_area *oa; - struct listnode *lnode; lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), htonl(id), ospf6->router_id, ospf6->lsdb); @@ -1524,20 +1522,6 @@ static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6, ospf6_external_lsa_purge(ospf6, lsa); - /* Delete the NSSA LSA */ - for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { - lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), - htonl(id), ospf6->router_id, - oa->lsdb); - if (lsa) { - if (IS_OSPF6_DEBUG_ASBR) - zlog_debug("withdraw type 7 lsa, LS ID: %u", - htonl(id)); - - ospf6_lsa_purge(lsa); - } - } - } static void @@ -2715,21 +2699,47 @@ void ospf6_fill_aggr_route_details(struct ospf6 *ospf6, rt_aggr->path.origin.id = htonl(aggr->id); } +static void +ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr) +{ + struct ospf6_route *rt_aggr; + struct ospf6_external_info *info; + + /* Create summary route and save it. */ + rt_aggr = ospf6_route_create(ospf6); + rt_aggr->type = OSPF6_DEST_TYPE_NETWORK; + /* Needed to install route while calling zebra api */ + SET_FLAG(rt_aggr->flag, OSPF6_ROUTE_BEST); + + info = XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO, sizeof(*info)); + rt_aggr->route_option = info; + aggr->route = rt_aggr; + + /* Prepare the external_info for aggregator + * Fill all the details which will get advertised + */ + ospf6_fill_aggr_route_details(ospf6, aggr); + + /* Add next-hop to Null interface. */ + ospf6_add_route_nexthop_blackhole(rt_aggr); + + ospf6_zebra_route_update_add(rt_aggr, ospf6); +} + static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr) { - struct prefix prefix_id; struct route_node *node; struct ospf6_lsa *lsa = NULL; - struct ospf6_route *rt_aggr; - struct ospf6_external_info *info; if (IS_OSPF6_DEBUG_AGGR) zlog_debug("%s: Originate new aggregate route(%pFX)", __func__, &aggr->p); aggr->id = ospf6->external_id++; + /* create/update binding in external_id_table */ prefix_id.family = AF_INET; prefix_id.prefixlen = 32; @@ -2742,28 +2752,10 @@ static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, "Advertise AS-External Id:%pI4 prefix %pFX metric %u", &prefix_id.u.prefix4, &aggr->p, aggr->metric); - /* Create summary route and save it. */ - rt_aggr = ospf6_route_create(ospf6); - rt_aggr->type = OSPF6_DEST_TYPE_NETWORK; - /* Needed to install route while calling zebra api */ - SET_FLAG(rt_aggr->flag, OSPF6_ROUTE_BEST); - - info = XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO, sizeof(*info)); - rt_aggr->route_option = info; - aggr->route = rt_aggr; - - /* Prepare the external_info for aggregator - * Fill all the details which will get advertised - */ - ospf6_fill_aggr_route_details(ospf6, aggr); - - /* Add next-hop to Null interface. */ - ospf6_add_route_nexthop_blackhole(rt_aggr); - - ospf6_zebra_route_update_add(rt_aggr, ospf6); + ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr); /* Originate summary LSA */ - lsa = ospf6_originate_type5_type7_lsas(rt_aggr, ospf6); + lsa = ospf6_originate_type5_type7_lsas(aggr->route, ospf6); if (lsa) { if (IS_OSPF6_DEBUG_AGGR) zlog_debug("%s: Set the origination bit for aggregator", @@ -2842,12 +2834,10 @@ ospf6_originate_summary_lsa(struct ospf6 *ospf6, /* The key for ID field is a running number and not prefix */ info = rt->route_option; assert(info); - if (info->id) { + if (info->id) lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), htonl(info->id), ospf6->router_id, ospf6->lsdb); - assert(lsa); - } aggr_lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), htonl(aggr->id), ospf6->router_id, ospf6->lsdb); @@ -2939,20 +2929,22 @@ ospf6_originate_summary_lsa(struct ospf6 *ospf6, /* If the external route prefix same as aggregate route * and if external route is already originated as TYPE-5 - * then it need to be refreshed and originate bit should - * be set. + * then just update the aggr info and remove the route info */ if (lsa && prefix_same(&aggr->p, &rt->prefix)) { if (IS_OSPF6_DEBUG_AGGR) - zlog_debug("%s: External route prefix is same as aggr so refreshing LSA(%pFX)", - __PRETTY_FUNCTION__, - &aggr->p); + zlog_debug( + "%s: Route prefix is same as aggr so no need to re-originate LSA(%pFX)", + __PRETTY_FUNCTION__, &aggr->p); - THREAD_OFF(lsa->refresh); - thread_add_event(master, ospf6_lsa_refresh, lsa, 0, - &lsa->refresh); aggr->id = info->id; + info->id = 0; + rt->path.origin.id = 0; + + ospf6_summary_add_aggr_route_and_blackhole(ospf6, aggr); + SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED); + return; } diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 3d52597161..f13ed3e3bb 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -41,6 +41,7 @@ #include "ospf6_flood.h" #include "ospf6_nssa.h" +#include "ospf6_gr.h" unsigned char conf_debug_ospf6_flooding; @@ -169,9 +170,26 @@ void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6, void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa) { + uint32_t id = lsa->header->id; + struct ospf6_area *oa; + struct listnode *lnode; + ospf6_lsa_purge(lsa); - ospf6_remove_id_from_external_id_table(ospf6, lsa->header->id); + ospf6_remove_id_from_external_id_table(ospf6, id); + + /* Delete the corresponding NSSA LSA */ + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), id, + ospf6->router_id, oa->lsdb); + if (lsa) { + if (IS_OSPF6_DEBUG_NSSA) + zlog_debug("withdraw type 7 lsa, LS ID: %u", + htonl(id)); + + ospf6_lsa_purge(lsa); + } + } } void ospf6_lsa_purge(struct ospf6_lsa *lsa) @@ -306,6 +324,22 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa) /* actually install */ lsa->installed = now; + + /* Topo change handling */ + if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))) { + + /* check if it is new lsa ? or existing lsa got modified ?*/ + if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) { + struct ospf6 *ospf6; + + ospf6 = ospf6_get_by_lsdb(lsa); + + assert(ospf6); + + ospf6_helper_handle_topo_chg(ospf6, lsa); + } + } + ospf6_lsdb_add(lsa, lsa->lsdb); if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) { @@ -999,6 +1033,50 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from, != from->ospf6_if->area->ospf6->router_id) ospf6_flood(from, new); + /* Received Grace-LSA */ + if (IS_GRACE_LSA(new)) { + struct ospf6 *ospf6; + + ospf6 = ospf6_get_by_lsdb(new); + + assert(ospf6); + + if (OSPF6_LSA_IS_MAXAGE(new)) { + + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Received a maxage GraceLSA from router %pI4", + __func__, + &new->header->adv_router); + if (old) { + ospf6_process_maxage_grace_lsa( + ospf6, new, from); + } else { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, GraceLSA doesn't exist in lsdb, so discarding GraceLSA", + __func__); + return; + } + } else { + + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Received a GraceLSA from router %pI4", + __func__, + &new->header->adv_router); + + if (ospf6_process_grace_lsa(ospf6, new, from) + == OSPF6_GR_NOT_HELPER) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Not moving to HELPER role, So dicarding GraceLSA", + __func__); + return; + } + } + } + /* (d), installing lsdb, which may cause routing table calculation (replacing database copy) */ ospf6_install_lsa(new); diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h new file mode 100644 index 0000000000..378b7193cd --- /dev/null +++ b/ospf6d/ospf6_gr.h @@ -0,0 +1,161 @@ +/* + * OSPF6 Graceful Retsart helper functions. + * + * Copyright (C) 2021-22 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 OSPF6_GR_H +#define OSPF6_GR_H + +#define OSPF6_GR_NOT_HELPER 0 +#define OSPF6_GR_ACTIVE_HELPER 1 + +#define OSPF6_GR_HELPER_NO_LSACHECK 0 +#define OSPF6_GR_HELPER_LSACHECK 1 + +#define OSPF6_MAX_GRACE_INTERVAL 1800 +#define OSPF6_MIN_GRACE_INTERVAL 1 + +/* Debug option */ +extern unsigned char conf_debug_ospf6_gr; + +#define OSPF6_DEBUG_GR 0x01 + +#define OSPF6_DEBUG_GR_ON() (conf_debug_ospf6_gr |= OSPF6_DEBUG_GR) + +#define OSPF6_DEBUG_GR_OFF() (conf_debug_ospf6_gr &= ~OSPF6_DEBUG_GR) + +#define IS_DEBUG_OSPF6_GR conf_debug_ospf6_gr + + +enum ospf6_helper_exit_reason { + OSPF6_GR_HELPER_EXIT_NONE = 0, + OSPF6_GR_HELPER_INPROGRESS, + OSPF6_GR_HELPER_TOPO_CHG, + OSPF6_GR_HELPER_GRACE_TIMEOUT, + OSPF6_GR_HELPER_COMPLETED +}; + +enum ospf6_gr_restart_reason { + OSPF6_GR_UNKNOWN_RESTART = 0, + OSPF6_GR_SW_RESTART = 1, + OSPF6_GR_SW_UPGRADE = 2, + OSPF6_GR_SWITCH_REDUNDANT_CARD = 3, + OSPF6_GR_INVALID_REASON_CODE = 4 +}; + +enum ospf6_gr_helper_rejected_reason { + OSPF6_HELPER_REJECTED_NONE, + OSPF6_HELPER_SUPPORT_DISABLED, + OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR, + OSPF6_HELPER_PLANNED_ONLY_RESTART, + OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST, + OSPF6_HELPER_LSA_AGE_MORE +}; + +#ifdef roundup +#define ROUNDUP(val, gran) roundup(val, gran) +#else /* roundup */ +#define ROUNDUP(val, gran) (((val)-1 | (gran)-1) + 1) +#endif /* roundup */ + +/* + * Generic TLV (type, length, value) macros + */ +struct tlv_header { + uint16_t type; /* Type of Value */ + uint16_t length; /* Length of Value portion only, in bytes */ +}; + +#define TLV_HDR_SIZE (sizeof(struct tlv_header)) + +#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t))) + +#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) + +#define TLV_HDR_TOP(lsah) \ + (struct tlv_header *)((char *)(lsah) + OSPF6_LSA_HEADER_SIZE) + +#define TLV_HDR_NEXT(tlvh) \ + (struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) + +/* Ref RFC5187 appendix-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; +}; +#define GRACE_PERIOD_TLV_SIZE sizeof(struct grace_tlv_graceperiod) + +/* 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]; +}; +#define GRACE_RESTART_REASON_TLV_SIZE sizeof(struct grace_tlv_restart_reason) + +#define OSPF6_GRACE_LSA_MIN_SIZE \ + GRACE_PERIOD_TLV_SIZE + GRACE_RESTART_REASON_TLV_SIZE + +struct advRtr { + in_addr_t advRtrAddr; +}; + +#define OSPF6_HELPER_ENABLE_RTR_COUNT(ospf) \ + (ospf6->ospf6_helper_cfg.enable_rtr_list->count) + +/* Check , it is a planned restart */ +#define OSPF6_GR_IS_PLANNED_RESTART(reason) \ + ((reason == OSPF6_GR_SW_RESTART) || (reason == OSPF6_GR_SW_UPGRADE)) + +/* Check the router is HELPER for current neighbour */ +#define OSPF6_GR_IS_ACTIVE_HELPER(N) \ + ((N)->gr_helper_info.gr_helper_status == OSPF6_GR_ACTIVE_HELPER) + +/* Check the LSA is GRACE LSA */ +#define IS_GRACE_LSA(lsa) (ntohs(lsa->header->type) == OSPF6_LSTYPE_GRACE_LSA) + +/* Check neighbour is in FULL state */ +#define IS_NBR_STATE_FULL(nbr) (nbr->state == OSPF6_NEIGHBOR_FULL) + +extern const char *ospf6_exit_reason_desc[]; +extern const char *ospf6_restart_reason_desc[]; +extern const char *ospf6_rejected_reason_desc[]; + +extern void ospf6_gr_helper_config_init(void); +extern void ospf6_gr_helper_init(struct ospf6 *ospf6); +extern void ospf6_gr_helper_deinit(struct ospf6 *ospf6); +extern void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, + enum ospf6_helper_exit_reason reason); +extern int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, + struct ospf6_neighbor *nbr); +extern void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf, + struct ospf6_lsa *lsa, + struct ospf6_neighbor *nbr); +extern void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, + struct ospf6_lsa *lsa); +extern int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6); +extern int config_write_ospf6_debug_gr_helper(struct vty *vty); +#endif /* OSPF6_GR_H */ diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c new file mode 100644 index 0000000000..07e479efcb --- /dev/null +++ b/ospf6d/ospf6_gr_helper.c @@ -0,0 +1,1375 @@ +/* + * OSPF6 Graceful Restart helper functions. + * + * Copyright (C) 2021-22 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 "log.h" +#include "vty.h" +#include "command.h" +#include "prefix.h" +#include "stream.h" +#include "zclient.h" +#include "memory.h" +#include "table.h" +#include "lib/bfd.h" +#include "lib_errors.h" +#include "jhash.h" + +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_message.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_intra.h" +#include "ospf6d.h" +#include "ospf6_gr.h" +#include "lib/json.h" +#ifndef VTYSH_EXTRACT_PL +#include "ospf6d/ospf6_gr_helper_clippy.c" +#endif + +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper"); + +unsigned char conf_debug_ospf6_gr; + +static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, + json_object *json, bool use_json); + +struct ospf6_lsa_handler grace_lsa_handler = {.lh_type = OSPF6_LSTYPE_GRACE_LSA, + .lh_name = "Grace", + .lh_short_name = "GR", + .lh_show = + ospf6_grace_lsa_show_info, + .lh_get_prefix_str = NULL, + .lh_debug = 0}; + +const char *ospf6_exit_reason_desc[] = { + "Unknown reason", + "Helper in progress", + "Topology Change", + "Grace timer expiry", + "Successful graceful restart", +}; + +const char *ospf6_restart_reason_desc[] = { + "Unknown restart", + "Software restart", + "Software reload/upgrade", + "Switch to redundant control processor", +}; + +const char *ospf6_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 unsigned int ospf6_enable_rtr_hash_key(const void *data) +{ + const struct advRtr *rtr = data; + + return jhash_1word(rtr->advRtrAddr, 0); +} + +static bool ospf6_enable_rtr_hash_cmp(const void *d1, const void *d2) +{ + const struct advRtr *rtr1 = d1; + const struct advRtr *rtr2 = d2; + + return (rtr1->advRtrAddr == rtr2->advRtrAddr); +} + +static void *ospf6_enable_rtr_hash_alloc(void *p) +{ + struct advRtr *rid; + + rid = XCALLOC(MTYPE_OSPF6_GR_HELPER, sizeof(struct advRtr)); + rid->advRtrAddr = ((struct advRtr *)p)->advRtrAddr; + + return rid; +} + +static void ospf6_disable_rtr_hash_free(void *rtr) +{ + XFREE(MTYPE_OSPF6_GR_HELPER, rtr); +} + +static void ospf6_enable_rtr_hash_destroy(struct ospf6 *ospf6) +{ + if (ospf6->ospf6_helper_cfg.enable_rtr_list == NULL) + return; + + hash_clean(ospf6->ospf6_helper_cfg.enable_rtr_list, + ospf6_disable_rtr_hash_free); + hash_free(ospf6->ospf6_helper_cfg.enable_rtr_list); + ospf6->ospf6_helper_cfg.enable_rtr_list = NULL; +} + +/* + * Extracting tlv info from GRACE LSA. + * + * lsa + * ospf6 grace lsa + * + * Returns: + * interval : grace interval. + * reason : Restarting reason. + */ +static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, + uint32_t *interval, uint8_t *reason) +{ + struct ospf6_lsa_header *lsah = NULL; + struct tlv_header *tlvh = NULL; + struct grace_tlv_graceperiod *gracePeriod; + struct grace_tlv_restart_reason *grReason; + uint16_t length = 0; + int sum = 0; + + lsah = (struct ospf6_lsa_header *)lsa->header; + + length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE; + + 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; + *interval = ntohl(gracePeriod->interval); + sum += TLV_SIZE(tlvh); + + /* Check if grace interval is valid */ + if (*interval > OSPF6_MAX_GRACE_INTERVAL + || *interval < OSPF6_MIN_GRACE_INTERVAL) + return OSPF6_FAILURE; + break; + case RESTART_REASON_TYPE: + grReason = (struct grace_tlv_restart_reason *)tlvh; + *reason = grReason->reason; + sum += TLV_SIZE(tlvh); + + if (*reason >= OSPF6_GR_INVALID_REASON_CODE) + return OSPF6_FAILURE; + break; + default: + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Ignoring unknown TLV type:%d", + __func__, ntohs(tlvh->type)); + } + } + + return OSPF6_SUCCESS; +} + +/* + * Grace timer expiry handler. + * HELPER aborts its role at grace timer expiry. + * + * thread + * thread pointer + * + * Returns: + * Nothing + */ +static int ospf6_handle_grace_timer_expiry(struct thread *thread) +{ + struct ospf6_neighbor *nbr = THREAD_ARG(thread); + + nbr->gr_helper_info.t_grace_timer = NULL; + + ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT); + return OSPF6_SUCCESS; +} + +/* + * API to check any change in the neighbor's + * retransmission list. + * + * nbr + * ospf6 neighbor + * + * Returns: + * TRUE - if any change in the lsa. + * FALSE - no change in the lsas. + */ +static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor *nbr) +{ + struct ospf6_lsa *lsa, *lsanext; + + for (ALL_LSDB(nbr->retrans_list, lsa, lsanext)) { + struct ospf6_lsa *lsa_in_db = NULL; + + /* Fetching the same copy of LSA form LSDB to validate the + * topochange. + */ + lsa_in_db = + ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, + lsa->header->adv_router, lsa->lsdb); + + if (lsa_in_db && lsa_in_db->tobe_acknowledged) + return OSPF6_TRUE; + } + + return OSPF6_FALSE; +} + +/* + * Process Grace LSA.If it is eligible move to HELPER role. + * Ref rfc3623 section 3.1 and rfc5187 + * + * ospf + * Ospf6 pointer. + * + * lsa + * Grace LSA received from RESTARTER. + * + * restarter + * ospf6 neighbour which requests 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 ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, + struct ospf6_neighbor *restarter) +{ + uint8_t restart_reason = 0; + uint32_t grace_interval = 0; + uint32_t actual_grace_interval = 0; + struct advRtr lookup; + int ret; + + /* Extract the grace lsa packet fields */ + ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval, + &restart_reason); + if (ret != OSPF6_SUCCESS) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Wrong Grace LSA packet.", __func__); + return OSPF6_GR_NOT_HELPER; + } + + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Grace LSA received from %pI4, grace interval:%u, restart reason :%s", + __func__, &restarter->router_id, grace_interval, + ospf6_restart_reason_desc[restart_reason]); + + /* Verify Helper enabled globally */ + if (!ospf6->ospf6_helper_cfg.is_helper_supported) { + /* Verify Helper support is enabled for the + * current neighbour router-id. + */ + lookup.advRtrAddr = restarter->router_id; + + if (!hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list, + &lookup)) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, HELPER support is disabled, So not a HELPER", + __func__); + restarter->gr_helper_info.rejected_reason = + OSPF6_HELPER_SUPPORT_DISABLED; + return OSPF6_GR_NOT_HELPER; + } + } + + /* Check neighbour is in FULL state and + * became a adjacency. + */ + if (!IS_NBR_STATE_FULL(restarter)) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, This Neighbour %pI6 is not in FULL state.", + __func__, &restarter->linklocal_addr); + restarter->gr_helper_info.rejected_reason = + OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR; + return OSPF6_GR_NOT_HELPER; + } + + /* Based on the restart reason from grace lsa + * check the current router is supporting or not + */ + if (ospf6->ospf6_helper_cfg.only_planned_restart + && !OSPF6_GR_IS_PLANNED_RESTART(restart_reason)) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Router supports only planned restarts but received the GRACE LSA due a unplanned restart", + __func__); + restarter->gr_helper_info.rejected_reason = + OSPF6_HELPER_PLANNED_ONLY_RESTART; + return OSPF6_GR_NOT_HELPER; + } + + /* Check the retransmission list of this + * neighbour, check any change in lsas. + */ + if (ospf6->ospf6_helper_cfg.strict_lsa_check + && restarter->retrans_list->count + && ospf6_check_chg_in_rxmt_list(restarter)) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Changed LSA in Rxmt list.So not Helper.", + __func__); + restarter->gr_helper_info.rejected_reason = + OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST; + return OSPF6_GR_NOT_HELPER; + } + + /* LSA age must be less than the grace period */ + if (ntohs(lsa->header->age) >= grace_interval) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Grace LSA age(%d) is more than the grace interval(%d)", + __func__, lsa->header->age, grace_interval); + restarter->gr_helper_info.rejected_reason = + OSPF6_HELPER_LSA_AGE_MORE; + return OSPF6_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 > ospf6->ospf6_helper_cfg.supported_grace_time) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Received grace period %d is larger than supported grace %d", + __func__, grace_interval, + ospf6->ospf6_helper_cfg.supported_grace_time); + actual_grace_interval = + ospf6->ospf6_helper_cfg.supported_grace_time; + } + + if (OSPF6_GR_IS_ACTIVE_HELPER(restarter)) { + if (restarter->gr_helper_info.t_grace_timer) + THREAD_OFF(restarter->gr_helper_info.t_grace_timer); + + if (ospf6->ospf6_helper_cfg.active_restarter_cnt > 0) + ospf6->ospf6_helper_cfg.active_restarter_cnt--; + + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Router is already acting as a HELPER for this nbr,so restart the grace timer", + __func__); + } else { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, This Router becomes a HELPER for the neighbour %pI6", + __func__, &restarter->linklocal_addr); + } + + /* Became a Helper to the RESTART neighbour. + * change the helper status. + */ + restarter->gr_helper_info.gr_helper_status = OSPF6_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 = OSPF6_HELPER_REJECTED_NONE; + + /* Increment the active restart nbr count */ + ospf6->ospf6_helper_cfg.active_restarter_cnt++; + + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Grace timer started.interval:%u", __func__, + actual_grace_interval); + + /* Start the grace timer */ + thread_add_timer(master, ospf6_handle_grace_timer_expiry, restarter, + actual_grace_interval, + &restarter->gr_helper_info.t_grace_timer); + + return OSPF6_GR_ACTIVE_HELPER; +} + +/* + * Api to exit from HELPER role to take all actions + * required at exit. + * Ref rfc3623 section 3. and rfc51872 + * + * ospf6 + * Ospf6 pointer. + * + * nbr + * Ospf6 neighbour for which it is acting as HELPER. + * + * reason + * The reason for exiting from HELPER. + * + * Returns: + * Nothing. + */ +void ospf6_gr_helper_exit(struct ospf6_neighbor *nbr, + enum ospf6_helper_exit_reason reason) +{ + struct ospf6_interface *oi = nbr->ospf6_if; + struct ospf6 *ospf6; + + if (!oi) + return; + + ospf6 = oi->area->ospf6; + + if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr)) + return; + + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Exiting from HELPER support to %pI6, due to %s", + __func__, &nbr->linklocal_addr, + ospf6_exit_reason_desc[reason]); + + /* Reset helper status*/ + nbr->gr_helper_info.gr_helper_status = OSPF6_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; + ospf6->ospf6_helper_cfg.last_exit_reason = reason; + + /* If the exit not triggered due to grace timer + * expiry, stop the grace timer. + */ + if (reason != OSPF6_GR_HELPER_GRACE_TIMEOUT) + THREAD_OFF(nbr->gr_helper_info.t_grace_timer); + + if (ospf6->ospf6_helper_cfg.active_restarter_cnt <= 0) { + zlog_err( + "OSPF6 GR-Helper: Number of active Restarters should be greater than zero."); + return; + } + /* Decrement active restarter count */ + ospf6->ospf6_helper_cfg.active_restarter_cnt--; + + /* check exit triggered due to successful completion + * of graceful restart. + */ + if (reason != OSPF6_GR_HELPER_COMPLETED) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Unsuccessful GR exit. RESTARTER : %pI6", + __func__, &nbr->linklocal_addr); + } + + /*Recalculate the DR for the network segment */ + dr_election(oi); + + /* Originate a router LSA */ + OSPF6_ROUTER_LSA_SCHEDULE(nbr->ospf6_if->area); + + /* Originate network lsa if it is an DR in the LAN */ + if (nbr->ospf6_if->state == OSPF6_INTERFACE_DR) + OSPF6_NETWORK_LSA_SCHEDULE(nbr->ospf6_if); +} + +/* + * Process max age Grace LSA. + * It is a indication for successful completion of GR. + * If router acting as HELPER, It exits from helper role. + * + * ospf6 + * Ospf6 pointer. + * + * lsa + * Grace LSA received from RESTARTER. + * + * nbr + * ospf6 neighbour which request the router to act as + * HELPER. + * + * Returns: + * Nothing. + */ +void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa, + struct ospf6_neighbor *restarter) +{ + uint8_t restart_reason = 0; + uint32_t grace_interval = 0; + int ret; + + /* Extract the grace lsa packet fields */ + ret = ospf6_extract_grace_lsa_fields(lsa, &grace_interval, + &restart_reason); + if (ret != OSPF6_SUCCESS) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Wrong Grace LSA packet.", __func__); + return; + } + + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, GraceLSA received for neighbour %pI4.", + __func__, &restarter->router_id); + + ospf6_gr_helper_exit(restarter, OSPF6_GR_HELPER_COMPLETED); +} + +/* + * Actions to be taken when topo change detected + * HELPER will be exited upon a topo change. + * + * ospf6 + * ospf6 pointer + * lsa + * topo change occurred due to this lsa(type (1-5 and 7) + * + * Returns: + * Nothing + */ +void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6, struct ospf6_lsa *lsa) +{ + struct listnode *i, *j, *k; + struct ospf6_neighbor *nbr = NULL; + struct ospf6_area *oa = NULL; + struct ospf6_interface *oi = NULL; + + if (!ospf6->ospf6_helper_cfg.active_restarter_cnt) + return; + + /* Topo change not required to be handled if strict + * LSA check is disabled for this router. + */ + if (!ospf6->ospf6_helper_cfg.strict_lsa_check) + return; + + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, Topo change detected due to lsa details : %s", + __func__, lsa->name); + + lsa->tobe_acknowledged = OSPF6_TRUE; + + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) + for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { + + /* Ref rfc3623 section 3.2.3.b and rfc5187 + * 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 (IS_AREA_STUB(oi->area) + && ((lsa->header->type == OSPF6_LSTYPE_AS_EXTERNAL) + || (lsa->header->type == OSPF6_LSTYPE_TYPE_7) + || (lsa->header->type + == OSPF6_LSTYPE_INTER_ROUTER))) { + continue; + } + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, nbr)) { + + ospf6_gr_helper_exit(nbr, + OSPF6_GR_HELPER_TOPO_CHG); + } + } +} + +/* Configuration handlers */ +/* + * Disable/Enable HELPER support on router level. + * + * ospf6 + * Ospf6 pointer. + * + * status + * TRUE/FALSE + * + * Returns: + * Nothing. + */ +static void ospf6_gr_helper_support_set(struct ospf6 *ospf6, bool support) +{ + struct ospf6_interface *oi; + struct advRtr lookup; + struct listnode *i, *j, *k; + struct ospf6_neighbor *nbr = NULL; + struct ospf6_area *oa = NULL; + + if (ospf6->ospf6_helper_cfg.is_helper_supported == support) + return; + + ospf6->ospf6_helper_cfg.is_helper_supported = support; + + /* If helper support disabled, cease HELPER role for all + * supporting neighbors. + */ + if (support == OSPF6_FALSE) { + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) + for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, + nbr)) { + + lookup.advRtrAddr = nbr->router_id; + /* check if helper support enabled for + * the corresponding routerid. + * If enabled, + * dont exit from helper role. + */ + if (hash_lookup( + ospf6->ospf6_helper_cfg + .enable_rtr_list, + &lookup)) + continue; + + ospf6_gr_helper_exit( + nbr, OSPF6_GR_HELPER_TOPO_CHG); + } + } + } +} + +/* + * Api to enable/disable strict lsa check on the HELPER. + * + * ospf6 + * Ospf6 pointer. + * + * enabled + * True - disable the lsa check. + * False - enable the strict lsa check. + * + * Returns: + * Nothing. + */ +static void ospf6_gr_helper_lsacheck_set(struct ospf6 *ospf6, bool enabled) +{ + if (ospf6->ospf6_helper_cfg.strict_lsa_check == enabled) + return; + + ospf6->ospf6_helper_cfg.strict_lsa_check = enabled; +} + +/* + * Api to set the supported restart reason. + * + * ospf6 + * Ospf6 pointer. + * + * only_planned + * True: support only planned restart. + * False: support for planned/unplanned restarts. + * + * Returns: + * Nothing. + */ + +static void +ospf6_gr_helper_set_supported_onlyPlanned_restart(struct ospf6 *ospf6, + bool only_planned) +{ + ospf6->ospf6_helper_cfg.only_planned_restart = only_planned; +} + +/* + * Api to set the supported grace interval in this router. + * + * ospf6 + * Ospf6 pointer. + * + * interval + * The supported grace interval.. + * + * Returns: + * Nothing. + */ +static void ospf6_gr_helper_supported_gracetime_set(struct ospf6 *ospf6, + uint32_t interval) +{ + ospf6->ospf6_helper_cfg.supported_grace_time = interval; +} + +/* API to walk and print all the Helper supported router ids */ +static int ospf6_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket, + void *arg) +{ + struct advRtr *rtr = bucket->data; + struct vty *vty = (struct vty *)arg; + static unsigned int count; + + vty_out(vty, "%-6pI4,", &rtr->advRtrAddr); + count++; + + if (count % 5 == 0) + vty_out(vty, "\n"); + + return HASHWALK_CONTINUE; +} + +/* API to walk and print all the Helper supported router ids.*/ +static int ospf6_print_json_helper_dis_rtr_walkcb(struct hash_bucket *bucket, + void *arg) +{ + struct advRtr *rtr = bucket->data; + struct json_object *json_rid_array = (struct json_object *)arg; + struct json_object *json_rid; + char router_id[16]; + + inet_ntop(AF_INET, &rtr->advRtrAddr, router_id, sizeof(router_id)); + + json_rid = json_object_new_object(); + + json_object_string_add(json_rid, "routerId", router_id); + json_object_array_add(json_rid_array, json_rid); + + return HASHWALK_CONTINUE; +} + +/* + * Enable/Disable HELPER support on a specified advertisement + * router. + * + * ospf6 + * Ospf6 pointer. + * + * advRtr + * HELPER support for given Advertisement Router. + * + * support + * True - Enable Helper Support. + * False - Disable Helper Support. + * + * Returns: + * Nothing. + */ +static void ospf6_gr_helper_support_set_per_routerid(struct ospf6 *ospf6, + struct in_addr router_id, + bool support) +{ + struct advRtr temp; + struct advRtr *rtr; + struct listnode *i, *j, *k; + struct ospf6_interface *oi; + struct ospf6_neighbor *nbr; + struct ospf6_area *oa; + + temp.advRtrAddr = router_id.s_addr; + + if (support == OSPF6_FALSE) { + /*Delete the routerid from the enable router hash table */ + rtr = hash_lookup(ospf6->ospf6_helper_cfg.enable_rtr_list, + &temp); + + if (rtr) { + hash_release(ospf6->ospf6_helper_cfg.enable_rtr_list, + rtr); + ospf6_disable_rtr_hash_free(rtr); + } + + /* If helper support is enabled globally + * no action is required. + */ + if (ospf6->ospf6_helper_cfg.is_helper_supported) + return; + + /* Cease the HELPER role fore neighbours from the + * specified advertisement router. + */ + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) + for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, + nbr)) { + + if (nbr->router_id != router_id.s_addr) + continue; + + if (OSPF6_GR_IS_ACTIVE_HELPER(nbr)) + ospf6_gr_helper_exit( + nbr, + OSPF6_GR_HELPER_TOPO_CHG); + } + } + + } else { + /* Add the routerid to the enable router hash table */ + hash_get(ospf6->ospf6_helper_cfg.enable_rtr_list, &temp, + ospf6_enable_rtr_hash_alloc); + } +} + +static void show_ospfv6_gr_helper_per_nbr(struct vty *vty, json_object *json, + bool uj, struct ospf6_neighbor *nbr) +{ + if (!uj) { + vty_out(vty, " Routerid : %pI4\n", &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", + ospf6_restart_reason_desc[nbr->gr_helper_info + .gr_restart_reason]); + } else { + char nbrid[16]; + json_object *json_neigh = NULL; + + inet_ntop(AF_INET, &nbr->router_id, nbrid, sizeof(nbrid)); + json_neigh = json_object_new_object(); + json_object_string_add(json_neigh, "routerid", nbrid); + 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", + ospf6_restart_reason_desc[ + nbr->gr_helper_info.gr_restart_reason]); + json_object_object_add(json, nbr->name, json_neigh); + } +} + +static int show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6, + json_object *json, bool uj, bool detail) +{ + struct ospf6_interface *oi; + + /* Show Router ID. */ + if (uj) { + char router_id[16]; + + inet_ntop(AF_INET, &ospf6->router_id, router_id, + sizeof(router_id)); + json_object_string_add(json, "routerId", router_id); + } else + vty_out(vty, + " OSPFv3 Routing Process (0) with Router-ID %pI4\n", + &ospf6->router_id); + + if (!uj) { + + if (ospf6->ospf6_helper_cfg.is_helper_supported) + vty_out(vty, + " Graceful restart helper support enabled.\n"); + else + vty_out(vty, + " Graceful restart helper support disabled.\n"); + + if (ospf6->ospf6_helper_cfg.strict_lsa_check) + vty_out(vty, " Strict LSA check is enabled.\n"); + else + vty_out(vty, " Strict LSA check is disabled.\n"); + + if (ospf6->ospf6_helper_cfg.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", + ospf6->ospf6_helper_cfg.supported_grace_time); + + if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf)) { + vty_out(vty, " Enable Router list:\n"); + vty_out(vty, " "); + hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list, + ospf6_print_vty_helper_dis_rtr_walkcb, vty); + vty_out(vty, "\n\n"); + } + + if (ospf6->ospf6_helper_cfg.last_exit_reason + != OSPF6_GR_HELPER_EXIT_NONE) { + vty_out(vty, " Last Helper exit Reason :%s\n", + ospf6_exit_reason_desc + [ospf6->ospf6_helper_cfg + .last_exit_reason]); + + if (ospf6->ospf6_helper_cfg.active_restarter_cnt) + vty_out(vty, + " Number of Active neighbours in graceful restart: %d\n", + ospf6->ospf6_helper_cfg + .active_restarter_cnt); + else + vty_out(vty, "\n"); + } + + + } else { + json_object_string_add( + json, "helperSupport", + (ospf6->ospf6_helper_cfg.is_helper_supported) + ? "Enabled" + : "Disabled"); + json_object_string_add( + json, "strictLsaCheck", + (ospf6->ospf6_helper_cfg.strict_lsa_check) + ? "Enabled" + : "Disabled"); + json_object_string_add( + json, "restartSupoort", + (ospf6->ospf6_helper_cfg.only_planned_restart) + ? "Planned Restart only" + : "Planned and Unplanned Restarts"); + + json_object_int_add( + json, "supportedGracePeriod", + ospf6->ospf6_helper_cfg.supported_grace_time); + + if (ospf6->ospf6_helper_cfg.last_exit_reason + != OSPF6_GR_HELPER_EXIT_NONE) + json_object_string_add( + json, "LastExitReason", + ospf6_exit_reason_desc + [ospf6->ospf6_helper_cfg + .last_exit_reason]); + + if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) { + struct json_object *json_rid_array = + json_object_new_array(); + + json_object_object_add(json, "enabledRouterIds", + json_rid_array); + + hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list, + ospf6_print_json_helper_dis_rtr_walkcb, + json_rid_array); + } + } + + if (detail) { + int cnt = 1; + struct listnode *i, *j, *k; + struct ospf6_area *oa; + json_object *json_neighbors = NULL; + + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa)) + for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { + struct ospf6_neighbor *nbr; + + if (uj) { + json_object_object_get_ex( + json, "Neighbors", + &json_neighbors); + if (!json_neighbors) { + json_neighbors = + json_object_new_object(); + json_object_object_add( + json, "Neighbors", + json_neighbors); + } + } + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, + nbr)) { + + if (!OSPF6_GR_IS_ACTIVE_HELPER(nbr)) + continue; + + if (!uj) + vty_out(vty, + " Neighbour %d :\n", + cnt++); + + show_ospfv6_gr_helper_per_nbr( + vty, json_neighbors, uj, nbr); + + } + } + } + + return CMD_SUCCESS; +} + +/* Graceful Restart HELPER config Commands */ +DEFPY(ospf6_gr_helper_enable, + ospf6_gr_helper_enable_cmd, + "graceful-restart helper-only [A.B.C.D$rtr_id]", + "ospf6 graceful restart\n" + "Enable Helper support\n" + "Advertisement RouterId\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + if (rtr_id_str != NULL) { + + ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id, + OSPF6_TRUE); + + return CMD_SUCCESS; + } + + ospf6_gr_helper_support_set(ospf6, OSPF6_TRUE); + + return CMD_SUCCESS; +} + +DEFPY(ospf6_gr_helper_disable, + ospf6_gr_helper_disable_cmd, + "no graceful-restart helper-only [A.B.C.D$rtr_id]", + NO_STR + "ospf6 graceful restart\n" + "Disable Helper support\n" + "Advertisement RouterId\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + if (rtr_id_str != NULL) { + + ospf6_gr_helper_support_set_per_routerid(ospf6, rtr_id, + OSPF6_FALSE); + + return CMD_SUCCESS; + } + + ospf6_gr_helper_support_set(ospf6, OSPF6_FALSE); + + return CMD_SUCCESS; +} + +DEFPY(ospf6_gr_helper_disable_lsacheck, + ospf6_gr_helper_disable_lsacheck_cmd, + "graceful-restart helper lsa-check-disable", + "ospf6 graceful restart\n" + "ospf6 GR Helper\n" + "disable strict LSA check\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_FALSE); + return CMD_SUCCESS; +} + +DEFPY(no_ospf6_gr_helper_disable_lsacheck, + no_ospf6_gr_helper_disable_lsacheck_cmd, + "no graceful-restart helper lsa-check-disable", + NO_STR + "ospf6 graceful restart\n" + "ospf6 GR Helper\n" + "diasble strict LSA check\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_gr_helper_lsacheck_set(ospf6, OSPF6_TRUE); + return CMD_SUCCESS; +} + +DEFPY(ospf6_gr_helper_planned_only, + ospf6_gr_helper_planned_only_cmd, + "graceful-restart helper planned-only", + "ospf6 graceful restart\n" + "ospf6 GR Helper\n" + "supported only planned restart\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_TRUE); + + return CMD_SUCCESS; +} + +DEFPY(no_ospf6_gr_helper_planned_only, no_ospf6_gr_helper_planned_only_cmd, + "no graceful-restart helper planned-only", + NO_STR + "ospf6 graceful restart\n" + "ospf6 GR Helper\n" + "supported only for planned restart\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_gr_helper_set_supported_onlyPlanned_restart(ospf6, OSPF6_FALSE); + + return CMD_SUCCESS; +} + +DEFPY(ospf6_gr_helper_supported_grace_time, + ospf6_gr_helper_supported_grace_time_cmd, + "graceful-restart helper supported-grace-time (10-1800)$interval", + "ospf6 graceful restart\n" + "ospf6 GR Helper\n" + "supported grace timer\n" + "grace interval(in seconds)\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_gr_helper_supported_gracetime_set(ospf6, interval); + return CMD_SUCCESS; +} + +DEFPY(no_ospf6_gr_helper_supported_grace_time, + no_ospf6_gr_helper_supported_grace_time_cmd, + "no graceful-restart helper supported-grace-time (10-1800)$interval", + NO_STR + "ospf6 graceful restart\n" + "ospf6 GR Helper\n" + "supported grace timer\n" + "grace interval(in seconds)\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_gr_helper_supported_gracetime_set(ospf6, + OSPF6_MAX_GRACE_INTERVAL); + return CMD_SUCCESS; +} + +/* Show commands */ +DEFPY(show_ipv6_ospf6_gr_helper, + show_ipv6_ospf6_gr_helper_cmd, + "show ipv6 ospf6 graceful-restart helper [detail] [json]", + SHOW_STR + "Ipv6 Information\n" + "OSPF6 information\n" + "ospf6 graceful restart\n" + "helper details in the router\n" + "detailed information\n" JSON_STR) +{ + int idx = 0; + bool uj = use_json(argc, argv); + struct ospf6 *ospf6 = NULL; + json_object *json = NULL; + bool detail = false; + + ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); + OSPF6_CMD_CHECK_RUNNING(); + + if (argv_find(argv, argc, "detail", &idx)) + detail = true; + + if (uj) + json = json_object_new_object(); + + show_ospf6_gr_helper_details(vty, ospf6, 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; +} + +/* Debug commands */ +DEFPY(debug_ospf6_gr, debug_ospf6_gr_cmd, + "[no$no] debug ospf6 graceful-restart", + NO_STR DEBUG_STR OSPF6_STR "Graceful restart\n") +{ + if (!no) + OSPF6_DEBUG_GR_ON(); + else + OSPF6_DEBUG_GR_OFF(); + + return CMD_SUCCESS; +} + +/* + * Api to display the grace LSA information. + * + * vty + * vty pointer. + * lsa + * Grace LSA. + * json + * json object + * + * Returns: + * Nothing. + */ +static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, + json_object *json, bool use_json) +{ + struct ospf6_lsa_header *lsah = NULL; + struct tlv_header *tlvh = NULL; + struct grace_tlv_graceperiod *gracePeriod; + struct grace_tlv_restart_reason *grReason; + uint16_t length = 0; + int sum = 0; + + lsah = (struct ospf6_lsa_header *)lsa->header; + + length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE; + + if (vty) { + if (!use_json) + vty_out(vty, "TLV info:\n"); + } else { + zlog_debug(" TLV info:"); + } + + 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); + + if (vty) { + if (use_json) + json_object_int_add( + json, "gracePeriod", + ntohl(gracePeriod->interval)); + else + vty_out(vty, " Grace period:%d\n", + ntohl(gracePeriod->interval)); + } else { + zlog_debug(" Grace period:%d", + ntohl(gracePeriod->interval)); + } + break; + case RESTART_REASON_TYPE: + grReason = (struct grace_tlv_restart_reason *)tlvh; + sum += TLV_SIZE(tlvh); + if (vty) { + if (use_json) + json_object_string_add( + json, "restartReason", + ospf6_restart_reason_desc + [grReason->reason]); + else + vty_out(vty, " Restart reason:%s\n", + ospf6_restart_reason_desc + [grReason->reason]); + } else { + zlog_debug(" Restart reason:%s", + ospf6_restart_reason_desc + [grReason->reason]); + } + break; + default: + break; + } + } + + return 0; +} + +void ospf6_gr_helper_config_init(void) +{ + + ospf6_install_lsa_handler(&grace_lsa_handler); + + install_element(OSPF6_NODE, &ospf6_gr_helper_enable_cmd); + install_element(OSPF6_NODE, &ospf6_gr_helper_disable_cmd); + install_element(OSPF6_NODE, &ospf6_gr_helper_disable_lsacheck_cmd); + install_element(OSPF6_NODE, &no_ospf6_gr_helper_disable_lsacheck_cmd); + install_element(OSPF6_NODE, &ospf6_gr_helper_planned_only_cmd); + install_element(OSPF6_NODE, &no_ospf6_gr_helper_planned_only_cmd); + install_element(OSPF6_NODE, &ospf6_gr_helper_supported_grace_time_cmd); + install_element(OSPF6_NODE, + &no_ospf6_gr_helper_supported_grace_time_cmd); + + install_element(VIEW_NODE, &show_ipv6_ospf6_gr_helper_cmd); + + install_element(CONFIG_NODE, &debug_ospf6_gr_cmd); + install_element(ENABLE_NODE, &debug_ospf6_gr_cmd); +} + + +/* + * Initialize GR helper config data structure. + * + * ospf6 + * ospf6 pointer + * + * Returns: + * Nothing + */ +void ospf6_gr_helper_init(struct ospf6 *ospf6) +{ + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, GR Helper init.", __func__); + + ospf6->ospf6_helper_cfg.is_helper_supported = OSPF6_FALSE; + ospf6->ospf6_helper_cfg.strict_lsa_check = OSPF6_TRUE; + ospf6->ospf6_helper_cfg.only_planned_restart = OSPF6_FALSE; + ospf6->ospf6_helper_cfg.supported_grace_time = OSPF6_MAX_GRACE_INTERVAL; + ospf6->ospf6_helper_cfg.last_exit_reason = OSPF6_GR_HELPER_EXIT_NONE; + ospf6->ospf6_helper_cfg.active_restarter_cnt = 0; + + ospf6->ospf6_helper_cfg.enable_rtr_list = hash_create( + ospf6_enable_rtr_hash_key, ospf6_enable_rtr_hash_cmp, + "Ospf6 enable router hash"); +} + +/* + * De-initialize GR helper config data structure. + * + * ospf6 + * ospf6 pointer + * + * Returns: + * Nothing + */ +void ospf6_gr_helper_deinit(struct ospf6 *ospf6) +{ + + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s, GR helper deinit.", __func__); + + ospf6_enable_rtr_hash_destroy(ospf6); +} + +static int ospf6_cfg_write_helper_enable_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 %pI4\n", &rtr->advRtrAddr); + return HASHWALK_CONTINUE; +} + +int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6) +{ + if (ospf6->ospf6_helper_cfg.is_helper_supported) + vty_out(vty, " graceful-restart helper-only\n"); + + if (!ospf6->ospf6_helper_cfg.strict_lsa_check) + vty_out(vty, " graceful-restart helper lsa-check-disable\n"); + + if (ospf6->ospf6_helper_cfg.only_planned_restart) + vty_out(vty, " graceful-restart helper planned-only\n"); + + if (ospf6->ospf6_helper_cfg.supported_grace_time + != OSPF6_MAX_GRACE_INTERVAL) + vty_out(vty, + " graceful-restart helper supported-grace-time %d\n", + ospf6->ospf6_helper_cfg.supported_grace_time); + + if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) { + hash_walk(ospf6->ospf6_helper_cfg.enable_rtr_list, + ospf6_cfg_write_helper_enable_rtr_walkcb, vty); + } + + return 0; +} + +int config_write_ospf6_debug_gr_helper(struct vty *vty) +{ + if (IS_DEBUG_OSPF6_GR) + vty_out(vty, "debug ospf6 gr helper\n"); + return 0; +} diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index a169b9c60e..bbb474ba1a 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -44,9 +44,10 @@ #include "ospf6d.h" #include "ospf6_bfd.h" #include "ospf6_zebra.h" +#include "ospf6_gr.h" #include "lib/json.h" -DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface"); DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names"); DEFINE_QOBJ_TYPE(ospf6_interface); DEFINE_HOOK(ospf6_interface_change, @@ -59,6 +60,22 @@ const char *const ospf6_interface_state_str[] = { "None", "Down", "Loopback", "Waiting", "PointToPoint", "DROther", "BDR", "DR", NULL}; +int ospf6_interface_neighbor_count(struct ospf6_interface *oi) +{ + int count = 0; + struct ospf6_neighbor *nbr = NULL; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, nbr)) { + /* Down state is not shown. */ + if (nbr->state == OSPF6_NEIGHBOR_DOWN) + continue; + count++; + } + + return count; +} + struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) { @@ -579,7 +596,7 @@ static struct ospf6_neighbor *better_drouter(struct ospf6_neighbor *a, return a; } -static uint8_t dr_election(struct ospf6_interface *oi) +uint8_t dr_election(struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on, *drouter, *bdrouter, myself; @@ -896,6 +913,17 @@ int interface_down(struct thread *thread) /* Stop trying to set socket options. */ THREAD_OFF(oi->thread_sso); + /* Cease the HELPER role for all the neighbours + * of this interface. + */ + if (ospf6_interface_neighbor_count(oi)) { + struct listnode *ln; + struct ospf6_neighbor *nbr = NULL; + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, ln, nbr)) + ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_TOPO_CHG); + } + for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) ospf6_neighbor_delete(on); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index b5efca743e..ccdf8b1c8f 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -218,6 +218,8 @@ extern void install_element_ospf6_clear_interface(void); extern int config_write_ospf6_debug_interface(struct vty *vty); extern void install_element_ospf6_debug_interface(void); +extern int ospf6_interface_neighbor_count(struct ospf6_interface *oi); +extern uint8_t dr_election(struct ospf6_interface *oi); DECLARE_HOOK(ospf6_interface_change, (struct ospf6_interface * oi, int state, int old_state), diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 4c95ee69bd..a8ed9132dd 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -70,7 +70,8 @@ #define OSPF6_LSTYPE_TYPE_7 0x2007 #define OSPF6_LSTYPE_LINK 0x0008 #define OSPF6_LSTYPE_INTRA_PREFIX 0x2009 -#define OSPF6_LSTYPE_SIZE 0x000a +#define OSPF6_LSTYPE_GRACE_LSA 0x000b +#define OSPF6_LSTYPE_SIZE 0x000c /* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */ #define OSPF6_LSTYPE_UBIT_MASK 0x8000 @@ -146,6 +147,9 @@ struct ospf6_lsa { /* lsa instance */ struct ospf6_lsa_header *header; + + /*For topo chg detection in HELPER role*/ + bool tobe_acknowledged; }; #define OSPF6_LSA_HEADERONLY 0x01 @@ -210,6 +214,14 @@ extern vector ospf6_lsa_handler_vector; continue; \ } +#define CHECK_LSA_TOPO_CHG_ELIGIBLE(type) \ + ((type == OSPF6_LSTYPE_ROUTER) \ + || (type == OSPF6_LSTYPE_NETWORK) \ + || (type == OSPF6_LSTYPE_INTER_PREFIX) \ + || (type == OSPF6_LSTYPE_INTER_ROUTER) \ + || (type == OSPF6_LSTYPE_AS_EXTERNAL) \ + || (type == OSPF6_LSTYPE_TYPE_7) \ + || (type == OSPF6_LSTYPE_INTRA_PREFIX)) /* Function Prototypes */ extern const char *ospf6_lstype_name(uint16_t type); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 549f5668b9..cd73e3d406 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -46,7 +46,7 @@ #include "ospf6_flood.h" #include "ospf6d.h" - +#include "ospf6_gr.h" #include <netinet/ip6.h> DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message"); @@ -84,7 +84,9 @@ const uint16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = { /* 0x2006 */ 0, /* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, /* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE, - /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE}; + /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE, + /* 0x200a */ 0, + /* 0x000b */ OSPF6_GRACE_LSA_MIN_SIZE}; /* print functions */ @@ -512,8 +514,44 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, thread_execute(master, hello_received, on, 0); if (twoway) thread_execute(master, twoway_received, on, 0); - else - thread_execute(master, oneway_received, on, 0); + else { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Received oneway hello from RESTARTER so ignore here.", + __PRETTY_FUNCTION__); + + if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) { + /* 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 ONE_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. + */ + thread_execute(master, oneway_received, on, 0); + } + } + + if (OSPF6_GR_IS_ACTIVE_HELPER(on)) { + /* As per the GR Conformance Test Case 7.2. Section 3 + * "Also, if X was the Designated Router on network segment S + * when the helping relationship began, Y maintains X as the + * Designated Router until the helping relationship is + * terminated." + * When it is a helper for this neighbor, It should not trigger + * the ISM Events. Also Intentionally not setting the priority + * and other fields so that when the neighbor exits the Grace + * period, it can handle if there is any change before GR and + * after GR. + */ + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Neighbor is under GR Restart, hence ignoring the ISM Events", + __PRETTY_FUNCTION__); + + return; + } /* Schedule interface events */ if (backupseen) @@ -1260,7 +1298,15 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah, lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTRA_PREFIX_LSA_MIN_SIZE, ntohs(intra_prefix_lsa->prefix_num) /* 16 bits */ - ); + ); + case OSPF6_LSTYPE_GRACE_LSA: + if (lsalen < OSPF6_LSA_HEADER_SIZE + GRACE_PERIOD_TLV_SIZE + + GRACE_RESTART_REASON_TLV_SIZE) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug("%s: Undersized GraceLSA.", + __func__); + return MSG_NG; + } } /* No additional validation is possible for unknown LSA types, which are themselves valid in OPSFv3, hence the default decision is to accept. diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 8cf05183e1..4ea615f32b 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -45,6 +45,7 @@ #include "ospf6_lsa.h" #include "ospf6_spf.h" #include "ospf6_zebra.h" +#include "ospf6_gr.h" #include "lib/json.h" DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor"); @@ -151,6 +152,7 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on) THREAD_OFF(on->thread_send_lsreq); THREAD_OFF(on->thread_send_lsupdate); THREAD_OFF(on->thread_send_lsack); + THREAD_OFF(on->gr_helper_info.t_grace_timer); bfd_sess_free(&on->bfd_session); XFREE(MTYPE_OSPF6_NEIGHBOR, on); @@ -192,19 +194,24 @@ static void ospf6_neighbor_state_change(uint8_t next_state, if (prev_state == OSPF6_NEIGHBOR_FULL || next_state == OSPF6_NEIGHBOR_FULL) { - OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area); - if (on->ospf6_if->state == OSPF6_INTERFACE_DR) { - OSPF6_NETWORK_LSA_SCHEDULE(on->ospf6_if); - OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(on->ospf6_if); + if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) { + OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area); + if (on->ospf6_if->state == OSPF6_INTERFACE_DR) { + OSPF6_NETWORK_LSA_SCHEDULE(on->ospf6_if); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT( + on->ospf6_if); + } } if (next_state == OSPF6_NEIGHBOR_FULL) on->ospf6_if->area->intra_prefix_originate = 1; - OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area); + if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB( + on->ospf6_if->area); - if ((prev_state == OSPF6_NEIGHBOR_LOADING || - prev_state == OSPF6_NEIGHBOR_EXCHANGE) && - next_state == OSPF6_NEIGHBOR_FULL) { + if ((prev_state == OSPF6_NEIGHBOR_LOADING + || prev_state == OSPF6_NEIGHBOR_EXCHANGE) + && next_state == OSPF6_NEIGHBOR_FULL) { OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if); on->ospf6_if->area->full_nbrs++; } @@ -601,12 +608,29 @@ int inactivity_timer(struct thread *thread) on->drouter = on->prev_drouter = 0; on->bdrouter = on->prev_bdrouter = 0; - ospf6_neighbor_state_change(OSPF6_NEIGHBOR_DOWN, on, - OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); - thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL); + if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) { + on->drouter = on->prev_drouter = 0; + on->bdrouter = on->prev_bdrouter = 0; + + ospf6_neighbor_state_change( + OSPF6_NEIGHBOR_DOWN, on, + OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); + thread_add_event(master, neighbor_change, on->ospf6_if, 0, + NULL); + + listnode_delete(on->ospf6_if->neighbor_list, on); + ospf6_neighbor_delete(on); - listnode_delete(on->ospf6_if->neighbor_list, on); - ospf6_neighbor_delete(on); + } else { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s, Acting as HELPER for this neighbour, So restart the dead timer.", + __PRETTY_FUNCTION__); + + thread_add_timer(master, inactivity_timer, on, + on->ospf6_if->dead_interval, + &on->inactivity_timer); + } return 0; } diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 729b1d2e85..a229897226 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -32,6 +32,38 @@ extern unsigned char conf_debug_ospf6_neighbor; #define IS_OSPF6_DEBUG_NEIGHBOR(level) \ (conf_debug_ospf6_neighbor & OSPF6_DEBUG_NEIGHBOR_##level) +struct ospf6_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*/ + uint32_t helper_exit_reason; + + /* Planned/Unplanned restart*/ + uint32_t gr_restart_reason; + + + /* Helper rejected reason */ + uint32_t rejected_reason; +}; + /* Neighbor structure */ struct ospf6_neighbor { /* Neighbor Router ID String */ @@ -104,6 +136,9 @@ struct ospf6_neighbor { /* BFD information */ struct bfd_session_params *bfd_session; + + /* ospf6 graceful restart HELPER info */ + struct ospf6_helper_info gr_helper_info; }; /* Neighbor state */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 6105e2c24b..fc181a6d18 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -51,6 +51,7 @@ #include "ospf6_intra.h" #include "ospf6_spf.h" #include "ospf6d.h" +#include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" @@ -440,6 +441,7 @@ static struct ospf6 *ospf6_create(const char *name) o->oi_write_q = list_new(); + ospf6_gr_helper_init(o); QOBJ_REG(o, ospf6); /* Make ospf protocol socket. */ @@ -485,6 +487,7 @@ void ospf6_delete(struct ospf6 *o) QOBJ_UNREG(o); + ospf6_gr_helper_deinit(o); ospf6_flush_self_originated_lsas_now(o); ospf6_disable(o); ospf6_del(o); @@ -2233,7 +2236,7 @@ static int config_write_ospf6(struct vty *vty) ospf6_distance_config_write(vty, ospf6); ospf6_distribute_config_write(vty, ospf6); ospf6_asbr_summary_config_write(vty, ospf6); - + config_write_ospf6_gr_helper(vty, ospf6); vty_out(vty, "!\n"); } return 0; diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index fe02cd3f84..58ecf08495 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -60,6 +60,43 @@ struct ospf6_redist { #define ROUTEMAP(R) (R->route_map.map) }; +struct ospf6_gr_helper { + /* 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 for which Helper support is + * enabled. + */ + struct hash *enable_rtr_list; + + /* HELPER for number of active + * RESTARTERs. + */ + int active_restarter_cnt; + + /* last HELPER exit reason */ + uint32_t last_exit_reason; +}; + /* OSPFv3 top level data structure */ struct ospf6 { /* The relevant vrf_id */ @@ -154,6 +191,10 @@ struct ospf6 { * to support ECMP. */ uint16_t max_multipath; + + /*ospf6 Graceful restart helper info */ + struct ospf6_gr_helper ospf6_helper_cfg; + /* Count of NSSA areas */ uint8_t anyNSSA; struct thread *t_abr_task; /* ABR task timer. */ diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index fb6ac4402a..5dfd986e2a 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -45,6 +45,7 @@ #include "ospf6_flood.h" #include "ospf6d.h" #include "ospf6_bfd.h" +#include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" @@ -96,6 +97,7 @@ static int config_write_ospf6_debug(struct vty *vty) config_write_ospf6_debug_abr(vty); config_write_ospf6_debug_flood(vty); config_write_ospf6_debug_nssa(vty); + config_write_ospf6_debug_gr_helper(vty); return 0; } @@ -1402,6 +1404,7 @@ void ospf6_init(struct thread_master *master) ospf6_intra_init(); ospf6_asbr_init(); ospf6_abr_init(); + ospf6_gr_helper_config_init(); /* initialize hooks for modifying filter rules */ prefix_list_add_hook(ospf6_plist_add); diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 5afece9b0a..d5170be7cc 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -108,6 +108,12 @@ extern struct thread_master *master; vrf_name = VRF_DEFAULT_NAME; \ } +#define OSPF6_FALSE false +#define OSPF6_TRUE true +#define OSPF6_SUCCESS 1 +#define OSPF6_FAILURE 0 +#define OSPF6_INVALID -1 + extern struct zebra_privs_t ospf6d_privs; /* Function Prototypes */ diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 78fb26b00e..ac99e90b26 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -12,6 +12,7 @@ vtysh_scan += \ ospf6d/ospf6_area.c \ ospf6d/ospf6_bfd.c \ ospf6d/ospf6_flood.c \ + ospf6d/ospf6_gr_helper.c \ ospf6d/ospf6_interface.c \ ospf6d/ospf6_intra.c \ ospf6d/ospf6_lsa.c \ @@ -39,6 +40,7 @@ ospf6d_libospf6_a_SOURCES = \ ospf6d/ospf6_routemap_nb_config.c \ ospf6d/ospf6_bfd.c \ ospf6d/ospf6_flood.c \ + ospf6d/ospf6_gr_helper.c \ ospf6d/ospf6_interface.c \ ospf6d/ospf6_intra.c \ ospf6d/ospf6_lsa.c \ @@ -61,6 +63,7 @@ noinst_HEADERS += \ ospf6d/ospf6_asbr.h \ ospf6d/ospf6_bfd.h \ ospf6d/ospf6_flood.h \ + ospf6d/ospf6_gr.h \ ospf6d/ospf6_interface.h \ ospf6d/ospf6_intra.h \ ospf6d/ospf6_lsa.h \ @@ -91,6 +94,7 @@ clippy_scan += \ ospf6d/ospf6_top.c \ ospf6d/ospf6_asbr.c \ ospf6d/ospf6_lsa.c \ + ospf6d/ospf6_gr_helper.c \ # end nodist_ospf6d_ospf6d_SOURCES = \ diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 7fddb65a86..8f9153d766 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -267,6 +267,8 @@ static void ospf_process_self_originated_lsa(struct ospf *ospf, ospf_external_lsa_refresh(ospf, new, &ei_aggr, LSA_REFRESH_FORCE, true); + SET_FLAG(aggr->flags, + OSPF_EXTERNAL_AGGRT_ORIGINATED); } else ospf_lsa_flush_as(ospf, new); } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 9ef2a6520a..d209ae053c 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -3631,6 +3631,8 @@ struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa) ospf_external_lsa_refresh(ospf, lsa, &ei_aggr, LSA_REFRESH_FORCE, true); + SET_FLAG(aggr->flags, + OSPF_EXTERNAL_AGGRT_ORIGINATED); } else ospf_lsa_flush_as(ospf, lsa); } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 21fa625311..9a421de017 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -291,6 +291,16 @@ static int ospf_area_id_cmp(struct ospf_area *a1, struct ospf_area *a2) return 0; } +static void ospf_add(struct ospf *ospf) +{ + listnode_add(om->ospf, ospf); +} + +static void ospf_delete(struct ospf *ospf) +{ + listnode_delete(om->ospf, ospf); +} + struct ospf *ospf_new_alloc(unsigned short instance, const char *name) { int i; @@ -366,6 +376,8 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name) new->maxage_delay = OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT; new->maxage_lsa = route_table_init(); new->t_maxage_walker = NULL; + thread_add_timer(master, ospf_lsa_maxage_walker, new, + OSPF_LSA_MAXAGE_CHECK_INTERVAL, &new->t_maxage_walker); /* Max paths initialization */ new->max_multipath = MULTIPATH_NUM; @@ -376,6 +388,8 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name) new->lsa_refresh_queue.index = 0; new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; new->t_lsa_refresher = NULL; + thread_add_timer(master, ospf_lsa_refresh_walker, new, + new->lsa_refresh_interval, &new->t_lsa_refresher); new->lsa_refresher_started = monotime(NULL); new->ibuf = stream_new(OSPF_MAX_PACKET_SIZE + 1); @@ -390,6 +404,8 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name) ospf_asbr_external_aggregator_init(new); + ospf_opaque_type11_lsa_init(new); + QOBJ_REG(new, ospf); new->fd = -1; @@ -403,23 +419,23 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) struct ospf *new; new = ospf_new_alloc(instance, name); + ospf_add(new); + + if (new->vrf_id == VRF_UNKNOWN) + return new; if ((ospf_sock_init(new)) < 0) { - if (new->vrf_id != VRF_UNKNOWN) - flog_err( - EC_LIB_SOCKET, - "%s: ospf_sock_init is unable to open a socket", - __func__); + flog_err(EC_LIB_SOCKET, + "%s: ospf_sock_init is unable to open a socket", + __func__); return new; } - thread_add_timer(master, ospf_lsa_maxage_walker, new, - OSPF_LSA_MAXAGE_CHECK_INTERVAL, &new->t_maxage_walker); - thread_add_timer(master, ospf_lsa_refresh_walker, new, - new->lsa_refresh_interval, &new->t_lsa_refresher); - thread_add_read(master, ospf_read, new, new->fd, &new->t_read); + new->oi_running = 1; + ospf_router_id_update(new); + /* * Read from non-volatile memory whether this instance is performing a * graceful restart or not. @@ -455,16 +471,6 @@ static int ospf_is_ready(struct ospf *ospf) return 1; } -static void ospf_add(struct ospf *ospf) -{ - listnode_add(om->ospf, ospf); -} - -static void ospf_delete(struct ospf *ospf) -{ - listnode_delete(om->ospf, ospf); -} - struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name) { struct ospf *ospf = NULL; @@ -483,16 +489,6 @@ struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name) return NULL; } -static void ospf_init(struct ospf *ospf) -{ - ospf_opaque_type11_lsa_init(ospf); - - if (ospf->vrf_id != VRF_UNKNOWN) - ospf->oi_running = 1; - - ospf_router_id_update(ospf); -} - struct ospf *ospf_lookup(unsigned short instance, const char *name) { struct ospf *ospf; @@ -513,12 +509,8 @@ struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) ospf = ospf_lookup(instance, name); *created = (ospf == NULL); - if (ospf == NULL) { + if (ospf == NULL) ospf = ospf_new(instance, name); - ospf_add(ospf); - - ospf_init(ospf); - } return ospf; } diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index a911210ab4..db5f256a86 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -1755,13 +1755,20 @@ DEFPY_NOSH( DEFPY_NOSH( pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd, - "[no] pce-config WORD$name", + "pce-config WORD$name", + "Shared configuration\n" + "Shared configuration name\n") +{ + return path_pcep_cli_pcep_pce_config(vty, name); +} + +DEFPY(pcep_cli_pcep_no_pce_config, + pcep_cli_pcep_no_pce_config_cmd, + "no pce-config WORD$name", NO_STR "Shared configuration\n" "Shared configuration name\n") { - if (no == NULL) - return path_pcep_cli_pcep_pce_config(vty, name); return path_pcep_cli_pcep_pce_config_delete(vty, name); } @@ -1781,13 +1788,20 @@ DEFPY(pcep_cli_show_srte_pcep_pce_config, DEFPY_NOSH( pcep_cli_pce, pcep_cli_pce_cmd, - "[no] pce WORD$name", + "pce WORD$name", + "PCE configuration, address sub-config is mandatory\n" + "PCE name\n") +{ + return path_pcep_cli_pce(vty, name); +} + +DEFPY(pcep_cli_no_pce, + pcep_cli_no_pce_cmd, + "no pce WORD$name", NO_STR "PCE configuration, address sub-config is mandatory\n" "PCE name\n") { - if (no == NULL) - return path_pcep_cli_pce(vty, name); return path_pcep_cli_pce_delete(vty, name); } @@ -1906,15 +1920,19 @@ DEFPY(pcep_cli_peer_timers, DEFPY_NOSH( pcep_cli_pcc, pcep_cli_pcc_cmd, - "[no] pcc", + "pcc", + "PCC configuration\n") +{ + return path_pcep_cli_pcc(vty); +} + +DEFPY(pcep_cli_no_pcc, + pcep_cli_no_pcc_cmd, + "no pcc", NO_STR "PCC configuration\n") { - if (no != NULL) { - return path_pcep_cli_pcc_delete(vty); - } else { - return path_pcep_cli_pcc(vty); - } + return path_pcep_cli_pcc_delete(vty); } DEFPY(pcep_cli_pcc_pcc_msd, @@ -2001,6 +2019,7 @@ void pcep_cli_init(void) /* PCEP configuration group related configuration commands */ install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd); + install_element(PCEP_NODE, &pcep_cli_pcep_no_pce_config_cmd); install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_source_address_cmd); install_element(PCEP_PCE_CONFIG_NODE, &pcep_cli_peer_timers_cmd); @@ -2010,6 +2029,7 @@ void pcep_cli_init(void) /* PCE peer related configuration commands */ install_element(PCEP_NODE, &pcep_cli_pce_cmd); + install_element(PCEP_NODE, &pcep_cli_no_pce_cmd); install_element(PCEP_PCE_NODE, &pcep_cli_peer_address_cmd); install_element(PCEP_PCE_NODE, &pcep_cli_peer_source_address_cmd); install_element(PCEP_PCE_NODE, &pcep_cli_peer_pcep_pce_config_ref_cmd); @@ -2021,6 +2041,7 @@ void pcep_cli_init(void) /* PCC related configuration commands */ install_element(ENABLE_NODE, &pcep_cli_show_srte_pcc_cmd); install_element(PCEP_NODE, &pcep_cli_pcc_cmd); + install_element(PCEP_NODE, &pcep_cli_no_pcc_cmd); install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_peer_cmd); install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_msd_cmd); diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 0181e885fd..f2845ee6e1 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -419,9 +419,12 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) active = bsm_rpinfos_first(bsgrp_node->bsrp_list); /* Remove nodes with hold time 0 & check if list still has a head */ - frr_each_safe (bsm_rpinfos, bsgrp_node->partial_bsrp_list, pend) - if (is_hold_time_zero(pend)) + frr_each_safe (bsm_rpinfos, bsgrp_node->partial_bsrp_list, pend) { + if (is_hold_time_zero(pend)) { bsm_rpinfos_del(bsgrp_node->partial_bsrp_list, pend); + pim_bsm_rpinfo_free(pend); + } + } pend = bsm_rpinfos_first(bsgrp_node->partial_bsrp_list); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 812c8c1449..1238e03a5b 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -7179,7 +7179,7 @@ DEFPY (pim_register_accept_list, DEFUN (ip_pim_joinprune_time, ip_pim_joinprune_time_cmd, - "ip pim join-prune-interval (5-600)", + "ip pim join-prune-interval (1-65535)", IP_STR "pim multicast routing\n" "Join Prune Send Interval\n" @@ -7193,27 +7193,22 @@ DEFUN (ip_pim_joinprune_time, DEFUN (no_ip_pim_joinprune_time, no_ip_pim_joinprune_time_cmd, - "no ip pim join-prune-interval (5-600)", + "no ip pim join-prune-interval [(1-65535)]", NO_STR IP_STR "pim multicast routing\n" "Join Prune Send Interval\n" - "Seconds\n") + IGNORED_IN_NO_STR) { - char jp_default_timer[5]; - - snprintf(jp_default_timer, sizeof(jp_default_timer), "%d", - PIM_DEFAULT_T_PERIODIC); - nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval", - NB_OP_MODIFY, jp_default_timer); + NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_register_suppress, ip_pim_register_suppress_cmd, - "ip pim register-suppress-time (5-60000)", + "ip pim register-suppress-time (1-65535)", IP_STR "pim multicast routing\n" "Register Suppress Timer\n" @@ -7227,27 +7222,22 @@ DEFUN (ip_pim_register_suppress, DEFUN (no_ip_pim_register_suppress, no_ip_pim_register_suppress_cmd, - "no ip pim register-suppress-time (5-60000)", + "no ip pim register-suppress-time [(1-65535)]", NO_STR IP_STR "pim multicast routing\n" "Register Suppress Timer\n" - "Seconds\n") + IGNORED_IN_NO_STR) { - char rs_default_timer[5]; - - snprintf(rs_default_timer, sizeof(rs_default_timer), "%d", - PIM_REGISTER_SUPPRESSION_TIME_DEFAULT); - nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time", - NB_OP_MODIFY, rs_default_timer); + NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_rp_keep_alive, ip_pim_rp_keep_alive_cmd, - "ip pim rp keep-alive-timer (31-60000)", + "ip pim rp keep-alive-timer (1-65535)", IP_STR "pim multicast routing\n" "Rendevous Point\n" @@ -7274,20 +7264,26 @@ DEFUN (ip_pim_rp_keep_alive, DEFUN (no_ip_pim_rp_keep_alive, no_ip_pim_rp_keep_alive_cmd, - "no ip pim rp keep-alive-timer (31-60000)", + "no ip pim rp keep-alive-timer [(1-65535)]", NO_STR IP_STR "pim multicast routing\n" "Rendevous Point\n" "Keep alive Timer\n" - "Seconds\n") + IGNORED_IN_NO_STR) { const char *vrfname; - char rp_ka_timer[5]; + char rp_ka_timer[6]; char rp_ka_timer_xpath[XPATH_MAXLEN]; + uint v; - snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%d", - PIM_RP_KEEPALIVE_PERIOD); + /* RFC4601 */ + v = yang_dnode_get_uint16(vty->candidate_config->dnode, + "/frr-pim:pim/register-suppress-time"); + v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT; + if (v > UINT16_MAX) + v = UINT16_MAX; + snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); vrfname = pim_cli_get_vrf_name(vty); if (vrfname == NULL) @@ -7306,7 +7302,7 @@ DEFUN (no_ip_pim_rp_keep_alive, DEFUN (ip_pim_keep_alive, ip_pim_keep_alive_cmd, - "ip pim keep-alive-timer (31-60000)", + "ip pim keep-alive-timer (1-65535)", IP_STR "pim multicast routing\n" "Keep alive Timer\n" @@ -7331,19 +7327,16 @@ DEFUN (ip_pim_keep_alive, DEFUN (no_ip_pim_keep_alive, no_ip_pim_keep_alive_cmd, - "no ip pim keep-alive-timer (31-60000)", + "no ip pim keep-alive-timer [(1-65535)]", NO_STR IP_STR "pim multicast routing\n" "Keep alive Timer\n" - "Seconds\n") + IGNORED_IN_NO_STR) { const char *vrfname; - char ka_timer[5]; char ka_timer_xpath[XPATH_MAXLEN]; - snprintf(ka_timer, sizeof(ka_timer), "%d", PIM_KEEPALIVE_PERIOD); - vrfname = pim_cli_get_vrf_name(vty); if (vrfname == NULL) return CMD_WARNING_CONFIG_FAILED; @@ -7352,15 +7345,14 @@ DEFUN (no_ip_pim_keep_alive, "frr-pim:pimd", "pim", vrfname); strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); - nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, - ka_timer); + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } DEFUN (ip_pim_packets, ip_pim_packets_cmd, - "ip pim packets (1-100)", + "ip pim packets (1-255)", IP_STR "pim multicast routing\n" "packets to process at one time per fd\n" @@ -7374,27 +7366,21 @@ DEFUN (ip_pim_packets, DEFUN (no_ip_pim_packets, no_ip_pim_packets_cmd, - "no ip pim packets (1-100)", + "no ip pim packets [(1-255)]", NO_STR IP_STR "pim multicast routing\n" "packets to process at one time per fd\n" - "Number of packets\n") + IGNORED_IN_NO_STR) { - char default_packet[3]; - - snprintf(default_packet, sizeof(default_packet), "%d", - PIM_DEFAULT_PACKET_PROCESS); - - nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY, - default_packet); + nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } DEFPY (igmp_group_watermark, igmp_group_watermark_cmd, - "ip igmp watermark-warn (10-60000)$limit", + "ip igmp watermark-warn (1-65535)$limit", IP_STR IGMP_STR "Configure group limit for watermark warning\n" @@ -7408,12 +7394,12 @@ DEFPY (igmp_group_watermark, DEFPY (no_igmp_group_watermark, no_igmp_group_watermark_cmd, - "no ip igmp watermark-warn [(10-60000)$limit]", + "no ip igmp watermark-warn [(1-65535)$limit]", NO_STR IP_STR IGMP_STR "Unconfigure group limit for watermark warning\n" - "Group count to generate watermark warning\n") + IGNORED_IN_NO_STR) { PIM_DECLVAR_CONTEXT(vrf, pim); pim->igmp_watermark_limit = 0; @@ -8146,7 +8132,7 @@ DEFUN (interface_no_ip_igmp_join, DEFUN (interface_ip_igmp_query_interval, interface_ip_igmp_query_interval_cmd, - "ip igmp query-interval (1-1800)", + "ip igmp query-interval (1-65535)", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_INTERVAL_STR @@ -8174,19 +8160,14 @@ DEFUN (interface_ip_igmp_query_interval, DEFUN (interface_no_ip_igmp_query_interval, interface_no_ip_igmp_query_interval_cmd, - "no ip igmp query-interval", + "no ip igmp query-interval [(1-65535)]", NO_STR IP_STR IFACE_IGMP_STR - IFACE_IGMP_QUERY_INTERVAL_STR) + IFACE_IGMP_QUERY_INTERVAL_STR + IGNORED_IN_NO_STR) { - char default_query_interval[5]; - - snprintf(default_query_interval, sizeof(default_query_interval), "%d", - IGMP_GENERAL_QUERY_INTERVAL); - - nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY, - default_query_interval); + nb_cli_enqueue_change(vty, "./query-interval", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } @@ -8222,7 +8203,7 @@ DEFUN (interface_no_ip_igmp_version, DEFUN (interface_ip_igmp_query_max_response_time, interface_ip_igmp_query_max_response_time_cmd, - "ip igmp query-max-response-time (10-250)", + "ip igmp query-max-response-time (1-65535)", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR @@ -8251,27 +8232,21 @@ DEFUN (interface_ip_igmp_query_max_response_time, DEFUN (interface_no_ip_igmp_query_max_response_time, interface_no_ip_igmp_query_max_response_time_cmd, - "no ip igmp query-max-response-time (10-250)", + "no ip igmp query-max-response-time [(1-65535)]", NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR - "Time for response in deci-seconds\n") + IGNORED_IN_NO_STR) { - char default_query_max_response_time[4]; - - snprintf(default_query_max_response_time, - sizeof(default_query_max_response_time), - "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); - - nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, - default_query_max_response_time); + nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY, + NULL); return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec, interface_ip_igmp_query_max_response_time_dsec_cmd, - "ip igmp query-max-response-time-dsec (10-250)", + "ip igmp query-max-response-time-dsec (1-65535)", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR @@ -8299,27 +8274,22 @@ DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec, DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec, interface_no_ip_igmp_query_max_response_time_dsec_cmd, - "no ip igmp query-max-response-time-dsec", + "no ip igmp query-max-response-time-dsec [(1-65535)]", NO_STR IP_STR IFACE_IGMP_STR - IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR) + IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR + IGNORED_IN_NO_STR) { - char default_query_max_response_time[4]; - - snprintf(default_query_max_response_time, - sizeof(default_query_max_response_time), - "%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); - - nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, - default_query_max_response_time); + nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY, + NULL); return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_ip_igmp_last_member_query_count, interface_ip_igmp_last_member_query_count_cmd, - "ip igmp last-member-query-count (1-7)", + "ip igmp last-member-query-count (1-255)", IP_STR IFACE_IGMP_STR IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR @@ -8347,27 +8317,22 @@ DEFUN (interface_ip_igmp_last_member_query_count, DEFUN (interface_no_ip_igmp_last_member_query_count, interface_no_ip_igmp_last_member_query_count_cmd, - "no ip igmp last-member-query-count [(1-7)]", + "no ip igmp last-member-query-count [(1-255)]", NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR - "Last member query count\n") + IGNORED_IN_NO_STR) { - char default_robustness[2]; - - snprintf(default_robustness, sizeof(default_robustness), "%d", - IGMP_DEFAULT_ROBUSTNESS_VARIABLE); - - nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY, - default_robustness); + nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_DESTROY, + NULL); return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } DEFUN (interface_ip_igmp_last_member_query_interval, interface_ip_igmp_last_member_query_interval_cmd, - "ip igmp last-member-query-interval (1-255)", + "ip igmp last-member-query-interval (1-65535)", IP_STR IFACE_IGMP_STR IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR @@ -8395,21 +8360,15 @@ DEFUN (interface_ip_igmp_last_member_query_interval, DEFUN (interface_no_ip_igmp_last_member_query_interval, interface_no_ip_igmp_last_member_query_interval_cmd, - "no ip igmp last-member-query-interval [(1-255)]", + "no ip igmp last-member-query-interval [(1-65535)]", NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR - "Last member query interval in deciseconds\n") + IGNORED_IN_NO_STR) { - char default_last_member_query_count[4]; - - snprintf(default_last_member_query_count, - sizeof(default_last_member_query_count), - "%d", IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC); - - nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY, - default_last_member_query_count); + nb_cli_enqueue_change(vty, "./last-member-query-interval", + NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); } @@ -8439,13 +8398,7 @@ DEFUN (interface_no_ip_pim_drprio, "Revert the Designated Router Priority to default\n" "Old Value of the Priority\n") { - char default_priority[10]; - - snprintf(default_priority, sizeof(default_priority), "%d", - PIM_DEFAULT_DR_PRIORITY); - - nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, - default_priority); + nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-pim:pim"); } @@ -8780,7 +8733,7 @@ DEFUN (interface_no_ip_mroute, DEFUN (interface_ip_pim_hello, interface_ip_pim_hello_cmd, - "ip pim hello (1-180) [(1-630)]", + "ip pim hello (1-65535) [(1-65535)]", IP_STR PIM_STR IFACE_PIM_HELLO_STR @@ -8815,21 +8768,15 @@ DEFUN (interface_ip_pim_hello, DEFUN (interface_no_ip_pim_hello, interface_no_ip_pim_hello_cmd, - "no ip pim hello [(1-180) [(1-630)]]", + "no ip pim hello [(1-65535) [(1-65535)]]", NO_STR IP_STR PIM_STR IFACE_PIM_HELLO_STR - IFACE_PIM_HELLO_TIME_STR - IFACE_PIM_HELLO_HOLD_STR) + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR) { - char hello_default_timer[3]; - - snprintf(hello_default_timer, sizeof(hello_default_timer), "%d", - PIM_DEFAULT_HELLO_PERIOD); - - nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, - hello_default_timer); + nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, "./frr-pim:pim"); @@ -9636,10 +9583,10 @@ DEFUN (no_ip_pim_ucast_bsm, } #if HAVE_BFDD > 0 -DEFUN_HIDDEN( +DEFUN_HIDDEN ( ip_pim_bfd_param, ip_pim_bfd_param_cmd, - "ip pim bfd (2-255) (50-60000) (50-60000)", + "ip pim bfd (2-255) (1-65535) (1-65535)", IP_STR PIM_STR "Enables BFD support\n" @@ -9650,7 +9597,7 @@ DEFUN_HIDDEN( DEFUN( ip_pim_bfd_param, ip_pim_bfd_param_cmd, - "ip pim bfd (2-255) (50-60000) (50-60000)", + "ip pim bfd (2-255) (1-65535) (1-65535)", IP_STR PIM_STR "Enables BFD support\n" @@ -9689,7 +9636,10 @@ DEFUN_HIDDEN( #if HAVE_BFDD == 0 ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, - "no ip pim bfd (2-255) (50-60000) (50-60000)", NO_STR IP_STR PIM_STR + "no ip pim bfd (2-255) (1-65535) (1-65535)", + NO_STR + IP_STR + PIM_STR "Enables BFD support\n" "Detect Multiplier\n" "Required min receive interval\n" @@ -9728,7 +9678,7 @@ DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, } DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, - "ip msdp timers (2-600)$keepalive (3-600)$holdtime [(1-600)$connretry]", + "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", IP_STR CFG_MSDP_STR "MSDP timers configuration\n" @@ -9759,6 +9709,35 @@ DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, return CMD_SUCCESS; } +DEFPY(no_ip_msdp_timers, no_ip_msdp_timers_cmd, + "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", + NO_STR + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR) +{ + const char *vrfname; + char xpath[XPATH_MAXLEN]; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname == NULL) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(xpath, sizeof(xpath), FRR_PIM_MSDP_XPATH, "frr-pim:pimd", + "pim", vrfname, "frr-routing:ipv4"); + + nb_cli_enqueue_change(vty, "./hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, NULL); + + nb_cli_apply_changes(vty, xpath); + + return CMD_SUCCESS; +} + DEFUN (no_ip_msdp_peer, no_ip_msdp_peer_cmd, "no ip msdp peer A.B.C.D", @@ -11383,6 +11362,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &ip_msdp_timers_cmd); install_element(VRF_NODE, &ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); + install_element(VRF_NODE, &no_ip_msdp_timers_cmd); install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 72c726690c..52ded08ae3 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -96,9 +96,9 @@ struct pim_router { int t_periodic; struct pim_assert_metric infinite_assert_metric; long rpf_cache_refresh_delay_msec; - int32_t register_suppress_time; + uint32_t register_suppress_time; int packet_process; - int32_t register_probe_time; + uint32_t register_probe_time; /* * What is the default vrf that we work in diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index bd5e215027..22a98f94dd 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -556,8 +556,27 @@ int pim_join_prune_interval_modify(struct nb_cb_modify_args *args) */ int pim_register_suppress_time_modify(struct nb_cb_modify_args *args) { + uint16_t value; switch (args->event) { case NB_EV_VALIDATE: + value = yang_dnode_get_uint16(args->dnode, NULL); + /* + * As soon as this is non-constant it needs to be replaced with + * a yang_dnode_get to lookup the candidate value, *not* the + * operational value. Since the code has a field assigned and + * used for this value it should have YANG/CLI to set it too, + * otherwise just use the #define! + */ + /* RFC7761: 4.11. Timer Values */ + if (value <= router->register_probe_time * 2) { + snprintf( + args->errmsg, args->errmsg_len, + "Register suppress time (%u) must be more than " + "twice the register probe time (%u).", + value, router->register_probe_time); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: break; @@ -956,21 +975,13 @@ int pim_msdp_hold_time_modify(struct nb_cb_modify_args *args) switch (args->event) { case NB_EV_VALIDATE: - if (yang_dnode_get_uint32(args->dnode, NULL) - <= yang_dnode_get_uint32(args->dnode, "../keep-alive")) { - snprintf( - args->errmsg, args->errmsg_len, - "Hold time must be greater than keep alive interval"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - pim->msdp.hold_time = yang_dnode_get_uint32(args->dnode, NULL); + pim->msdp.hold_time = yang_dnode_get_uint16(args->dnode, NULL); break; } @@ -988,21 +999,13 @@ int pim_msdp_keep_alive_modify(struct nb_cb_modify_args *args) switch (args->event) { case NB_EV_VALIDATE: - if (yang_dnode_get_uint32(args->dnode, NULL) - >= yang_dnode_get_uint32(args->dnode, "../hold-time")) { - snprintf( - args->errmsg, args->errmsg_len, - "Keep alive must be less than hold time interval"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - pim->msdp.keep_alive = yang_dnode_get_uint32(args->dnode, NULL); + pim->msdp.keep_alive = yang_dnode_get_uint16(args->dnode, NULL); break; } @@ -1027,7 +1030,7 @@ int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args) vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; pim->msdp.connection_retry = - yang_dnode_get_uint32(args->dnode, NULL); + yang_dnode_get_uint16(args->dnode, NULL); break; } @@ -2636,9 +2639,7 @@ int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args) int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args) { struct interface *ifp; - struct pim_interface *pim_ifp; int query_interval; - int query_interval_dsec; switch (args->event) { case NB_EV_VALIDATE: @@ -2647,18 +2648,8 @@ int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args) break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - pim_ifp = ifp->info; query_interval = yang_dnode_get_uint16(args->dnode, NULL); - query_interval_dsec = 10 * query_interval; - if (query_interval_dsec <= - pim_ifp->igmp_query_max_response_time_dsec) { - snprintf(args->errmsg, args->errmsg_len, - "Can't set general query interval %d dsec <= query max response time %d dsec.", - query_interval_dsec, - pim_ifp->igmp_query_max_response_time_dsec); - return NB_ERR_INCONSISTENCY; - } - change_query_interval(pim_ifp, query_interval); + change_query_interval(ifp->info, query_interval); } return NB_OK; @@ -2671,9 +2662,7 @@ int lib_interface_igmp_query_max_response_time_modify( struct nb_cb_modify_args *args) { struct interface *ifp; - struct pim_interface *pim_ifp; int query_max_response_time_dsec; - int default_query_interval_dsec; switch (args->event) { case NB_EV_VALIDATE: @@ -2682,22 +2671,9 @@ int lib_interface_igmp_query_max_response_time_modify( break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - pim_ifp = ifp->info; query_max_response_time_dsec = - yang_dnode_get_uint8(args->dnode, NULL); - default_query_interval_dsec = - 10 * pim_ifp->igmp_default_query_interval; - - if (query_max_response_time_dsec - >= default_query_interval_dsec) { - snprintf(args->errmsg, args->errmsg_len, - "Can't set query max response time %d sec >= general query interval %d sec", - query_max_response_time_dsec, - pim_ifp->igmp_default_query_interval); - return NB_ERR_INCONSISTENCY; - } - - change_query_max_response_time(pim_ifp, + yang_dnode_get_uint16(args->dnode, NULL); + change_query_max_response_time(ifp->info, query_max_response_time_dsec); } @@ -2722,8 +2698,8 @@ int lib_interface_igmp_last_member_query_interval_modify( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - last_member_query_interval = yang_dnode_get_uint8(args->dnode, - NULL); + last_member_query_interval = + yang_dnode_get_uint16(args->dnode, NULL); pim_ifp->igmp_specific_query_max_response_time_dsec = last_member_query_interval; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 2b674b4234..d21c7b4008 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1800,12 +1800,16 @@ void pim_upstream_start_register_stop_timer(struct pim_upstream *up, THREAD_OFF(up->t_rs_timer); if (!null_register) { - uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD); - uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD); - time = lower + (frr_weak_random() % (upper - lower + 1)) - - PIM_REGISTER_PROBE_PERIOD; + uint32_t lower = (0.5 * router->register_suppress_time); + uint32_t upper = (1.5 * router->register_suppress_time); + time = lower + (frr_weak_random() % (upper - lower + 1)); + /* Make sure we don't wrap around */ + if (time >= router->register_probe_time) + time -= router->register_probe_time; + else + time = 0; } else - time = PIM_REGISTER_PROBE_PERIOD; + time = router->register_probe_time; if (PIM_DEBUG_PIM_TRACE) { zlog_debug( diff --git a/snapcraft/README.snap_build.md b/snapcraft/README.snap_build.md index e43f63f2d9..f4a38e7f7f 100644 --- a/snapcraft/README.snap_build.md +++ b/snapcraft/README.snap_build.md @@ -1,7 +1,6 @@ Building your own FRRouting Snap ======================================== -(Tested on Ubuntu 16.04 with Snap Version 2, does not work on Ubuntu 15.x -which uses earlier versions of snaps) +(Tested on Ubuntu 18.04) 1. Install snapcraft: @@ -100,6 +99,7 @@ All the commands are prefixed with frr. frr.staticd-debug frr.bfdd-debug frr.fabricd-debug + frr.pathd-debug vtysh can be accessed as frr.vtysh (Make sure you have /snap/bin in your path). If access as `vtysh` instead of `frr.vtysh` is needed, you can enable it diff --git a/snapcraft/README.usage.md b/snapcraft/README.usage.md index 6a0864c8c5..7abc0f6ded 100644 --- a/snapcraft/README.usage.md +++ b/snapcraft/README.usage.md @@ -18,7 +18,8 @@ ie for `ospf6d` (OSPFv3): systemctl enable snap.frr.ospf6d.service The daemons are: `ripd`, `ripngd`, `ospfd`, `ospf6d`, `isisd`, `bgpd`, -`pimd`, `ldpd`, `eigrpd`, `babeld`, `nhrpd`, `bfdd`, `zebra` +`pimd`, `ldpd`, `eigrpd`, `babeld`, `nhrpd`, `bfdd`, `vrrpd`, `pbrd`, +`pathd`, `fabricd`, `staticd`, `zebra` Commands defined by this snap ----------------------------- diff --git a/snapcraft/defaults/pathd.conf.default b/snapcraft/defaults/pathd.conf.default new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/snapcraft/defaults/pathd.conf.default diff --git a/snapcraft/scripts/Makefile b/snapcraft/scripts/Makefile index 0435b3bc52..5aedddcf69 100644 --- a/snapcraft/scripts/Makefile +++ b/snapcraft/scripts/Makefile @@ -19,6 +19,7 @@ install: install -D -m 0755 bfdd-service $(DESTDIR)/bin/ install -D -m 0755 fabricd-service $(DESTDIR)/bin/ install -D -m 0755 vrrpd-service $(DESTDIR)/bin/ + install -D -m 0755 pathd-service $(DESTDIR)/bin/ install -D -m 0755 set-options $(DESTDIR)/bin/ install -D -m 0755 show_version $(DESTDIR)/bin/ diff --git a/snapcraft/scripts/pathd-service b/snapcraft/scripts/pathd-service new file mode 100644 index 0000000000..6473c59d97 --- /dev/null +++ b/snapcraft/scripts/pathd-service @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e -x + +if ! [ -e $SNAP_DATA/pathd.conf ]; then + cp $SNAP/etc/frr/pathd.conf.default $SNAP_DATA/pathd.conf +fi +exec $SNAP/sbin/pathd \ + -f $SNAP_DATA/pathd.conf \ + --pid_file $SNAP_DATA/pathd.pid \ + --socket $SNAP_DATA/zsock \ + --vty_socket $SNAP_DATA + diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index 1836f34979..fca9652db1 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -4,11 +4,12 @@ summary: FRRouting BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP/EIGRP/BFD routing da description: BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP/EIGRP/BFD routing daemon FRRouting (FRR) is free software which manages TCP/IP based routing protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2, - RIPng, PIM, LDP, Babel, EIGRP, PBR (Policy-based routing), BFD and OpenFabric - as well as the IPv6 versions of these. + RIPng, PIM, LDP, Babel, EIGRP, PBR (Policy-based routing), PATHD (Segment + routing), BFD and OpenFabric as well as the IPv6 versions of these. FRRouting (frr) is a fork of Quagga. confinement: strict grade: devel +base: core18 apps: vtysh: @@ -141,6 +142,13 @@ apps: - network - network-bind - network-control + pathd: + command: bin/pathd-service + daemon: simple + plugs: + - network + - network-bind + - network-control set: command: bin/set-options zebra-debug: @@ -245,6 +253,13 @@ apps: - network - network-bind - network-control + pathd-debug: + command: sbin/pathd -f $SNAP_DATA/pathd.conf --pid_file $SNAP_DATA/pathd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA + plugs: + - network + - network-bind + - network-control + parts: rtrlib: build-packages: @@ -254,6 +269,7 @@ parts: - libssh-dev stage-packages: - libssh-4 + - zlib1g prime: - lib/librtr.so* - usr/lib/x86_64-linux-gnu/libssh.so* @@ -268,12 +284,12 @@ parts: - cmake - make - gcc - - libpcre3-dev + - libpcre2-dev stage-packages: - - libpcre3 + - libpcre2-8-0 source: https://github.com/CESNET/libyang.git source-type: git - source-tag: v1.0.184 + source-tag: v2.0.7 plugin: cmake configflags: - -DCMAKE_INSTALL_PREFIX:PATH=/usr @@ -298,7 +314,6 @@ parts: - imagemagick - ghostscript - groff - - hardening-wrapper - libpcre3-dev - chrpath - pkg-config @@ -315,12 +330,20 @@ parts: - logrotate - libcap2 - libtinfo5 - - libreadline6 - - libjson-c2 + - libreadline7 + - libjson-c3 - libc-ares2 - libatm1 - libprotobuf-c1 - libdb5.3 + - libacl1 + - libattr1 + - libaudit1 + - libcap-ng0 + - libpam0g + - libpcre3 + - libselinux1 + - libxtables12 plugin: autotools source: ../frr-@PACKAGE_VERSION@.tar.gz configflags: @@ -367,6 +390,7 @@ parts: bfdd.conf.default: etc/frr/bfdd.conf.default fabricd.conf.default: etc/frr/fabricd.conf.default vrrpd.conf.default: etc/frr/vrrpd.conf.default + pathd.conf.default: etc/frr/pathd.conf.default vtysh.conf.default: etc/frr/vtysh.conf.default staticd.conf.default: etc/frr/staticd.conf.default frr-scripts: @@ -376,6 +400,8 @@ parts: stage-packages: - telnet - traceroute + - libgcc1 + - libstdc++6 plugin: make source: helpers prime: @@ -390,8 +416,3 @@ parts: README.snap_build.md: doc/README.snap_build.md extra_version_info.txt: doc/extra_version_info.txt -passthrough: - layout: - /usr/lib/x86_64-linux-gnu/libyang1: - bind: $SNAP/usr/lib/x86_64-linux-gnu/libyang1 - diff --git a/staticd/static_vty.c b/staticd/static_vty.c index ea09054a23..f16b40a23f 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -325,7 +325,8 @@ static int static_route_leak(struct vty *vty, const char *svrf, dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath); if (!dnode) { - /* Silently return */ + vty_out(vty, + "%% Refusing to remove a non-existent route\n"); return CMD_SUCCESS; } diff --git a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf index 5e736a7fcc..fd57b2c4d5 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf @@ -4,7 +4,7 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.0.2 vrf r1-cust1 + peer 192.168.0.2 vrf r1-bfd-cust1 echo-mode no shutdown ! diff --git a/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf index 5bb45b9863..cf72f30d66 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 101 vrf r1-cust1 +router bgp 101 vrf r1-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.0.2 remote-as 102 diff --git a/tests/topotests/bfd_vrf_topo1/r1/zebra.conf b/tests/topotests/bfd_vrf_topo1/r1/zebra.conf index fcd1e7db17..62ed36fdb8 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/zebra.conf @@ -1,3 +1,3 @@ -interface r1-eth0 vrf r1-cust1 +interface r1-eth0 vrf r1-bfd-cust1 ip address 192.168.0.1/24 ! diff --git a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf index 94f502c7d9..e5539f14e5 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf @@ -4,13 +4,13 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.0.1 vrf r2-cust1 + peer 192.168.0.1 vrf r2-bfd-cust1 receive-interval 1000 transmit-interval 500 echo-mode no shutdown ! - peer 192.168.1.1 vrf r2-cust1 + peer 192.168.1.1 vrf r2-bfd-cust1 echo-mode no shutdown ! diff --git a/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf index b2aac74685..132011cf86 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 102 vrf r2-cust1 +router bgp 102 vrf r2-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.0.1 remote-as 101 diff --git a/tests/topotests/bfd_vrf_topo1/r2/zebra.conf b/tests/topotests/bfd_vrf_topo1/r2/zebra.conf index daffd1912e..1e817b19f6 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/zebra.conf @@ -1,9 +1,9 @@ -interface r2-eth0 vrf r2-cust1 +interface r2-eth0 vrf r2-bfd-cust1 ip address 192.168.0.2/24 ! -interface r2-eth1 vrf r2-cust1 +interface r2-eth1 vrf r2-bfd-cust1 ip address 192.168.1.2/24 ! -interface r2-eth2 vrf r2-cust1 +interface r2-eth2 vrf r2-bfd-cust1 ip address 192.168.2.2/24 ! diff --git a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf index 76910ac927..e1f53e1abc 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf @@ -4,7 +4,7 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.1.2 vrf r3-cust1 + peer 192.168.1.2 vrf r3-bfd-cust1 echo-interval 100 echo-mode no shutdown diff --git a/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf index 1d7c730395..f764647920 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 103 vrf r3-cust1 +router bgp 103 vrf r3-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.1.2 remote-as 102 diff --git a/tests/topotests/bfd_vrf_topo1/r3/zebra.conf b/tests/topotests/bfd_vrf_topo1/r3/zebra.conf index f727c2d633..e67345948e 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/zebra.conf @@ -1,3 +1,3 @@ -interface r3-eth0 vrf r3-cust1 +interface r3-eth0 vrf r3-bfd-cust1 ip address 192.168.1.1/24 ! diff --git a/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf index 63d0da7805..9ef2023b21 100644 --- a/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf @@ -4,7 +4,7 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.2.2 vrf r4-cust1 + peer 192.168.2.2 vrf r4-bfd-cust1 transmit-interval 2000 receive-interval 2000 no shutdown diff --git a/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf index f34035d460..03353e45e3 100644 --- a/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 104 vrf r4-cust1 +router bgp 104 vrf r4-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.2.2 remote-as 102 diff --git a/tests/topotests/bfd_vrf_topo1/r4/zebra.conf b/tests/topotests/bfd_vrf_topo1/r4/zebra.conf index 69770dd2bf..15d3ec1d90 100644 --- a/tests/topotests/bfd_vrf_topo1/r4/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r4/zebra.conf @@ -1,3 +1,3 @@ -interface r4-eth0 vrf r4-cust1 +interface r4-eth0 vrf r4-bfd-cust1 ip address 192.168.2.1/24 ! diff --git a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py index 8a1ffe085d..a342997912 100644 --- a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py @@ -95,20 +95,18 @@ def setup_module(mod): logger.info("Testing with VRF Namespace support") cmds = [ - "if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi", - "ip netns add {0}-cust1", - "ip link set dev {0}-eth0 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth0 up", + "if [ -e /var/run/netns/{0}-bfd-cust1 ] ; then ip netns del {0}-bfd-cust1 ; fi", + "ip netns add {0}-bfd-cust1", + "ip link set dev {0}-eth0 netns {0}-bfd-cust1 up", ] cmds2 = [ - "ip link set dev {0}-eth1 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth1 up", - "ip link set dev {0}-eth2 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth2 up", + "ip link set dev {0}-eth1 netns {0}-bfd-cust1", + "ip netns exec {0}-bfd-cust1 ip link set {0}-eth1 up", + "ip link set dev {0}-eth2 netns {0}-bfd-cust1 up", ] for rname, router in router_list.items(): - # create VRF rx-cust1 and link rx-eth0 to rx-cust1 + # create VRF rx-bfd-cust1 and link rx-eth0 to rx-bfd-cust1 for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) if rname == "r2": @@ -138,11 +136,11 @@ def teardown_module(_mod): # move back rx-eth0 to default VRF # delete rx-vrf cmds = [ - "ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1", - "ip netns delete {0}-cust1", + "ip netns exec {0}-bfd-cust1 ip link set {0}-eth0 netns 1", + "ip netns delete {0}-bfd-cust1", ] cmds2 = [ - "ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1", + "ip netns exec {0}-bfd-cust1 ip link set {0}-eth1 netns 1", "ip netns exec {0}-cust2 ip link set {0}-eth1 netns 1", ] @@ -189,7 +187,7 @@ def test_bgp_convergence(): test_func = partial( topotest.router_json_cmp, router, - "show ip bgp vrf {}-cust1 summary json".format(router.name), + "show ip bgp vrf {}-bfd-cust1 summary json".format(router.name), expected, ) _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0) @@ -211,7 +209,7 @@ def test_bgp_fast_convergence(): test_func = partial( topotest.router_json_cmp, router, - "show ip bgp vrf {}-cust1 json".format(router.name), + "show ip bgp vrf {}-bfd-cust1 json".format(router.name), expected, ) _, res = topotest.run_and_expect(test_func, None, count=40, wait=1) @@ -231,7 +229,7 @@ def test_bfd_fast_convergence(): # Disable r2-eth0 link router2 = tgen.gears["r2"] topotest.interface_set_status( - router2, "r2-eth0", ifaceaction=False, vrf_name="r2-cust1" + router2, "r2-eth0", ifaceaction=False, vrf_name="r2-bfd-cust1" ) # Wait the minimum time we can before checking that BGP/BFD @@ -286,7 +284,7 @@ def test_bgp_fast_reconvergence(): test_func = partial( topotest.router_json_cmp, router, - "show ip bgp vrf {}-cust1 json".format(router.name), + "show ip bgp vrf {}-bfd-cust1 json".format(router.name), expected, ) _, res = topotest.run_and_expect(test_func, None, count=16, wait=1) diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py index e7ce216042..83bf4fcc18 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py @@ -249,6 +249,8 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): This function groups the repetitive function calls into one function. """ + logger.info("configure_gr_followed_by_clear: dut %s peer %s", dut, peer) + result = create_router_bgp(tgen, topo, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -766,9 +768,7 @@ def test_BGP_GR_10_p2(request): # Creating configuration from JSON reset_config_on_routers(tgen) - logger.info( - "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized" - ) + step("Test Setup: [Helper Mode]R3-----R1[Restart Mode] initialized") # Configure graceful-restart input_dict = { @@ -847,6 +847,8 @@ def test_BGP_GR_10_p2(request): configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") for addr_type in ADDR_TYPES: + step("Verifying GR config and operational state for addr_type {}".format(addr_type)) + result = verify_graceful_restart( tgen, topo, addr_type, input_dict, dut="r1", peer="r3" ) @@ -870,7 +872,7 @@ def test_BGP_GR_10_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv4Unicast", dut="r1" + tgen, topo, addr_type, "ipv4Unicast", dut="r1", peer="r3", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result @@ -878,7 +880,7 @@ def test_BGP_GR_10_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv6Unicast", dut="r1" + tgen, topo, addr_type, "ipv6Unicast", dut="r1", peer="r3", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result @@ -886,7 +888,7 @@ def test_BGP_GR_10_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv4Unicast", dut="r3" + tgen, topo, addr_type, "ipv4Unicast", dut="r3", peer="r1", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result @@ -894,12 +896,14 @@ def test_BGP_GR_10_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv6Unicast", dut="r3" + tgen, topo, addr_type, "ipv6Unicast", dut="r3", peer="r1", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result ) + step("Killing bgpd on r1") + # Kill BGPd daemon on R1 kill_router_daemons(tgen, "r1", ["bgpd"]) @@ -917,6 +921,8 @@ def test_BGP_GR_10_p2(request): tc_name, result ) + step("Starting bgpd on r1") + # Start BGPd daemon on R1 start_router_daemons(tgen, "r1", ["bgpd"]) @@ -1671,7 +1677,7 @@ def test_BGP_GR_26_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv4Unicast", dut="r1" + tgen, topo, addr_type, "ipv4Unicast", dut="r1", peer="r3", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result @@ -1679,7 +1685,7 @@ def test_BGP_GR_26_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv6Unicast", dut="r1" + tgen, topo, addr_type, "ipv6Unicast", dut="r1", peer="r3", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result @@ -1687,7 +1693,7 @@ def test_BGP_GR_26_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv4Unicast", dut="r3" + tgen, topo, addr_type, "ipv4Unicast", dut="r3", peer="r1", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result @@ -1695,7 +1701,7 @@ def test_BGP_GR_26_p2(request): # verify multi address family result = verify_gr_address_family( - tgen, topo, addr_type, "ipv6Unicast", dut="r3" + tgen, topo, addr_type, "ipv6Unicast", dut="r3", peer="r1", ) assert result is True, "Testcase {} : Failed \n Error {}".format( tc_name, result diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py index c9a93bd75f..84e10af5b3 100644 --- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py +++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py @@ -178,14 +178,10 @@ NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} LOOPBACK_1 = { "ipv4": "10.10.10.10/32", "ipv6": "10::10:10/128", - "ipv4_mask": "255.255.255.255", - "ipv6_mask": None, } LOOPBACK_2 = { "ipv4": "20.20.20.20/32", "ipv6": "20::20:20/128", - "ipv4_mask": "255.255.255.255", - "ipv6_mask": None, } @@ -1911,7 +1907,6 @@ def test_static_routes_for_inter_vrf_route_leaking_p0(request): "loopback1", LOOPBACK_1[addr_type], "RED_A", - LOOPBACK_1["{}_mask".format(addr_type)], ) create_interface_in_kernel( tgen, @@ -1919,7 +1914,6 @@ def test_static_routes_for_inter_vrf_route_leaking_p0(request): "loopback2", LOOPBACK_2[addr_type], "RED_B", - LOOPBACK_2["{}_mask".format(addr_type)], ) step( @@ -2047,7 +2041,6 @@ def test_inter_vrf_and_intra_vrf_communication_iBGP_p0(request): "loopback1", LOOPBACK_1[addr_type], "RED_A", - LOOPBACK_1["{}_mask".format(addr_type)], ) create_interface_in_kernel( @@ -2056,7 +2049,6 @@ def test_inter_vrf_and_intra_vrf_communication_iBGP_p0(request): "loopback2", LOOPBACK_2[addr_type], "BLUE_A", - LOOPBACK_2["{}_mask".format(addr_type)], ) step( @@ -2216,7 +2208,6 @@ def test_inter_vrf_and_intra_vrf_communication_eBGP_p0(request): "loopback1", LOOPBACK_1[addr_type], "RED_A", - LOOPBACK_1["{}_mask".format(addr_type)], ) create_interface_in_kernel( tgen, @@ -2224,7 +2215,6 @@ def test_inter_vrf_and_intra_vrf_communication_eBGP_p0(request): "loopback2", LOOPBACK_2[addr_type], "BLUE_A", - LOOPBACK_2["{}_mask".format(addr_type)], ) step( diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 37da53fc31..31569e69b4 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -131,8 +131,6 @@ NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} LOOPBACK_2 = { "ipv4": "20.20.20.20/32", "ipv6": "20::20:20/128", - "ipv4_mask": "255.255.255.255", - "ipv6_mask": None, } MAX_PATHS = 2 @@ -1928,7 +1926,6 @@ def test_vrf_route_leaking_next_hop_interface_flapping_p1(request): "loopback2", LOOPBACK_2[addr_type], "RED_B", - LOOPBACK_2["{}_mask".format(addr_type)], ) intf_red1_r11 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"] diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py index e7d70f6d8e..2fe80c77f0 100644 --- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py +++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py @@ -1103,7 +1103,7 @@ def test_next_hop_with_recursive_lookup_p1(request): tc_name, result ) - step("Toggle the interface on R3(ifconfig 192.34).") + step("Toggle the interface on R3.") intf_r3_r4 = topo["routers"]["r3"]["links"]["r4"]["interface"] shutdown_bringup_interface(tgen, "r3", intf_r3_r4) @@ -1161,7 +1161,7 @@ def test_next_hop_with_recursive_lookup_p1(request): tc_name, result ) - step("Toggle the interface on R4(ifconfig 192.34).") + step("Toggle the interface on R4.") intf_r4_r3 = topo["routers"]["r4"]["links"]["r3"]["interface"] shutdown_bringup_interface(tgen, "r4", intf_r4_r3) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py index d6f1058a98..ea1b1a42d7 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py @@ -123,8 +123,6 @@ LOOPBACK_1 = { LOOPBACK_2 = { "ipv4": "10.0.0.16/24", "ipv6": "fd00:0:0:3::5/64", - "ipv4_mask": "255.255.255.0", - "ipv6_mask": None, } PREFERRED_NEXT_HOP = "global" @@ -692,14 +690,13 @@ def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): "loopback2", LOOPBACK_2[addr_type], "ISR", - LOOPBACK_2["{}_mask".format(addr_type)], ) for addr_type in ADDR_TYPES: step( "On router R1 Change the next-hop of static routes in vrf " - "ISR to LOOPBACK_1" + "ISR to LOOPBACK_2" ) input_routes_r1 = { diff --git a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf index cfe3f2e2b5..572dce7455 100644 --- a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf @@ -1,5 +1,5 @@ ! -router bgp 100 vrf r1-cust1 +router bgp 100 vrf r1-bgp-cust1 bgp router-id 10.0.1.1 bgp bestpath as-path multipath-relax no bgp ebgp-requires-policy diff --git a/tests/topotests/bgp_vrf_netns/r1/summary.txt b/tests/topotests/bgp_vrf_netns/r1/summary.txt index 1a079ff130..819f26133f 100644 --- a/tests/topotests/bgp_vrf_netns/r1/summary.txt +++ b/tests/topotests/bgp_vrf_netns/r1/summary.txt @@ -2,7 +2,7 @@ "ipv4Unicast":{ "routerId":"10.0.1.1", "as":100, - "vrfName":"r1-cust1", + "vrfName":"r1-bgp-cust1", "peerCount":1, "peers":{ "10.0.1.101":{ diff --git a/tests/topotests/bgp_vrf_netns/r1/summary20.txt b/tests/topotests/bgp_vrf_netns/r1/summary20.txt index 2b5787e6da..ea04a56d85 100644 --- a/tests/topotests/bgp_vrf_netns/r1/summary20.txt +++ b/tests/topotests/bgp_vrf_netns/r1/summary20.txt @@ -1,7 +1,7 @@ { "routerId":"10.0.1.1", "as":100, - "vrfName":"re1-cust1", + "vrfName":"re1-bgp-cust1", "peerCount":1, "peers":{ "10.0.1.101":{ diff --git a/tests/topotests/bgp_vrf_netns/r1/zebra.conf b/tests/topotests/bgp_vrf_netns/r1/zebra.conf index 817d9544d3..fd0e18f5fd 100644 --- a/tests/topotests/bgp_vrf_netns/r1/zebra.conf +++ b/tests/topotests/bgp_vrf_netns/r1/zebra.conf @@ -1,5 +1,5 @@ ! -interface r1-eth0 vrf r1-cust1 +interface r1-eth0 vrf r1-bgp-cust1 ip address 10.0.1.1/24 ! line vty diff --git a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py index 9889e1cdd5..60511aebde 100644 --- a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py +++ b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py @@ -106,13 +106,12 @@ def setup_module(module): if CustomizeVrfWithNetns == True: logger.info("Testing with VRF Namespace support") - # create VRF r1-cust1 - # move r1-eth0 to VRF r1-cust1 + # create VRF r1-bgp-cust1 + # move r1-eth0 to VRF r1-bgp-cust1 cmds = [ - "if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi", - "ip netns add {0}-cust1", - "ip link set dev {0}-eth0 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth0 up", + "if [ -e /var/run/netns/{0}-bgp-cust1 ] ; then ip netns del {0}-bgp-cust1 ; fi", + "ip netns add {0}-bgp-cust1", + "ip link set {0}-eth0 netns {0}-bgp-cust1 up", ] for cmd in cmds: cmd = cmd.format("r1") @@ -154,10 +153,10 @@ def setup_module(module): def teardown_module(module): tgen = get_topogen() # move back r1-eth0 to default VRF - # delete VRF r1-cust1 + # delete VRF r1-bgp-cust1 cmds = [ - "ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1", - "ip netns delete {0}-cust1", + "ip netns exec {0}-bgp-cust1 ip link set {0}-eth0 netns 1", + "ip netns delete {0}-bgp-cust1", ] for cmd in cmds: tgen.net["r1"].cmd(cmd.format("r1")) @@ -203,7 +202,7 @@ def test_bgp_convergence(): expected = json.loads(open(reffile).read()) test_func = functools.partial( - topotest.router_json_cmp, router, "show bgp vrf r1-cust1 summary json", expected + topotest.router_json_cmp, router, "show bgp vrf r1-bgp-cust1 summary json", expected ) _, res = topotest.run_and_expect(test_func, None, count=90, wait=0.5) assertmsg = "BGP router network did not converge" @@ -231,11 +230,11 @@ def test_bgp_vrf_netns(): test_func = functools.partial( topotest.router_json_cmp, tgen.gears["r1"], - "show ip bgp vrf r1-cust1 ipv4 json", + "show ip bgp vrf r1-bgp-cust1 ipv4 json", expect, ) _, res = topotest.run_and_expect(test_func, None, count=12, wait=0.5) - assertmsg = 'expected routes in "show ip bgp vrf r1-cust1 ipv4" output' + assertmsg = 'expected routes in "show ip bgp vrf r1-bgp-cust1 ipv4" output' assert res is None, assertmsg diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 2f1f67439f..922dee1291 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -3765,7 +3765,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer) @retry(retry_timeout=8) -def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut, expected=True): +def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut, peer, expected=True): """ This API is to verify gr_address_family in the BGP gr capability advertised by the neighbor router @@ -3777,80 +3777,86 @@ def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut, expected=T * `addr_type` : ip type ipv4/ipv6 * `addr_type` : ip type IPV4 Unicast/IPV6 Unicast * `dut`: input dut router name + * `peer`: input peer router to check * `expected` : expected results from API, by-default True Usage ----- - result = verify_gr_address_family(tgen, topo, "ipv4", "ipv4Unicast", "r1") + result = verify_gr_address_family(tgen, topo, "ipv4", "ipv4Unicast", "r1", "r3") Returns ------- - errormsg(str) or True + errormsg(str) or None """ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) - for router, rnode in tgen.routers().items(): - if router != dut: - continue + if not check_address_types(addr_type): + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return - bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] + routers = tgen.routers() + if dut not in routers: + return "{} not in routers".format(dut) - if addr_type in bgp_addr_type: - if not check_address_types(addr_type): - continue + rnode = routers[dut] + bgp_addr_type = topo["routers"][dut]["bgp"]["address_family"] - bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] + if addr_type not in bgp_addr_type: + return "{} not in bgp_addr_types".format(addr_type) - for bgp_neighbor, peer_data in bgp_neighbors.items(): - for dest_link, peer_dict in peer_data["dest_link"].items(): - data = topo["routers"][bgp_neighbor]["links"] + if peer not in bgp_addr_type[addr_type]["unicast"]["neighbor"]: + return "{} not a peer of {} over {}".format(peer, dut, addr_type) - if dest_link in data: - neighbor_ip = data[dest_link][addr_type].split("/")[0] + nbr_links = topo["routers"][peer]["links"] + if dut not in nbr_links or addr_type not in nbr_links[dut]: + return "peer {} missing back link to {} over {}".format(peer, dut, addr_type) - logger.info( - "[DUT: {}]: Checking bgp graceful-restart" - " show o/p {}".format(dut, neighbor_ip) - ) + neighbor_ip = nbr_links[dut][addr_type].split("/")[0] - show_bgp_graceful_json = run_frr_cmd( - rnode, - "show bgp {} neighbor {} graceful-restart json".format( - addr_type, neighbor_ip - ), - isjson=True, - ) + logger.info( + "[DUT: {}]: Checking bgp graceful-restart show o/p {} for {}".format( + dut, neighbor_ip, addr_family + ) + ) - show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip] + show_bgp_graceful_json = run_frr_cmd( + rnode, + "show bgp {} neighbor {} graceful-restart json".format( + addr_type, neighbor_ip + ), + isjson=True, + ) - if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip: - logger.info("Neighbor ip matched {}".format(neighbor_ip)) - else: - errormsg = "Neighbor ip NOT a match {}".format(neighbor_ip) - return errormsg + show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip] - if addr_family == "ipv4Unicast": - if "ipv4Unicast" in show_bgp_graceful_json_out: - logger.info("ipv4Unicast present for {} ".format(neighbor_ip)) - return True - else: - errormsg = "ipv4Unicast NOT present for {} ".format(neighbor_ip) - return errormsg + if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip: + logger.info("Neighbor ip matched {}".format(neighbor_ip)) + else: + errormsg = "Neighbor ip NOT a match {}".format(neighbor_ip) + return errormsg - elif addr_family == "ipv6Unicast": - if "ipv6Unicast" in show_bgp_graceful_json_out: - logger.info("ipv6Unicast present for {} ".format(neighbor_ip)) - return True - else: - errormsg = "ipv6Unicast NOT present for {} ".format(neighbor_ip) - return errormsg - else: - errormsg = "Aaddress family: {} present for {} ".format( - addr_family, neighbor_ip - ) - return errormsg + if addr_family == "ipv4Unicast": + if "ipv4Unicast" in show_bgp_graceful_json_out: + logger.info("ipv4Unicast present for {} ".format(neighbor_ip)) + return True + else: + errormsg = "ipv4Unicast NOT present for {} ".format(neighbor_ip) + return errormsg + + elif addr_family == "ipv6Unicast": + if "ipv6Unicast" in show_bgp_graceful_json_out: + logger.info("ipv6Unicast present for {} ".format(neighbor_ip)) + return True + else: + errormsg = "ipv6Unicast NOT present for {} ".format(neighbor_ip) + return errormsg + else: + errormsg = "Aaddress family: {} present for {} ".format( + addr_family, neighbor_ip + ) + return errormsg logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 22a678862a..3754ad999e 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -971,22 +971,31 @@ def add_interfaces_to_vlan(tgen, input_dict): for intf_dict in interfaces: for interface, data in intf_dict.items(): # Adding interface to VLAN - cmd = "vconfig add {} {}".format(interface, vlan) + vlan_intf = "{}.{}".format(interface, vlan) + cmd = "ip link add link {} name {} type vlan id {}".format( + interface, + vlan_intf, + vlan + ) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) - vlan_intf = "{}.{}".format(interface, vlan) - - ip = data["ip"] - subnet = data["subnet"] - # Bringing interface up - cmd = "ip link set up {}".format(vlan_intf) + cmd = "ip link set {} up".format(vlan_intf) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) # Assigning IP address - cmd = "ifconfig {} {} netmask {}".format(vlan_intf, ip, subnet) + ifaddr = ipaddress.ip_interface( + u"{}/{}".format( + frr_unicode(data["ip"]), + frr_unicode(data["subnet"]) + ) + ) + + cmd = "ip -{0} a flush {1} scope global && ip a add {2} dev {1} && ip l set {1} up".format( + ifaddr.version, vlan_intf, ifaddr + ) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) @@ -1391,15 +1400,20 @@ def create_interface_in_kernel( rnode = tgen.routers()[dut] if create: - cmd = "sudo ip link add name {} type dummy".format(name) + cmd = "ip link show {0} >/dev/null || ip link add {0} type dummy".format(name) rnode.run(cmd) - addr_type = validate_ip_address(ip_addr) - if addr_type == "ipv4": - cmd = "ifconfig {} {} netmask {}".format(name, ip_addr, netmask) + if not netmask: + ifaddr = ipaddress.ip_interface(frr_unicode(ip_addr)) else: - cmd = "ifconfig {} inet6 add {}/{}".format(name, ip_addr, netmask) - + ifaddr = ipaddress.ip_interface(u"{}/{}".format( + frr_unicode(ip_addr), + frr_unicode(netmask) + )) + cmd = "ip -{0} a flush {1} scope global && ip a add {2} dev {1} && ip l set {1} up".format( + ifaddr.version, name, ifaddr + ) + logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) if vrf: @@ -2933,7 +2947,7 @@ def configure_interface_mac(tgen, input_dict): rnode = tgen.routers()[dut] for intf, mac in input_dict[dut].items(): - cmd = "ifconfig {} hw ether {}".format(intf, mac) + cmd = "ip link set {} address {}".format(intf, mac) logger.info("[DUT: %s]: Running command: %s", dut, cmd) try: diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index 7de1c7a2f9..e093e6de53 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -55,7 +55,7 @@ def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True input_dict = { "r1": { "pim": { - "disable" : ["l1-i1-eth1"], + "join-prune-interval": "5", "rp": [{ "rp_addr" : "1.0.3.17". "keep-alive-timer": "100" @@ -90,7 +90,7 @@ def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True if "rp" not in input_dict[router]["pim"]: continue - result = _create_pim_config( + result = _create_pim_rp_config( tgen, topo, input_dict, router, build, load_config ) if result is not True: @@ -100,9 +100,9 @@ def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True return result -def _create_pim_config(tgen, topo, input_dict, router, build=False, load_config=False): +def _create_pim_rp_config(tgen, topo, input_dict, router, build=False, load_config=False): """ - Helper API to create pim configuration. + Helper API to create pim RP configurations. Parameters ---------- @@ -119,96 +119,93 @@ def _create_pim_config(tgen, topo, input_dict, router, build=False, load_config= result = False logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) - try: - pim_data = input_dict[router]["pim"] + pim_data = input_dict[router]["pim"] + rp_data = pim_data["rp"] - for dut in tgen.routers(): - if "pim" not in input_dict[router]: - continue + # Configure this RP on every router. + for dut in tgen.routers(): - for destLink, data in topo[dut]["links"].items(): - if "pim" not in data: - continue + # At least one interface must be enabled for PIM on the router + pim_if_enabled = False + for destLink, data in topo[dut]["links"].items(): + if "pim" in data: + pim_if_enabled = True + if not pim_if_enabled: + continue - if "rp" in pim_data: - config_data = [] - rp_data = pim_data["rp"] + config_data = [] - for rp_dict in deepcopy(rp_data): - # ip address of RP - if "rp_addr" not in rp_dict and build: - logger.error( - "Router %s: 'ip address of RP' not " - "present in input_dict/JSON", - router, - ) + for rp_dict in deepcopy(rp_data): + # ip address of RP + if "rp_addr" not in rp_dict and build: + logger.error( + "Router %s: 'ip address of RP' not " + "present in input_dict/JSON", + router, + ) - return False - rp_addr = rp_dict.setdefault("rp_addr", None) + return False + rp_addr = rp_dict.setdefault("rp_addr", None) - # Keep alive Timer - keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None) + # Keep alive Timer + keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None) - # Group Address range to cover - if "group_addr_range" not in rp_dict and build: - logger.error( - "Router %s:'Group Address range to cover'" - " not present in input_dict/JSON", - router, - ) + # Group Address range to cover + if "group_addr_range" not in rp_dict and build: + logger.error( + "Router %s:'Group Address range to cover'" + " not present in input_dict/JSON", + router, + ) - return False - group_addr_range = rp_dict.setdefault("group_addr_range", None) + return False + group_addr_range = rp_dict.setdefault("group_addr_range", None) - # Group prefix-list filter - prefix_list = rp_dict.setdefault("prefix_list", None) + # Group prefix-list filter + prefix_list = rp_dict.setdefault("prefix_list", None) - # Delete rp config - del_action = rp_dict.setdefault("delete", False) + # Delete rp config + del_action = rp_dict.setdefault("delete", False) - if keep_alive_timer: - cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer) - config_data.append(cmd) + if keep_alive_timer: + cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer) + if del_action: + cmd = "no {}".format(cmd) + config_data.append(cmd) + + if rp_addr: + if group_addr_range: + if type(group_addr_range) is not list: + group_addr_range = [group_addr_range] + for grp_addr in group_addr_range: + cmd = "ip pim rp {} {}".format(rp_addr, grp_addr) if del_action: cmd = "no {}".format(cmd) - config_data.append(cmd) - - if rp_addr: - if group_addr_range: - if type(group_addr_range) is not list: - group_addr_range = [group_addr_range] - - for grp_addr in group_addr_range: - cmd = "ip pim rp {} {}".format(rp_addr, grp_addr) - config_data.append(cmd) - - if del_action: - cmd = "no {}".format(cmd) - config_data.append(cmd) - - if prefix_list: - cmd = "ip pim rp {} prefix-list {}".format( - rp_addr, prefix_list - ) - config_data.append(cmd) + config_data.append(cmd) - if del_action: - cmd = "no {}".format(cmd) - config_data.append(cmd) + if prefix_list: + cmd = "ip pim rp {} prefix-list {}".format( + rp_addr, prefix_list + ) + if del_action: + cmd = "no {}".format(cmd) + config_data.append(cmd) + try: result = create_common_configuration( tgen, dut, config_data, "pim", build, load_config ) if result is not True: + logger.error("Error applying PIM config", exc_info=True) + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return False - except InvalidCLIError: - # Traceback - errormsg = traceback.format_exc() - logger.error(errormsg) - return errormsg + except InvalidCLIError as error: + logger.error("Error applying PIM config: %s", error, exc_info=error) + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return False logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return result @@ -338,35 +335,19 @@ def _enable_disable_pim(tgen, topo, input_dict, router, build=False): try: config_data = [] - enable_flag = True - # Disable pim on interface - if "pim" in input_dict[router]: - if "disable" in input_dict[router]["pim"]: - enable_flag = False - interfaces = input_dict[router]["pim"]["disable"] - - if type(interfaces) is not list: - interfaces = [interfaces] - - for interface in interfaces: - cmd = "interface {}".format(interface) - config_data.append(cmd) - config_data.append("no ip pim") - - # Enable pim on interface - if enable_flag: - for destRouterLink, data in sorted(topo[router]["links"].items()): - if "pim" in data and data["pim"] == "enable": + # Enable pim on interfaces + for destRouterLink, data in sorted(topo[router]["links"].items()): + if "pim" in data and data["pim"] == "enable": - # Loopback interfaces - if "type" in data and data["type"] == "loopback": - interface_name = destRouterLink - else: - interface_name = data["interface"] + # Loopback interfaces + if "type" in data and data["type"] == "loopback": + interface_name = destRouterLink + else: + interface_name = data["interface"] - cmd = "interface {}".format(interface_name) - config_data.append(cmd) - config_data.append("ip pim") + cmd = "interface {}".format(interface_name) + config_data.append(cmd) + config_data.append("ip pim") result = create_common_configuration( tgen, router, config_data, "interface_config", build=build @@ -374,6 +355,22 @@ def _enable_disable_pim(tgen, topo, input_dict, router, build=False): if result is not True: return False + config_data = [] + if "pim" in input_dict[router]: + pim_data = input_dict[router]["pim"] + for t in [ + "join-prune-interval", + "keep-alive-timer", + "register-suppress-time", + ]: + if t in pim_data: + cmd = "ip pim {} {}".format(t, pim_data[t]) + config_data.append(cmd) + + if config_data: + result = create_common_configuration( + tgen, router, config_data, "pim", build=build + ) except InvalidCLIError: # Traceback errormsg = traceback.format_exc() diff --git a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py index 98af4433ab..894326f19f 100644 --- a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py +++ b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py @@ -1008,8 +1008,8 @@ def test_BSM_fragmentation_p1(request): # set mtu of fhr(f1) to i1 interface to 100 so that bsm fragments step("set mtu of fhr(f1) to i1 interface to 100 so that bsm fragments") - fhr_node.run("ifconfig f1-i1-eth2 mtu 100") - inter_node.run("ifconfig i1-f1-eth0 mtu 100") + fhr_node.run("ip link set f1-i1-eth2 mtu 100") + inter_node.run("ip link set i1-f1-eth0 mtu 100") # Use scapy to send pre-defined packet from senser to receiver result = scapy_send_bsr_raw_packet(tgen, topo, "b1", "f1", "packet2") diff --git a/tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json b/tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json index 71454c2ab2..cc20abbe6a 100644 --- a/tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json +++ b/tests/topotests/multicast_pim_sm_topo1/multicast_pim_sm_topo1.json @@ -13,10 +13,12 @@ "r2": {"ipv4": "auto", "pim": "enable"}, "c1": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "igmp": { "interfaces": { "l1-i1-eth1" :{ "igmp":{ + "query": {"query-max-response-time": 40, "query-interval": 5}, "version": "2" } } @@ -38,6 +40,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i3": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["10.0.5.0/24", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24"], "next_hop": "10.0.7.1" @@ -55,6 +58,7 @@ "i2": {"ipv4": "auto", "pim": "enable"}, "i8": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.12.0/24", "10.0.11.0/24"], "next_hop": "10.0.7.2" @@ -71,6 +75,7 @@ "l1": {"ipv4": "auto", "pim": "enable"}, "i4": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.6.0/24", "10.0.3.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.12.0/24", "10.0.10.0/24", "10.0.11.0/24"], "next_hop": "10.0.2.2" @@ -87,6 +92,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i5": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.7.0/24", "10.0.10.0/24", "10.0.11.0/24"], "next_hop": "10.0.3.2" diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py index 99a6e5bacf..36a3103c9d 100755 --- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py +++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py @@ -78,6 +78,7 @@ from lib.common_config import ( step, iperfSendIGMPJoin, addKernelRoute, + apply_raw_config, reset_config_on_routers, iperfSendTraffic, kill_iperf, @@ -1553,8 +1554,10 @@ def test_modify_igmp_max_query_response_timer_p0(request): assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) step("Delete the PIM and IGMP on FRR1") - input_dict_1 = {"l1": {"pim": {"disable": ["l1-i1-eth1"]}}} - result = create_pim_config(tgen, topo, input_dict_1) + raw_config = { + "l1": {"raw_config": ["interface l1-i1-eth1", "no ip pim"]} + } + result = apply_raw_config(tgen, raw_config) assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) input_dict_2 = { diff --git a/tests/topotests/multicast_pim_sm_topo2/multicast_pim_sm_topo2.json b/tests/topotests/multicast_pim_sm_topo2/multicast_pim_sm_topo2.json index 71454c2ab2..cc20abbe6a 100644 --- a/tests/topotests/multicast_pim_sm_topo2/multicast_pim_sm_topo2.json +++ b/tests/topotests/multicast_pim_sm_topo2/multicast_pim_sm_topo2.json @@ -13,10 +13,12 @@ "r2": {"ipv4": "auto", "pim": "enable"}, "c1": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "igmp": { "interfaces": { "l1-i1-eth1" :{ "igmp":{ + "query": {"query-max-response-time": 40, "query-interval": 5}, "version": "2" } } @@ -38,6 +40,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i3": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["10.0.5.0/24", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24"], "next_hop": "10.0.7.1" @@ -55,6 +58,7 @@ "i2": {"ipv4": "auto", "pim": "enable"}, "i8": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.12.0/24", "10.0.11.0/24"], "next_hop": "10.0.7.2" @@ -71,6 +75,7 @@ "l1": {"ipv4": "auto", "pim": "enable"}, "i4": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.6.0/24", "10.0.3.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.12.0/24", "10.0.10.0/24", "10.0.11.0/24"], "next_hop": "10.0.2.2" @@ -87,6 +92,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i5": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.7.0/24", "10.0.10.0/24", "10.0.11.0/24"], "next_hop": "10.0.3.2" diff --git a/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo3.json b/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo3.json index f582f4929d..89c54a41d6 100644 --- a/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo3.json +++ b/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo3.json @@ -13,10 +13,12 @@ "r2": {"ipv4": "auto", "pim": "enable"}, "c1": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "igmp": { "interfaces": { "l1-i1-eth1" :{ "igmp":{ + "query": {"query-max-response-time": 40, "query-interval": 5}, "version": "2" } } @@ -38,6 +40,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i3": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["10.0.5.0/24", "10.0.6.0/24", "1.0.2.2/32", "10.0.1.0/24", "1.0.3.5/32"], "next_hop": "10.0.7.1" @@ -55,6 +58,7 @@ "i2": {"ipv4": "auto", "pim": "enable"}, "i8": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"], "next_hop": "10.0.7.2" @@ -71,6 +75,7 @@ "l1": {"ipv4": "auto", "pim": "enable"}, "i4": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.6.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24"], "next_hop": "10.0.2.2" @@ -87,6 +92,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i5": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.5.17/32", "10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24", "10.0.8.0/24", "10.0.9.0/24", "10.0.10.0/24", "10.0.11.0/24"], "next_hop": "10.0.3.2" diff --git a/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo4.json b/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo4.json index 4635dac7d2..afb55994a7 100644 --- a/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo4.json +++ b/tests/topotests/multicast_pim_sm_topo3/multicast_pim_sm_topo4.json @@ -13,10 +13,12 @@ "r2": {"ipv4": "auto", "pim": "enable"}, "c1": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "igmp": { "interfaces": { "l1-i1-eth1" :{ "igmp":{ + "query": {"query-max-response-time": 40, "query-interval": 5}, "version": "2" } } @@ -40,6 +42,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i3": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["10.0.4.0/24","10.0.3.1/24"], "next_hop": "10.0.7.1" @@ -57,6 +60,7 @@ "i2": {"ipv4": "auto", "pim": "enable"}, "i8": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["10.0.4.0/24","10.0.3.1/24"], "next_hop": "10.0.3.1" @@ -73,6 +77,7 @@ "l1": {"ipv4": "auto", "pim": "enable"}, "i4": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [{ "network": ["1.0.4.11/32","10.0.4.2/24", "10.0.3.1/24"], "next_hop": "10.0.2.2" @@ -87,6 +92,7 @@ "f1": {"ipv4": "auto", "pim": "enable"}, "i5": {"ipv4": "auto", "pim": "enable"} }, + "pim": { "join-prune-interval": "5", "keep-alive-timer": 15, "register-suppress-time": 12 }, "static_routes": [ { "network": ["1.0.4.11/32", "10.0.2.1/24", "10.0.1.2/24"], diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py index 33f476de44..033c76081a 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py @@ -2014,7 +2014,7 @@ def test_verify_remove_add_igmp_commands_when_pim_configured_p0(request): intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] input_dict_1 = { - "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2"}}}}} + "l1": {"igmp": {"interfaces": {intf_l1_i1: {"igmp": {"version": "2", "query": {"query-max-response-time": 40, "query-interval": 5}}}}}} } result = verify_igmp_config(tgen, input_dict_1) @@ -2231,8 +2231,10 @@ def test_verify_remove_add_pim_commands_when_igmp_configured_p1(request): step("Remove 'no ip pim' on receiver interface on FRR1") intf_l1_i1 = topo["routers"]["l1"]["links"]["i1"]["interface"] - input_dict_1 = {"l1": {"pim": {"disable": intf_l1_i1}}} - result = create_pim_config(tgen, topo, input_dict_1) + raw_config = { + "l1": {"raw_config": ["interface {}".format(intf_l1_i1), "no ip pim"]} + } + result = apply_raw_config(tgen, raw_config) assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) step("Verify that no core is observed") diff --git a/tests/topotests/multicast_pim_static_rp_topo1/multicast_pim_static_rp.json b/tests/topotests/multicast_pim_static_rp_topo1/multicast_pim_static_rp.json index 6d6c047b00..39c68408b4 100644 --- a/tests/topotests/multicast_pim_static_rp_topo1/multicast_pim_static_rp.json +++ b/tests/topotests/multicast_pim_static_rp_topo1/multicast_pim_static_rp.json @@ -4,7 +4,11 @@ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24}, "lo_prefix": {"ipv4": "1.0.", "v4mask": 32}, "routers": { - "r0": {"links": {"r1": {"ipv4": "auto"}}}, + "r0": { + "links": { + "r1": {"ipv4": "auto"} + } + }, "r1": { "links": { "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, @@ -14,9 +18,20 @@ "r4": {"ipv4": "auto", "pim": "enable"} }, "pim": { - "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": ["224.0.0.0/4"]}] + "join-prune-interval": "5", + "keep-alive-timer": 15, + "register-suppress-time": 12 + }, + "igmp": { + "interfaces": { + "r1-r0-eth0": { + "igmp": { + "query": {"query-max-response-time": 40, "query-interval": 5}, + "version": "2" + } + } + } }, - "igmp": {"interfaces": {"r1-r0-eth0": {"igmp": {"version": "2"}}}}, "static_routes": [ {"network": "10.0.4.0/24", "next_hop": "10.0.2.2"}, {"network": "10.0.5.0/24", "next_hop": "10.0.2.2"}, @@ -35,6 +50,9 @@ "r3": {"ipv4": "auto", "pim": "enable"} }, "pim": { + "join-prune-interval": "5", + "keep-alive-timer": 15, + "register-suppress-time": 12, "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": ["224.0.0.0/4"]}] }, "static_routes": [ @@ -57,7 +75,9 @@ "r5": {"ipv4": "auto", "pim": "enable"} }, "pim": { - "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": ["224.0.0.0/4"]}] + "join-prune-interval": "5", + "keep-alive-timer": 15, + "register-suppress-time": 12 }, "static_routes": [ {"network": "10.0.0.0/24", "next_hop": "10.0.2.1"}, @@ -75,7 +95,9 @@ "r3": {"ipv4": "auto", "pim": "enable"} }, "pim": { - "rp": [{"rp_addr": "1.0.2.17", "group_addr_range": ["224.0.0.0/4"]}] + "join-prune-interval": "5", + "keep-alive-timer": 15, + "register-suppress-time": 12 }, "static_routes": [ {"network": "10.0.0.0/24", "next_hop": "10.0.3.1"}, @@ -88,6 +110,10 @@ {"network": "1.0.3.17/32", "next_hop": "10.0.5.1"} ] }, - "r5": {"links": {"r3": {"ipv4": "auto"}}} + "r5": { + "links": { + "r3": {"ipv4": "auto"} + } + } } } diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index a595bc0491..374d68509c 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -1011,7 +1011,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): r0_r1_intf = topo["routers"]["r0"]["links"]["r1"]["interface"] r1_r0_intf = topo["routers"]["r1"]["links"]["r0"]["interface"] - rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1200".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1037,7 +1037,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): "Modify the MTU to non default Value on R0 to R1 interface. " "Reset ospf neighbors on R0." ) - rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1500".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1062,7 +1062,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): result = config_ospf_interface(tgen, topo, r1_ospf_mtu) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1200".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1094,7 +1094,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): step("Modify the MTU to again default valaue on R0 to R1 interface.") - rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1500".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1106,8 +1106,8 @@ def test_ospf_tc4_mtu_ignore_p0(request): "Configure ospf interface with jumbo MTU (9216)." "Reset ospf neighbors on R0." ) - rtr0.run("ifconfig {} mtu 9216".format(r0_r1_intf)) - rtr1.run("ifconfig {} mtu 9216".format(r1_r0_intf)) + rtr0.run("ip link set {} mtu 9216".format(r0_r1_intf)) + rtr1.run("ip link set {} mtu 9216".format(r1_r0_intf)) clear_ospf(tgen, "r0") clear_ospf(tgen, "r1") diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf index 9a68635568..e1e2bfb99a 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf +++ b/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf @@ -3,7 +3,7 @@ hostname r1 password zebra log file /tmp/r1-ospfd.log ! -router ospf vrf r1-cust1 +router ospf vrf r1-ospf-cust1 ospf router-id 10.0.255.1 redistribute kernel redistribute connected diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt index 134a10a454..d617ab36d9 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt @@ -1,4 +1,4 @@ -VRF Name: r1-cust1 +VRF Name: r1-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [10] area: 0.0.0.0 directly attached to r1-eth0 diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt index 083d77126c..4f7fd699cf 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt @@ -1,4 +1,4 @@ -VRF Name: r1-cust1 +VRF Name: r1-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [10] area: 0.0.0.0 directly attached to r1-eth0 diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf b/tests/topotests/ospf_topo1_vrf/r1/zebra.conf index e826793657..e100d3b121 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf +++ b/tests/topotests/ospf_topo1_vrf/r1/zebra.conf @@ -7,10 +7,10 @@ hostname r1 password zebra log file /tmp/r1-zebra.log ! -interface r1-eth0 vrf r1-cust1 +interface r1-eth0 vrf r1-ospf-cust1 ip address 10.0.1.1/24 ! -interface r1-eth1 vrf r1-cust1 +interface r1-eth1 vrf r1-ospf-cust1 ip address 10.0.3.2/24 ! ip forwarding diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt index d72aa3b8e5..979af20c59 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt @@ -1,4 +1,4 @@ -VRF r1-cust1: +VRF r1-ospf-cust1: O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt index 5ea6bdc04d..ec99fad762 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt @@ -1,4 +1,4 @@ -VRF r1-cust1: +VRF r1-ospf-cust1: O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf index ad481a996d..c1984276f4 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf +++ b/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf @@ -4,7 +4,7 @@ password zebra log file /tmp/r2-ospfd.log ! ! -router ospf vrf r2-cust1 +router ospf vrf r2-ospf-cust1 ospf router-id 10.0.255.2 redistribute kernel redistribute connected diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt index a49cb77249..89763ff733 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt @@ -1,4 +1,4 @@ -VRF Name: r2-cust1 +VRF Name: r2-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [20] area: 0.0.0.0 via 10.0.3.2, r2-eth1 diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt index 2227bedf07..d946f02dfd 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt @@ -1,4 +1,4 @@ -VRF Name: r2-cust1 +VRF Name: r2-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [20] area: 0.0.0.0 via 10.0.3.2, r2-eth1 diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebra.conf b/tests/topotests/ospf_topo1_vrf/r2/zebra.conf index 8dcb713da6..6ff72d1267 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/zebra.conf +++ b/tests/topotests/ospf_topo1_vrf/r2/zebra.conf @@ -3,10 +3,10 @@ hostname r2 password zebra log file /tmp/r2-zebra.log ! -interface r2-eth0 vrf r2-cust1 +interface r2-eth0 vrf r2-ospf-cust1 ip address 10.0.2.1/24 ! -interface r2-eth1 vrf r2-cust1 +interface r2-eth1 vrf r2-ospf-cust1 ip address 10.0.3.3/24 ! ip forwarding diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt index ce5e5f3bab..df66e92abc 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt @@ -1,4 +1,4 @@ -VRF r2-cust1: +VRF r2-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt index 157811ec77..4afc354ca7 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt @@ -1,4 +1,4 @@ -VRF r2-cust1: +VRF r2-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf index d5214f734e..b73d547e3e 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf +++ b/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf @@ -4,7 +4,7 @@ password zebra log file /tmp/r3-ospfd.log ! ! -router ospf vrf r3-cust1 +router ospf vrf r3-ospf-cust1 ospf router-id 10.0.255.3 redistribute kernel redistribute connected diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt index 3b16bfbd55..917702b14c 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt @@ -1,4 +1,4 @@ -VRF Name: r3-cust1 +VRF Name: r3-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [20] area: 0.0.0.0 via 10.0.3.2, r3-eth0 diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt index 39beac7a73..966185e495 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt @@ -1,4 +1,4 @@ -VRF Name: r3-cust1 +VRF Name: r3-ospf-cust1 ============ OSPF network routing table ============ N 10.0.10.0/24 [10] area: 0.0.0.0 directly attached to r3-eth1 diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebra.conf b/tests/topotests/ospf_topo1_vrf/r3/zebra.conf index b548694330..1534150048 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/zebra.conf +++ b/tests/topotests/ospf_topo1_vrf/r3/zebra.conf @@ -3,10 +3,10 @@ hostname r3 password zebra log file /tmp/r3-zebra.log ! -interface r3-eth0 vrf r3-cust1 +interface r3-eth0 vrf r3-ospf-cust1 ip address 10.0.3.1/24 ! -interface r3-eth1 vrf r3-cust1 +interface r3-eth1 vrf r3-ospf-cust1 ip address 10.0.10.1/24 ! ip forwarding diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt index f40b7b09af..b435c2ebe5 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt @@ -1,4 +1,4 @@ -VRF r3-cust1: +VRF r3-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r3-eth0, weight 1, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r3-eth0, weight 1, XX:XX:XX O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt index 89cd6f56c4..f30a4be6c6 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt @@ -1,4 +1,4 @@ -VRF r3-cust1: +VRF r3-ospf-cust1: O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py b/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py index e2cb7bff03..713a65a812 100644 --- a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py +++ b/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py @@ -100,17 +100,17 @@ def setup_module(mod): logger.info("Testing with VRF Namespace support") cmds = [ - "if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi", - "ip netns add {0}-cust1", - "ip link set dev {0}-eth0 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth0 up", - "ip link set dev {0}-eth1 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth1 up", + "if [ -e /var/run/netns/{0}-ospf-cust1 ] ; then ip netns del {0}-ospf-cust1 ; fi", + "ip netns add {0}-ospf-cust1", + "ip link set dev {0}-eth0 netns {0}-ospf-cust1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth0 up", + "ip link set dev {0}-eth1 netns {0}-ospf-cust1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth1 up", ] for rname, router in router_list.items(): - # create VRF rx-cust1 and link rx-eth0 to rx-cust1 + # create VRF rx-ospf-cust1 and link rx-eth0 to rx-ospf-cust1 for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) @@ -137,9 +137,9 @@ def teardown_module(mod): # move back rx-eth0 to default VRF # delete rx-vrf cmds = [ - "ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1", - "ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1", - "ip netns delete {0}-cust1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth0 netns 1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth1 netns 1", + "ip netns delete {0}-ospf-cust1", ] router_list = tgen.routers() @@ -152,11 +152,11 @@ def teardown_module(mod): # Shared test function to validate expected output. def compare_show_ip_route_vrf(rname, expected): """ - Calls 'show ip ospf vrf [rname]-cust1 route' for router `rname` and compare the obtained + Calls 'show ip ospf vrf [rname]-ospf-cust1 route' for router `rname` and compare the obtained result with the expected output. """ tgen = get_topogen() - vrf_name = "{0}-cust1".format(rname) + vrf_name = "{0}-ospf-cust1".format(rname) current = topotest.ip4_route_zebra(tgen.gears[rname], vrf_name) ret = topotest.difflines( current, expected, title1="Current output", title2="Expected output" @@ -182,7 +182,7 @@ def test_ospf_convergence(): test_func = partial( topotest.router_output_cmp, router, - "show ip ospf vrf {0}-cust1 route".format(rname), + "show ip ospf vrf {0}-ospf-cust1 route".format(rname), expected, ) result, diff = topotest.run_and_expect(test_func, "", count=160, wait=0.5) @@ -220,13 +220,13 @@ def test_ospf_json(): for rname, router in tgen.routers().items(): logger.info( - 'Comparing router "%s" "show ip ospf vrf %s-cust1 json" output', + 'Comparing router "%s" "show ip ospf vrf %s-ospf-cust1 json" output', router.name, router.name, ) expected = { - "{}-cust1".format(router.name): { - "vrfName": "{}-cust1".format(router.name), + "{}-ospf-cust1".format(router.name): { + "vrfName": "{}-ospf-cust1".format(router.name), "routerId": "10.0.255.{}".format(rname[1:]), "tosRoutesOnly": True, "rfc2328Conform": True, @@ -244,7 +244,7 @@ def test_ospf_json(): } # Area specific additional checks if router.name == "r1" or router.name == "r2" or router.name == "r3": - expected["{}-cust1".format(router.name)]["areas"]["0.0.0.0"] = { + expected["{}-ospf-cust1".format(router.name)]["areas"]["0.0.0.0"] = { "areaIfActiveCounter": 2, "areaIfTotalCounter": 2, "authentication": "authenticationNone", @@ -263,7 +263,7 @@ def test_ospf_json(): test_func = partial( topotest.router_json_cmp, router, - "show ip ospf vrf {0}-cust1 json".format(rname), + "show ip ospf vrf {0}-ospf-cust1 json".format(rname), expected, ) _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) @@ -281,7 +281,7 @@ def test_ospf_link_down(): # Simulate a network down event on router3 switch3 interface. router3 = tgen.gears["r3"] topotest.interface_set_status( - router3, "r3-eth0", ifaceaction=False, vrf_name="r3-cust1" + router3, "r3-eth0", ifaceaction=False, vrf_name="r3-ospf-cust1" ) # Expect convergence on all routers @@ -295,7 +295,7 @@ def test_ospf_link_down(): test_func = partial( topotest.router_output_cmp, router, - "show ip ospf vrf {0}-cust1 route".format(rname), + "show ip ospf vrf {0}-ospf-cust1 route".format(rname), expected, ) result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) @@ -316,7 +316,7 @@ def test_ospf_link_down_kernel_route(): 'Checking OSPF IPv4 kernel routes in "%s" after link down', router.name ) - str = "{0}-cust1".format(router.name) + str = "{0}-ospf-cust1".format(router.name) reffile = os.path.join(CWD, "{}/zebraroutedown.txt".format(router.name)) expected = open(reffile).read() # Run test function until we get an result. Wait at most 60 seconds. diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index 56d112b7c3..778a710ee3 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -104,13 +104,19 @@ def test_zebra_kernel_admin_distance(): r1 = tgen.gears["r1"] # Route with 255/8192 metric - r1.run("ip route add 4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric 4278198272") + + distance = 255 + metric = 8192 + def makekmetric(dist, metric): + return (dist << 24) + metric + + r1.run("ip route add 4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric " + str(makekmetric(255, 8192))) # Route with 1/1 metric - r1.run("ip route add 4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric 16777217") + r1.run("ip route add 4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric " + str(makekmetric(1, 1))) # Route with 10/1 metric - r1.run("ip route add 4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric 167772161") + r1.run("ip route add 4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric " + str(makekmetric(10, 1))) # Same route with a 160/1 metric - r1.run("ip route add 4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric 2684354561") + r1.run("ip route add 4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric " + str(makekmetric(160, 1))) # Currently I believe we have a bug here with the same route and different # metric. That needs to be properly resolved. Making a note for @@ -194,93 +200,69 @@ def test_route_map_usage(): static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir) expected = open(static_rmapfile).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").rstrip() - actual = r1.vtysh_cmd("show route-map static") - actual = ("\n".join(actual.splitlines()) + "\n").rstrip() logger.info( "Does the show route-map static command run the correct number of times" ) - - diff = topotest.get_textdiff( - actual, - expected, - title1="Actual Route-map output", - title2="Expected Route-map output", - ) - if diff: - logger.info("Actual:") - logger.info(actual) - logger.info("Expected:") - logger.info(expected) - srun = r1.vtysh_cmd("show run") - srun = ("\n".join(srun.splitlines()) + "\n").rstrip() - logger.info("Show run") - logger.info(srun) - assert 0, "r1 static route processing:\n" + def check_static_map_correct_runs(): + actual = r1.vtysh_cmd("show route-map static") + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() + return topotest.get_textdiff( + actual, + expected, + title1="Actual Route-map output", + title2="Expected Route-map output", + ) + ok, result = topotest.run_and_expect(check_static_map_correct_runs, "", count=5, wait=1) + assert ok, result sharp_rmapfile = "%s/r1/sharp_rmap.ref" % (thisDir) expected = open(sharp_rmapfile).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").rstrip() - actual = r1.vtysh_cmd("show route-map sharp") - actual = ("\n".join(actual.splitlines()) + "\n").rstrip() logger.info("Does the show route-map sharp command run the correct number of times") - - diff = topotest.get_textdiff( - actual, - expected, - title1="Actual Route-map output", - title2="Expected Route-map output", - ) - if diff: - logger.info("Actual:") - logger.info(actual) - logger.info("Expected:") - logger.info(expected) - srun = r1.vtysh_cmd("show run") - srun = ("\n".join(srun.splitlines()) + "\n").rstrip() - logger.info("Show run:") - logger.info(srun) - assert 0, "r1 sharp route-map processing:\n" + def check_sharp_map_correct_runs(): + actual = r1.vtysh_cmd("show route-map sharp") + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() + return topotest.get_textdiff( + actual, + expected, + title1="Actual Route-map output", + title2="Expected Route-map output", + ) + ok, result = topotest.run_and_expect(check_sharp_map_correct_runs, "", count=5, wait=1) + assert ok, result logger.info( "Add a extension to the static route-map to see the static route go away" + " and test that the routes installed are correct" ) + r1.vtysh_cmd("conf\nroute-map sharp deny 5\nmatch ip address 5") - sleep(2) # we are only checking the kernel here as that this will give us the implied # testing of both the route-map and staticd withdrawing the route # let's spot check that the routes were installed correctly # in the kernel - logger.info("Test that the routes installed are correct") sharp_ipfile = "%s/r1/iproute.ref" % (thisDir) expected = open(sharp_ipfile).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").rstrip() - actual = r1.run("ip route show") - actual = ("\n".join(actual.splitlines()) + "\n").rstrip() - actual = re.sub(r" nhid [0-9][0-9]", "", actual) - actual = re.sub(r" proto sharp", " proto XXXX", actual) - actual = re.sub(r" proto static", " proto XXXX", actual) - actual = re.sub(r" proto 194", " proto XXXX", actual) - actual = re.sub(r" proto 196", " proto XXXX", actual) - actual = re.sub(r" proto kernel", " proto XXXX", actual) - actual = re.sub(r" proto 2", " proto XXXX", actual) - # Some platforms have double spaces? Why?????? - actual = re.sub(r" proto XXXX ", " proto XXXX ", actual) - actual = re.sub(r" metric", " metric", actual) - actual = re.sub(r" link ", " link ", actual) - diff = topotest.get_textdiff( - actual, expected, title1="Actual ip route show", title2="Expected ip route show" - ) - - if diff: - logger.info("Actual:") - logger.info(actual) - logger.info("Expected:") - logger.info(expected) - srun = r1.vtysh_cmd("show run") - srun = ("\n".join(srun.splitlines()) + "\n").rstrip() - logger.info("Show run:") - logger.info(srun) - assert 0, "r1 ip route show is not correct:" + def check_routes_installed(): + actual = r1.run("ip route show") + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() + actual = re.sub(r" nhid [0-9][0-9]", "", actual) + actual = re.sub(r" proto sharp", " proto XXXX", actual) + actual = re.sub(r" proto static", " proto XXXX", actual) + actual = re.sub(r" proto 194", " proto XXXX", actual) + actual = re.sub(r" proto 196", " proto XXXX", actual) + actual = re.sub(r" proto kernel", " proto XXXX", actual) + actual = re.sub(r" proto 2", " proto XXXX", actual) + # Some platforms have double spaces? Why?????? + actual = re.sub(r" proto XXXX ", " proto XXXX ", actual) + actual = re.sub(r" metric", " metric", actual) + actual = re.sub(r" link ", " link ", actual) + return topotest.get_textdiff( + actual, expected, title1="Actual ip route show", title2="Expected ip route show" + ) + ok, result = topotest.run_and_expect(check_routes_installed, "", count=5, wait=1) + assert ok, result def test_memory_leak(): diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index 750fa6b39f..e223eb2743 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -85,12 +85,18 @@ CMD_LIST_END # OSPF Support Bundle Command List PROC_NAME:ospf CMD_LIST_START -show ip ospf -show ip ospf vrfs show ip ospf vrf all +show ip ospf vrfs + show ip ospf vrf all interface +show ip ospf vrf all interface traffic show ip ospf vrf all neighbor -show ip ospf vrf all neighbor detail +show ip ospf vrf all neighbor detail all +show ip ospf vrf all graceful-restart helper detail + +show ip ospf vrf all border-routers +show ip ospf vrf all summary-address detail + show ip ospf vrf all database show ip ospf vrf all database router show ip ospf vrf all database network @@ -101,16 +107,20 @@ show ip ospf vrf all database opaque-area show ip ospf vrf all database opaque-as show ip ospf vrf all database opaque-link show ip ospf vrf all database nssa-external +show ip ospf database segment-routing show ip ospf vrf all database max-age show ip ospf vrf all database self-originate show ip ospf vrf all route + +show ip ospf mpls ldp-sync +show ip ospf mpls ldp-sync interface all + show ip ospf vrf all mpls-te interface -show ip ospf vrf all interface traffic +show ip ospf mpls-te database verbose show ip ospf mpls-te router + show ip ospf router-info show ip ospf router-info pce -show ip ospf database segment-routing -show debugging CMD_LIST_END # RIP Support Bundle Command List diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 4d8b6062ac..998ead6b76 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2237,8 +2237,7 @@ DEFUNSH(VTYSH_PATHD, pcep, pcep_cmd, } DEFUNSH(VTYSH_PATHD, pcep_cli_pcc, pcep_cli_pcc_cmd, - "[no] pcc", - NO_STR + "pcc", "PCC configuration\n") { vty->node = PCEP_PCC_NODE; @@ -2246,8 +2245,7 @@ DEFUNSH(VTYSH_PATHD, pcep_cli_pcc, pcep_cli_pcc_cmd, } DEFUNSH(VTYSH_PATHD, pcep_cli_pce, pcep_cli_pce_cmd, - "[no] pce WORD", - NO_STR + "pce WORD", "PCE configuration\n" "Peer name\n") { @@ -2256,8 +2254,7 @@ DEFUNSH(VTYSH_PATHD, pcep_cli_pce, pcep_cli_pce_cmd, } DEFUNSH(VTYSH_PATHD, pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd, - "[no] pce-config WORD", - NO_STR + "pce-config WORD", "PCEP peer Configuration Group\n" "PCEP peer Configuration Group name\n") { diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang index 9a864213ee..46a9100ab2 100644 --- a/yang/frr-filter.yang +++ b/yang/frr-filter.yang @@ -145,6 +145,7 @@ module frr-filter { leaf ipv4-prefix { description "Configure IPv4 prefix to match"; type inet:ipv4-prefix; + mandatory true; } leaf ipv4-exact-match { @@ -216,6 +217,7 @@ module frr-filter { leaf ipv6-prefix { description "Configure IPv6 prefix to match"; type inet:ipv6-prefix; + mandatory true; } leaf ipv6-exact-match { @@ -277,7 +279,7 @@ module frr-filter { key "sequence"; leaf sequence { - description "Access list sequence value"; + description "Prefix list sequence value"; type access-list-sequence; } @@ -295,6 +297,7 @@ module frr-filter { leaf ipv4-prefix { description "Configure IPv4 prefix to match"; type inet:ipv4-prefix; + mandatory true; } leaf ipv4-prefix-length-greater-or-equal { @@ -319,6 +322,7 @@ module frr-filter { leaf ipv6-prefix { description "Configure IPv6 prefix to match"; type inet:ipv6-prefix; + mandatory true; } leaf ipv6-prefix-length-greater-or-equal { diff --git a/yang/frr-igmp.yang b/yang/frr-igmp.yang index e2971dc5cf..8d151e430d 100644 --- a/yang/frr-igmp.yang +++ b/yang/frr-igmp.yang @@ -84,9 +84,10 @@ module frr-igmp { leaf query-interval { type uint16 { - range "1..1800"; + range "1..max"; } units seconds; + must ". * 10 >= ../query-max-response-time"; default "125"; description "The Query Interval is the interval between General Queries @@ -94,10 +95,11 @@ module frr-igmp { } leaf query-max-response-time { - type uint8 { - range "10..250"; + type uint16 { + range "1..max"; } units deciseconds; + must ". <= ../query-interval * 10"; default "100"; description "Query maximum response time specifies the maximum time @@ -105,8 +107,8 @@ module frr-igmp { } leaf last-member-query-interval { - type uint8 { - range "1..255"; + type uint16 { + range "1..max"; } units deciseconds; default "10"; @@ -117,7 +119,7 @@ module frr-igmp { leaf robustness-variable { type uint8 { - range "1..7"; + range "1..max"; } default "2"; description diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index e846ffa1f8..109ce22309 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -97,7 +97,7 @@ module frr-pim { leaf keep-alive-timer { type uint16 { - range "31..60000"; + range "1..max"; } default "210"; description @@ -106,7 +106,7 @@ module frr-pim { leaf rp-keep-alive-timer { type uint16 { - range "31..60000"; + range "1..max"; } default "210"; description @@ -116,36 +116,34 @@ module frr-pim { grouping msdp-timers { leaf hold-time { - type uint32 { - range 3..600; + type uint16 { + range "1..max"; } units seconds; default 75; description "Hold period is started at the MSDP peer connection establishment and is reset every new message. When the period expires the - connection is closed. - - This value needs to be greater than `keep-alive-period`."; + connection is closed. This value should be greater than the + remote keep-alive time."; } leaf keep-alive { - type uint32 { - range 2..600; + type uint16 { + range "1..max"; } units seconds; default 60; description "To maintain a connection established it is necessary to send keep alive messages in a certain frequency and this allows its - configuration. - - This value needs to be lesser than `hold-time-period`."; + configuration. This value should be less than the remote + hold time."; } leaf connection-retry { - type uint32 { - range 1..600; + type uint16 { + range "1..max"; } units seconds; default 30; @@ -343,7 +341,7 @@ module frr-pim { leaf hello-interval { type uint8 { - range "1..180"; + range "1..max"; } default "30"; description @@ -352,7 +350,7 @@ module frr-pim { leaf hello-holdtime { type uint16 { - range "1..630"; + range "1..max"; } must ". > ./../hello-interval" { error-message "HoldTime must be greater than Hello"; @@ -367,7 +365,7 @@ module frr-pim { leaf min-rx-interval { type uint16 { - range "50..60000"; + range "1..max"; } default "300"; description @@ -376,7 +374,7 @@ module frr-pim { leaf min-tx-interval { type uint16 { - range "50..60000"; + range "1..max"; } default "300"; description @@ -422,7 +420,7 @@ module frr-pim { leaf dr-priority { type uint32 { - range "1..4294967295"; + range "1..max"; } default 1; description @@ -521,7 +519,7 @@ module frr-pim { "PIM router parameters."; leaf packets { type uint8 { - range "1..100"; + range "1..max"; } default "3"; description @@ -529,7 +527,7 @@ module frr-pim { } leaf join-prune-interval { type uint16 { - range "5..600"; + range "1..max"; } default "60"; description @@ -537,7 +535,7 @@ module frr-pim { } leaf register-suppress-time { type uint16 { - range "5..60000"; + range "1..max"; } default "60"; description diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 011883649d..effec24c1f 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -350,21 +350,9 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELADDR: return netlink_interface_addr(h, ns_id, startup); case RTM_NEWNEIGH: - return netlink_neigh_change(h, ns_id); case RTM_DELNEIGH: - return netlink_neigh_change(h, ns_id); case RTM_GETNEIGH: - /* - * Kernel in some situations when it expects - * user space to resolve arp entries, we will - * receive this notification. As we don't - * need this notification and as that - * we don't want to spam the log file with - * below messages, just ignore. - */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Received RTM_GETNEIGH, ignoring"); - break; + return netlink_neigh_change(h, ns_id); case RTM_NEWRULE: return netlink_rule_change(h, ns_id, startup); case RTM_DELRULE: diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 66208bfd80..ddd6a74c0b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -867,7 +867,7 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, } void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, - uint16_t note) + enum zapi_iptable_notify_owner note) { struct listnode *node; struct zserv *client; @@ -901,7 +901,8 @@ void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, zserv_send_message(client, s); } -void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, uint16_t note) +void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, + enum zapi_ipset_notify_owner note) { struct listnode *node; struct zserv *client; @@ -936,7 +937,7 @@ void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, uint16_t note) } void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, - uint16_t note) + enum zapi_ipset_entry_notify_owner note) { struct listnode *node; struct zserv *client; diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index e991dca4f3..dad40c200d 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -87,11 +87,12 @@ extern void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, enum zapi_rule_notify_owner note); extern void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, - uint16_t note); + enum zapi_iptable_notify_owner note); extern void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, - uint16_t note); -extern void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, - uint16_t note); + enum zapi_ipset_notify_owner note); +extern void +zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, + enum zapi_ipset_entry_notify_owner note); extern bool zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 2f83fe4e28..c9450541e8 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -1295,6 +1295,9 @@ static zebra_nhlfe_t *nhlfe_alloc(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, nexthop->ifindex = ifindex; break; case NEXTHOP_TYPE_BLACKHOLE: + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("%s: invalid: blackhole nexthop", __func__); + nexthop_free(nexthop); XFREE(MTYPE_NHLFE, nhlfe); return NULL; @@ -1319,6 +1322,14 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, if (!lsp) return NULL; + /* Must have labels */ + if (num_labels == 0 || labels == NULL) { + if (IS_ZEBRA_DEBUG_MPLS) + zlog_debug("%s: invalid nexthop: no labels", __func__); + + return NULL; + } + /* Allocate new object */ nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels, labels); @@ -1530,8 +1541,13 @@ static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe) ifindex2ifname(nexthop->ifindex, nexthop->vrf_id)); break; - case NEXTHOP_TYPE_BLACKHOLE: case NEXTHOP_TYPE_IFINDEX: + if (nexthop->ifindex) + json_object_string_add(json_nhlfe, "interface", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: break; } @@ -1592,8 +1608,13 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty, ifindex2ifname(nexthop->ifindex, nexthop->vrf_id)); break; - case NEXTHOP_TYPE_BLACKHOLE: case NEXTHOP_TYPE_IFINDEX: + if (nexthop->ifindex) + vty_out(vty, " dev %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: break; } vty_out(vty, "%s", @@ -2835,9 +2856,21 @@ static bool ftn_update_znh(bool add_p, enum lsp_types_t type, break; success = true; break; - case NEXTHOP_TYPE_BLACKHOLE: case NEXTHOP_TYPE_IFINDEX: + if (znh->type != NEXTHOP_TYPE_IFINDEX) + continue; + if (nexthop->ifindex != znh->ifindex) + continue; + + found = true; + + if (!ftn_update_nexthop(add_p, nexthop, type, znh)) + break; + success = true; break; + case NEXTHOP_TYPE_BLACKHOLE: + /* Not valid */ + continue; } if (found) @@ -3815,8 +3848,13 @@ static char *nhlfe_config_str(const zebra_nhlfe_t *nhlfe, char *buf, int size) ifindex2ifname(nh->ifindex, VRF_DEFAULT), size); break; - case NEXTHOP_TYPE_BLACKHOLE: case NEXTHOP_TYPE_IFINDEX: + if (nh->ifindex) + strlcat(buf, + ifindex2ifname(nh->ifindex, VRF_DEFAULT), + size); + break; + case NEXTHOP_TYPE_BLACKHOLE: break; } diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index d789f20071..1ef70270f8 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -67,6 +67,11 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, return CMD_WARNING_CONFIG_FAILED; } + if (gate_str == NULL) { + vty_out(vty, "%% No Nexthop Information\n"); + return CMD_WARNING_CONFIG_FAILED; + } + out_label = MPLS_LABEL_IMPLICIT_NULL; /* as initialization */ label = atoi(inlabel_str); if (!IS_MPLS_UNRESERVED_LABEL(label)) { @@ -86,21 +91,18 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, } in_label = label; - gtype = NEXTHOP_TYPE_BLACKHOLE; /* as initialization */ - if (gate_str) { - /* Gateway is a IPv4 or IPv6 nexthop. */ - ret = inet_pton(AF_INET6, gate_str, &gate.ipv6); - if (ret) - gtype = NEXTHOP_TYPE_IPV6; + /* Gateway is a IPv4 or IPv6 nexthop. */ + ret = inet_pton(AF_INET6, gate_str, &gate.ipv6); + if (ret == 1) + gtype = NEXTHOP_TYPE_IPV6; + else { + ret = inet_pton(AF_INET, gate_str, &gate.ipv4); + if (ret == 1) + gtype = NEXTHOP_TYPE_IPV4; else { - ret = inet_pton(AF_INET, gate_str, &gate.ipv4); - if (ret) - gtype = NEXTHOP_TYPE_IPV4; - else { - vty_out(vty, "%% Invalid nexthop\n"); - return CMD_WARNING_CONFIG_FAILED; - } + vty_out(vty, "%% Invalid nexthop\n"); + return CMD_WARNING_CONFIG_FAILED; } } @@ -131,7 +133,7 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, ret = zebra_mpls_static_lsp_del(zvrf, in_label, gtype, &gate, 0); - if (ret) { + if (ret != 0) { vty_out(vty, "%% LSP cannot be %s\n", add_cmd ? "added" : "deleted"); return CMD_WARNING_CONFIG_FAILED; |
