diff options
186 files changed, 5949 insertions, 1067 deletions
diff --git a/.dockerignore b/.dockerignore index d613e18dfc..e6e1310d24 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,3 +6,4 @@ **/*.so **/.libs docker/alpine/pkgs +docker/centos/pkgs diff --git a/Makefile.am b/Makefile.am index 851cefc85c..34f112bf01 100644 --- a/Makefile.am +++ b/Makefile.am @@ -125,6 +125,7 @@ include doc/manpages/subdir.am include doc/developer/subdir.am include include/subdir.am include lib/subdir.am +include mlag/subdir.am include zebra/subdir.am include watchfrr/subdir.am include qpb/subdir.am diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 4bb8408157..6f4b905c15 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -74,7 +74,7 @@ unsigned char protocol_group[16]; /* babel's link-local multicast address */ int protocol_port; /* babel's port */ int protocol_socket = -1; /* socket: communicate with others babeld */ -static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; +static const char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; static char *babel_vty_addr = NULL; static int babel_vty_port = BABEL_VTY_PORT; @@ -136,7 +136,7 @@ struct option longopts[] = { 0 } }; -static const struct frr_yang_module_info *babeld_yang_modules[] = +static const struct frr_yang_module_info *const babeld_yang_modules[] = { &frr_interface_info, }; diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index 5a336df7b5..86f8bc721e 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -39,7 +39,7 @@ void babelz_zebra_init(void); struct zclient *zclient; /* Debug types */ -static struct { +static const struct { int type; int str_min_len; const char *str; diff --git a/bfdd/bfd.c b/bfdd/bfd.c index cc171f2ebf..920e3fdeea 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -1852,3 +1852,8 @@ void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf) strlcpy(bs->key.vrfname, vrf->name, sizeof(bs->key.vrfname)); hash_get(bfd_key_hash, bs, hash_alloc_intern); } + +unsigned long bfd_get_session_count(void) +{ + return bfd_key_hash->count; +} diff --git a/bfdd/bfd.h b/bfdd/bfd.h index eddfde62fb..97702aab54 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -399,8 +399,8 @@ struct bfd_global { struct zebra_privs_t bfdd_privs; }; extern struct bfd_global bglobal; -extern struct bfd_diag_str_list diag_list[]; -extern struct bfd_state_str_list state_list[]; +extern const struct bfd_diag_str_list diag_list[]; +extern const struct bfd_state_str_list state_list[]; void socket_close(int *s); @@ -567,6 +567,8 @@ typedef void (*hash_iter_func)(struct hash_bucket *hb, void *arg); void bfd_id_iterate(hash_iter_func hif, void *arg); void bfd_key_iterate(hash_iter_func hif, void *arg); +unsigned long bfd_get_session_count(void); + /* Export callback functions for `event.c`. */ extern struct thread_master *master; diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index a91fa3d047..341edbe5cd 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -109,7 +109,7 @@ static struct quagga_signal_t bfd_signals[] = { }, }; -static const struct frr_yang_module_info *bfdd_yang_modules[] = { +static const struct frr_yang_module_info *const bfdd_yang_modules[] = { &frr_interface_info, &frr_bfdd_info, }; @@ -122,7 +122,7 @@ FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617, .n_yang_modules = array_size(bfdd_yang_modules)) #define OPTION_CTLSOCK 1001 -static struct option longopts[] = { +static const struct option longopts[] = { {"bfdctl", required_argument, NULL, OPTION_CTLSOCK}, {0} }; @@ -133,7 +133,7 @@ static struct option longopts[] = { */ struct bfd_global bglobal; -struct bfd_diag_str_list diag_list[] = { +const struct bfd_diag_str_list diag_list[] = { {.str = "control-expired", .type = BD_CONTROL_EXPIRED}, {.str = "echo-failed", .type = BD_ECHO_FAILED}, {.str = "neighbor-down", .type = BD_NEIGHBOR_DOWN}, @@ -145,7 +145,7 @@ struct bfd_diag_str_list diag_list[] = { {.str = NULL}, }; -struct bfd_state_str_list state_list[] = { +const struct bfd_state_str_list state_list[] = { {.str = "admin-down", .type = PTM_BFD_ADM_DOWN}, {.str = "down", .type = PTM_BFD_DOWN}, {.str = "init", .type = PTM_BFD_INIT}, diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index c98ae5c7b3..e6307f78a4 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -142,8 +142,12 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag)); vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag)); + vty_out(vty, "\t\tPeer Type: %s\n", + BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) ? "configured" : "dynamic"); vty_out(vty, "\t\tLocal timers:\n"); + vty_out(vty, "\t\t\tDetect-multiplier: %" PRIu32 "\n", + bs->detect_mult); vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n", bs->timers.required_min_rx / 1000); vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n", @@ -152,6 +156,8 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs) bs->timers.required_min_echo / 1000); vty_out(vty, "\t\tRemote timers:\n"); + vty_out(vty, "\t\t\tDetect-multiplier: %" PRIu32 "\n", + bs->remote_detect_mult); vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n", bs->remote_timers.required_min_rx / 1000); vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n", @@ -235,12 +241,16 @@ static struct json_object *__display_peer_json(struct bfd_session *bs) else json_object_int_add(jo, "echo-interval", 0); + json_object_int_add(jo, "detect-multiplier", bs->detect_mult); + json_object_int_add(jo, "remote-receive-interval", bs->remote_timers.required_min_rx / 1000); json_object_int_add(jo, "remote-transmit-interval", bs->remote_timers.desired_min_tx / 1000); json_object_int_add(jo, "remote-echo-interval", bs->remote_timers.required_min_echo / 1000); + json_object_int_add(jo, "remote-detect-multiplier", + bs->remote_detect_mult); return jo; } @@ -254,7 +264,7 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs) } struct bfd_vrf_tuple { - char *vrfname; + const char *vrfname; struct vty *vty; struct json_object *jo; }; @@ -305,9 +315,8 @@ static void _display_peer_json_iter(struct hash_bucket *hb, void *arg) static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json) { struct json_object *jo; - struct bfd_vrf_tuple bvt; + struct bfd_vrf_tuple bvt = {0}; - memset(&bvt, 0, sizeof(bvt)); bvt.vrfname = vrfname; if (!use_json) { @@ -416,9 +425,8 @@ static void _display_peer_counter_json_iter(struct hash_bucket *hb, void *arg) static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json) { struct json_object *jo; - struct bfd_vrf_tuple bvt; + struct bfd_vrf_tuple bvt = {0}; - memset(&bvt, 0, sizeof(struct bfd_vrf_tuple)); bvt.vrfname = vrfname; if (!use_json) { bvt.vty = vty; @@ -435,6 +443,90 @@ static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json json_object_free(jo); } +static void _clear_peer_counter(struct bfd_session *bs) +{ + /* Clear only pkt stats, intention is not to loose system + events counters */ + bs->stats.rx_ctrl_pkt = 0; + bs->stats.tx_ctrl_pkt = 0; + bs->stats.rx_echo_pkt = 0; + bs->stats.tx_echo_pkt = 0; +} + +static void _display_peer_brief(struct vty *vty, struct bfd_session *bs) +{ + char addr_buf[INET6_ADDRSTRLEN]; + + if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { + vty_out(vty, "%-10u", bs->discrs.my_discr); + inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf)); + vty_out(vty, " %-40s", addr_buf); + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf)); + vty_out(vty, " %-40s", addr_buf); + vty_out(vty, "%-15s\n", state_list[bs->ses_state].str); + } else { + vty_out(vty, "%-10u", bs->discrs.my_discr); + vty_out(vty, " %-40s", satostr(&bs->local_address)); + inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf)); + vty_out(vty, " %-40s", addr_buf); + + vty_out(vty, "%-15s\n", state_list[bs->ses_state].str); + } +} + +static void _display_peer_brief_iter(struct hash_backet *hb, void *arg) +{ + struct bfd_vrf_tuple *bvt = arg; + struct vty *vty; + struct bfd_session *bs = hb->data; + + if (!bvt) + return; + vty = bvt->vty; + + if (bvt->vrfname) { + if (!bs->key.vrfname[0] || + !strmatch(bs->key.vrfname, bvt->vrfname)) + return; + } + + _display_peer_brief(vty, bs); +} + +static void _display_peers_brief(struct vty *vty, const char *vrfname, bool use_json) +{ + struct json_object *jo; + struct bfd_vrf_tuple bvt = {0}; + + bvt.vrfname = vrfname; + + if (use_json == false) { + bvt.vty = vty; + + vty_out(vty, "Session count: %lu\n", bfd_get_session_count()); + vty_out(vty, "%-10s", "SessionId"); + vty_out(vty, " %-40s", "LocalAddress"); + vty_out(vty, " %-40s", "PeerAddress"); + vty_out(vty, "%-15s\n", "Status"); + + vty_out(vty, "%-10s", "========="); + vty_out(vty, " %-40s", "============"); + vty_out(vty, " %-40s", "==========="); + vty_out(vty, "%-15s\n", "======"); + + bfd_id_iterate(_display_peer_brief_iter, &bvt); + return; + } + + jo = json_object_new_array(); + bvt.jo = jo; + + bfd_id_iterate(_display_peer_json_iter, &bvt); + + vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); + json_object_free(jo); +} + static struct bfd_session * _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, const char *label, const char *peer_str, @@ -596,6 +688,55 @@ DEFPY(bfd_show_peers_counters, bfd_show_peers_counters_cmd, return CMD_SUCCESS; } +DEFPY(bfd_clear_peer_counters, bfd_clear_peer_counters_cmd, + "clear bfd [vrf <NAME$vrfname>] peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname}]> counters", + SHOW_STR + "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR + "BFD peers status\n" + "Peer label\n" + PEER_IPV4_STR + PEER_IPV6_STR + MHOP_STR + LOCAL_STR + LOCAL_IPV4_STR + LOCAL_IPV6_STR + INTERFACE_STR + LOCAL_INTF_STR + "clear BFD peer counters information\n") +{ + struct bfd_session *bs; + + /* Look up the BFD peer. */ + bs = _find_peer_or_error(vty, argc, argv, label, peer_str, local_str, + ifname, vrfname); + if (bs == NULL) + return CMD_WARNING_CONFIG_FAILED; + + _clear_peer_counter(bs); + + return CMD_SUCCESS; +} + +DEFPY(bfd_show_peers_brief, bfd_show_peers_brief_cmd, + "show bfd [vrf <NAME$vrfname>] peers brief [json]", + SHOW_STR + "Bidirection Forwarding Detection\n" + VRF_CMD_HELP_STR + "BFD peers status\n" + "Show BFD peer information in tabular form\n" + JSON_STR) +{ + char *vrf_name = NULL; + int idx_vrf = 0; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf_name = argv[idx_vrf + 1]->arg; + + _display_peers_brief(vty, vrf_name, use_json(argc, argv)); + + return CMD_SUCCESS; +} /* * Function definitions. @@ -735,8 +876,10 @@ void bfdd_vty_init(void) { install_element(ENABLE_NODE, &bfd_show_peers_counters_cmd); install_element(ENABLE_NODE, &bfd_show_peer_counters_cmd); + install_element(ENABLE_NODE, &bfd_clear_peer_counters_cmd); install_element(ENABLE_NODE, &bfd_show_peers_cmd); install_element(ENABLE_NODE, &bfd_show_peer_cmd); + install_element(ENABLE_NODE, &bfd_show_peers_brief_cmd); install_element(ENABLE_NODE, &show_debugging_bfd_cmd); /* Install BFD node and commands. */ diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index cf51960b70..e7e7c3cc1f 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -24,7 +24,7 @@ #include "bgp_addpath.h" #include "bgp_route.h" -static struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = { +static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = { { .config_name = "addpath-tx-all-paths", .human_name = "All", @@ -41,7 +41,7 @@ static struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = { } }; -static struct bgp_addpath_strategy_names unknown_names = { +static const struct bgp_addpath_strategy_names unknown_names = { .config_name = "addpath-tx-unknown", .human_name = "Unknown-Addpath-Strategy", .human_description = "Unknown Addpath Strategy", @@ -53,7 +53,7 @@ static struct bgp_addpath_strategy_names unknown_names = { * Returns a structure full of strings associated with an addpath type. Will * never return null. */ -struct bgp_addpath_strategy_names * +const struct bgp_addpath_strategy_names * bgp_addpath_names(enum bgp_addpath_strat strat) { if (strat < BGP_ADDPATH_MAX) diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index c0c182791b..786873a004 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -48,7 +48,7 @@ int bgp_addpath_info_has_ids(struct bgp_addpath_info_data *d); uint32_t bgp_addpath_id_for_peer(struct peer *peer, afi_t afi, safi_t safi, struct bgp_addpath_info_data *d); -struct bgp_addpath_strategy_names * +const struct bgp_addpath_strategy_names * bgp_addpath_names(enum bgp_addpath_strat strat); int bgp_addpath_dmed_required(int strategy); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 4257b601f1..a781e70d2f 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -102,8 +102,10 @@ static void assegment_data_free(as_t *asdata) XFREE(MTYPE_AS_SEG_DATA, asdata); } -const char *aspath_segment_type_str[] = {"as-invalid", "as-set", "as-sequence", - "as-confed-sequence", "as-confed-set"}; +const char *const aspath_segment_type_str[] = { + "as-invalid", "as-set", "as-sequence", "as-confed-sequence", + "as-confed-set" +}; /* Get a new segment. Note that 0 is an allowed length, * and will result in a segment with no allocated data segment. @@ -414,6 +416,19 @@ unsigned int aspath_count_hops(const struct aspath *aspath) return count; } +/* Check if aspath has AS_SET or AS_CONFED_SET */ +bool aspath_check_as_sets(struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + + while (seg) { + if (seg->type == AS_SET || seg->type == AS_CONFED_SET) + return true; + seg = seg->next; + } + return false; +} + /* Estimate size aspath /might/ take if encoded into an * ASPATH attribute. * diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 10f6ee2821..a4427714ba 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -120,6 +120,7 @@ extern int aspath_confed_check(struct aspath *); extern int aspath_left_confed_check(struct aspath *); extern unsigned long aspath_count(void); extern unsigned int aspath_count_hops(const struct aspath *); +extern bool aspath_check_as_sets(struct aspath *aspath); extern unsigned int aspath_count_confeds(struct aspath *); extern unsigned int aspath_size(struct aspath *); extern as_t aspath_highest(struct aspath *); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 0e4c3a3e12..f716c4f308 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -101,7 +101,7 @@ const struct message bgp_status_msg[] = {{Idle, "Idle"}, {0}}; /* BGP message type string. */ -const char *bgp_type_str[] = {NULL, "OPEN", "UPDATE", +const char *const bgp_type_str[] = {NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE", "ROUTE-REFRESH", "CAPABILITY"}; @@ -169,8 +169,8 @@ static const struct message bgp_notify_capability_msg[] = { {0}}; /* Origin strings. */ -const char *bgp_origin_str[] = {"i", "e", "?"}; -const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"}; +const char *const bgp_origin_str[] = {"i", "e", "?"}; +const char *const bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"}; static int bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, struct prefix *p); diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index e05da37647..e1072c3df2 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -151,8 +151,7 @@ struct bgp_debug_filter { #define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b) #define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b) -extern const char *bgp_type_str[]; -extern const char *pmsi_tnltype_str[]; +extern const char *const bgp_type_str[]; extern int bgp_dump_attr(struct attr *, char *, size_t); extern int bgp_debug_peer_updout_enabled(char *host); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 11f5a326df..4c55a0764d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -77,37 +77,36 @@ static void ecommunity_hash_free(struct ecommunity *ecom) else return 0. */ int ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval) { - uint8_t *p; - int ret; int c; - /* When this is fist value, just add it. */ + /* When this is fist value, just add it. */ if (ecom->val == NULL) { - ecom->size++; - ecom->val = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom_length(ecom)); + ecom->size = 1; + ecom->val = XCALLOC(MTYPE_ECOMMUNITY_VAL, ECOMMUNITY_SIZE); memcpy(ecom->val, eval->val, ECOMMUNITY_SIZE); return 1; } /* If the value already exists in the structure return 0. */ c = 0; - for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) { - ret = memcmp(p, eval->val, ECOMMUNITY_SIZE); + for (uint8_t *p = ecom->val; c < ecom->size; + p += ECOMMUNITY_SIZE, c++) { + int ret = memcmp(p, eval->val, ECOMMUNITY_SIZE); if (ret == 0) return 0; - if (ret > 0) + else if (ret > 0) break; } /* Add the value to the structure with numerical sorting. */ ecom->size++; - ecom->val = - XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length(ecom)); + ecom->val = XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val, + ecom->size * ECOMMUNITY_SIZE); - memmove(ecom->val + (c + 1) * ECOMMUNITY_SIZE, - ecom->val + c * ECOMMUNITY_SIZE, + memmove(ecom->val + ((c + 1) * ECOMMUNITY_SIZE), + ecom->val + (c * ECOMMUNITY_SIZE), (ecom->size - 1 - c) * ECOMMUNITY_SIZE); - memcpy(ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE); + memcpy(ecom->val + (c * ECOMMUNITY_SIZE), eval->val, ECOMMUNITY_SIZE); return 1; } @@ -556,8 +555,8 @@ struct ecommunity *ecommunity_str2com(const char *str, int type, return ecom; } -static int ecommunity_rt_soo_str(char *buf, uint8_t *pnt, int type, - int sub_type, int format) +static int ecommunity_rt_soo_str(char *buf, size_t bufsz, uint8_t *pnt, + int type, int sub_type, int format) { int len = 0; const char *prefix; @@ -589,23 +588,25 @@ static int ecommunity_rt_soo_str(char *buf, uint8_t *pnt, int type, eas.val = (*pnt++ << 8); eas.val |= (*pnt++); - len = sprintf(buf, "%s%u:%u", prefix, eas.as, eas.val); + len = snprintf(buf, bufsz, "%s%u:%u", prefix, eas.as, eas.val); } else if (type == ECOMMUNITY_ENCODE_AS) { eas.as = (*pnt++ << 8); eas.as |= (*pnt++); pnt = ptr_get_be32(pnt, &eas.val); - len = sprintf(buf, "%s%u:%u", prefix, eas.as, eas.val); + len = snprintf(buf, bufsz, "%s%u:%u", prefix, eas.as, eas.val); } else if (type == ECOMMUNITY_ENCODE_IP) { memcpy(&eip.ip, pnt, 4); pnt += 4; eip.val = (*pnt++ << 8); eip.val |= (*pnt++); - len = sprintf(buf, "%s%s:%u", prefix, inet_ntoa(eip.ip), - eip.val); + len = snprintf(buf, bufsz, "%s%s:%u", prefix, inet_ntoa(eip.ip), + eip.val); } - (void)pnt; /* consume value */ + + /* consume value */ + (void)pnt; return len; } @@ -640,44 +641,31 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) uint8_t *pnt; uint8_t type = 0; uint8_t sub_type = 0; -#define ECOMMUNITY_STR_DEFAULT_LEN 64 +#define ECOMMUNITY_STRLEN 64 int str_size; - int str_pnt; char *str_buf; - int len = 0; - int first = 1; - if (ecom->size == 0) { - str_buf = XMALLOC(MTYPE_ECOMMUNITY_STR, 1); - str_buf[0] = '\0'; - return str_buf; - } + if (ecom->size == 0) + return XCALLOC(MTYPE_ECOMMUNITY_STR, 1); - /* Prepare buffer. */ - str_buf = XMALLOC(MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1); - str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1; - str_buf[0] = '\0'; - str_pnt = 0; + /* ecom strlen + space + null term */ + str_size = (ecom->size * (ECOMMUNITY_STRLEN + 1)) + 1; + str_buf = XCALLOC(MTYPE_ECOMMUNITY_STR, str_size); + + char encbuf[128]; for (i = 0; i < ecom->size; i++) { int unk_ecom = 0; - - /* Make it sure size is enough. */ - while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) { - str_size *= 2; - str_buf = XREALLOC(MTYPE_ECOMMUNITY_STR, str_buf, - str_size); - } + memset(encbuf, 0x00, sizeof(encbuf)); /* Space between each value. */ - if (!first) { - str_buf[str_pnt++] = ' '; - len++; - } + if (i > 0) + strlcat(str_buf, " ", str_size); + /* Retrieve value field */ pnt = ecom->val + (i * 8); - /* High-order octet of type. */ + /* High-order octet is the type */ type = *pnt++; if (type == ECOMMUNITY_ENCODE_AS || type == ECOMMUNITY_ENCODE_IP @@ -696,15 +684,15 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) inet_ntop(AF_INET, ipv4, ipv4str, INET_ADDRSTRLEN); - len = sprintf(str_buf + str_pnt, - "NH:%s:%d", - ipv4str, pnt[5]); + snprintf(encbuf, sizeof(encbuf), + "NH:%s:%d", ipv4str, pnt[5]); } else unk_ecom = 1; - } else - len = ecommunity_rt_soo_str(str_buf + str_pnt, - pnt, type, sub_type, - format); + } else { + ecommunity_rt_soo_str(encbuf, sizeof(encbuf), + pnt, type, sub_type, + format); + } } else if (type == ECOMMUNITY_ENCODE_OPAQUE) { if (filter == ECOMMUNITY_ROUTE_TARGET) continue; @@ -712,13 +700,15 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) uint16_t tunneltype; memcpy(&tunneltype, pnt + 5, 2); tunneltype = ntohs(tunneltype); - len = sprintf(str_buf + str_pnt, "ET:%d", - tunneltype); + + snprintf(encbuf, sizeof(encbuf), "ET:%d", + tunneltype); } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) { - len = sprintf(str_buf + str_pnt, - "Default Gateway"); - } else + strlcpy(encbuf, "Default Gateway", + sizeof(encbuf)); + } else { unk_ecom = 1; + } } else if (type == ECOMMUNITY_ENCODE_EVPN) { if (filter == ECOMMUNITY_ROUTE_TARGET) continue; @@ -726,15 +716,15 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) struct ethaddr rmac; pnt++; memcpy(&rmac, pnt, ETH_ALEN); - len = sprintf( - str_buf + str_pnt, - "Rmac:%02x:%02x:%02x:%02x:%02x:%02x", - (uint8_t)rmac.octet[0], - (uint8_t)rmac.octet[1], - (uint8_t)rmac.octet[2], - (uint8_t)rmac.octet[3], - (uint8_t)rmac.octet[4], - (uint8_t)rmac.octet[5]); + + snprintf(encbuf, sizeof(encbuf), + "Rmac:%02x:%02x:%02x:%02x:%02x:%02x", + (uint8_t)rmac.octet[0], + (uint8_t)rmac.octet[1], + (uint8_t)rmac.octet[2], + (uint8_t)rmac.octet[3], + (uint8_t)rmac.octet[4], + (uint8_t)rmac.octet[5]); } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) { uint32_t seqnum; @@ -742,29 +732,30 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) memcpy(&seqnum, pnt + 2, 4); seqnum = ntohl(seqnum); - if (flags - & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) - len = sprintf(str_buf + str_pnt, - "MM:%u, sticky MAC", - seqnum); - else - len = sprintf(str_buf + str_pnt, - "MM:%u", seqnum); + + snprintf(encbuf, sizeof(encbuf), "MM:%u", + seqnum); + + if (CHECK_FLAG( + flags, + ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)) + strlcat(encbuf, ", sticky MAC", + sizeof(encbuf)); } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ND) { uint8_t flags = *++pnt; - if (flags - & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) - len = sprintf(str_buf + str_pnt, - "ND:Router Flag"); + if (CHECK_FLAG( + flags, + ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)) + strlcpy(encbuf, "ND:Router Flag", + sizeof(encbuf)); } else unk_ecom = 1; } else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) { - len = sprintf( - str_buf + str_pnt, - "FS:redirect IP 0x%x", *(pnt+5)); + snprintf(encbuf, sizeof(encbuf), + "FS:redirect IP 0x%x", *(pnt + 5)); } else unk_ecom = 1; } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP || @@ -772,38 +763,35 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_REDIRECT_VRF) { - char buf[16]; - - memset(buf, 0, sizeof(buf)); - ecommunity_rt_soo_str(buf, (uint8_t *)pnt, - type & - ~ECOMMUNITY_ENCODE_TRANS_EXP, - ECOMMUNITY_ROUTE_TARGET, - ECOMMUNITY_FORMAT_DISPLAY); - len = snprintf(str_buf + str_pnt, - str_size - len, - "FS:redirect VRF %s", buf); + char buf[16] = {}; + ecommunity_rt_soo_str( + buf, sizeof(buf), (uint8_t *)pnt, + type & ~ECOMMUNITY_ENCODE_TRANS_EXP, + ECOMMUNITY_ROUTE_TARGET, + ECOMMUNITY_FORMAT_DISPLAY); + snprintf(encbuf, sizeof(encbuf), + "FS:redirect VRF %s", buf); } else if (type != ECOMMUNITY_ENCODE_TRANS_EXP) unk_ecom = 1; else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) { char action[64]; - char *ptr = action; if (*(pnt+3) == 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL) - ptr += snprintf(ptr, sizeof(action), - "terminate (apply)"); + strlcpy(action, "terminate (apply)", + sizeof(action)); else - ptr += snprintf(ptr, sizeof(action), - "eval stops"); + strlcpy(action, "eval stops", + sizeof(action)); + if (*(pnt+3) == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE) - snprintf(ptr, sizeof(action) - - (size_t)(ptr-action), - ", sample"); - len = snprintf(str_buf + str_pnt, - str_size - len, - "FS:action %s", action); + strlcat(action, ", sample", + sizeof(action)); + + + snprintf(encbuf, sizeof(encbuf), "FS:action %s", + action); } else if (sub_type == ECOMMUNITY_TRAFFIC_RATE) { union traffic_rate data; @@ -811,21 +799,19 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) data.rate_byte[2] = *(pnt+3); data.rate_byte[1] = *(pnt+4); data.rate_byte[0] = *(pnt+5); - len = sprintf( - str_buf + str_pnt, - "FS:rate %f", data.rate_float); + snprintf(encbuf, sizeof(encbuf), "FS:rate %f", + data.rate_float); } else if (sub_type == ECOMMUNITY_TRAFFIC_MARKING) { - len = sprintf( - str_buf + str_pnt, - "FS:marking %u", *(pnt+5)); + snprintf(encbuf, sizeof(encbuf), + "FS:marking %u", *(pnt + 5)); } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT) { struct ethaddr mac; - pnt++; memcpy(&mac, pnt, ETH_ALEN); - len = sprintf( - str_buf + str_pnt, + + snprintf( + encbuf, sizeof(encbuf), "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t)mac.octet[0], (uint8_t)mac.octet[1], @@ -841,11 +827,11 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) } if (unk_ecom) - len = sprintf(str_buf + str_pnt, "UNK:%d, %d", - type, sub_type); + snprintf(encbuf, sizeof(encbuf), "UNK:%d, %d", type, + sub_type); - str_pnt += len; - first = 0; + int r = strlcat(str_buf, encbuf, str_size); + assert(r < str_size); } return str_buf; diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 249e5bf7de..ae64f41ca1 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -105,8 +105,6 @@ struct ecommunity_val { char val[ECOMMUNITY_SIZE]; }; -#define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE) - /* * Encode BGP Route Target AS:nn. */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 35d54983dc..48b714c7df 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -494,6 +494,39 @@ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn, } } +static void bgp_evpn_get_rmac_nexthop(struct bgpevpn *vpn, + struct prefix_evpn *p, + struct attr *attr, uint8_t flags) +{ + struct bgp *bgp_vrf = vpn->bgp_vrf; + + memset(&attr->rmac, 0, sizeof(struct ethaddr)); + if (!bgp_vrf) + return; + + if (p->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) + return; + + /* Copy sys (pip) RMAC and PIP IP as nexthop + * in case of route is self MAC-IP, + * advertise-pip and advertise-svi-ip features + * are enabled. + * Otherwise, for all host MAC-IP route's + * copy anycast RMAC. + */ + if (CHECK_FLAG(flags, BGP_EVPN_MACIP_TYPE_SVI_IP) + && bgp_vrf->evpn_info->advertise_pip && + bgp_vrf->evpn_info->is_anycast_mac) { + /* copy sys rmac */ + memcpy(&attr->rmac, &bgp_vrf->evpn_info->pip_rmac, + ETH_ALEN); + attr->nexthop = bgp_vrf->evpn_info->pip_ip; + attr->mp_nexthop_global_in = + bgp_vrf->evpn_info->pip_ip; + } else + memcpy(&attr->rmac, &bgp_vrf->rmac, ETH_ALEN); +} + /* * Create RT extended community automatically from passed information: * of the form AS:VNI. @@ -1543,11 +1576,47 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, memset(&attr, 0, sizeof(struct attr)); bgp_attr_default_set(&attr, BGP_ORIGIN_IGP); } - /* Set nexthop to ourselves and fill in the Router MAC. */ - attr.nexthop = bgp_vrf->originator_ip; - attr.mp_nexthop_global_in = bgp_vrf->originator_ip; + + /* Advertise Primary IP (PIP) is enabled, send individual + * IP (default instance router-id) as nexthop. + * PIP is disabled or vrr interface is not present + * use anycast-IP as nexthop and anycast RMAC. + */ + if (!bgp_vrf->evpn_info->advertise_pip || + (!bgp_vrf->evpn_info->is_anycast_mac)) { + attr.nexthop = bgp_vrf->originator_ip; + attr.mp_nexthop_global_in = bgp_vrf->originator_ip; + memcpy(&attr.rmac, &bgp_vrf->rmac, ETH_ALEN); + } else { + /* copy sys rmac */ + memcpy(&attr.rmac, &bgp_vrf->evpn_info->pip_rmac, ETH_ALEN); + if (bgp_vrf->evpn_info->pip_ip.s_addr != INADDR_ANY) { + attr.nexthop = bgp_vrf->evpn_info->pip_ip; + attr.mp_nexthop_global_in = bgp_vrf->evpn_info->pip_ip; + } else if (bgp_vrf->evpn_info->pip_ip.s_addr == INADDR_ANY) + if (bgp_debug_zebra(NULL)) { + char buf1[PREFIX_STRLEN]; + + zlog_debug("VRF %s evp %s advertise-pip primary ip is not configured", + vrf_id_to_name(bgp_vrf->vrf_id), + prefix2str(evp, buf1, sizeof(buf1))); + } + } + + if (bgp_debug_zebra(NULL)) { + char buf[ETHER_ADDR_STRLEN]; + char buf1[PREFIX_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + zlog_debug("VRF %s type-5 route evp %s RMAC %s nexthop %s", + vrf_id_to_name(bgp_vrf->vrf_id), + prefix2str(evp, buf1, sizeof(buf1)), + prefix_mac2str(&attr.rmac, buf, sizeof(buf)), + inet_ntop(AF_INET, &attr.nexthop, buf2, + INET_ADDRSTRLEN)); + } + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - memcpy(&attr.rmac, &bgp_vrf->rmac, sizeof(struct ethaddr)); /* Setup RT and encap extended community */ build_evpn_type5_route_extcomm(bgp_vrf, &attr); @@ -1652,6 +1721,9 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, memcpy(&tmp_pi->extra->label, label, sizeof(label)); tmp_pi->extra->num_labels = num_labels; + /* Mark route as self type-2 route */ + if (flags && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP)) + tmp_pi->extra->af_flags = BGP_EVPN_MACIP_TYPE_SVI_IP; bgp_path_info_add(rn, tmp_pi); } else { tmp_pi = local_pi; @@ -1795,8 +1867,29 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, } /* router mac is only needed for type-2 routes here. */ - if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - bgpevpn_get_rmac(vpn, &attr.rmac); + if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { + uint8_t af_flags = 0; + + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP)) + SET_FLAG(af_flags, BGP_EVPN_MACIP_TYPE_SVI_IP); + + bgp_evpn_get_rmac_nexthop(vpn, p, &attr, af_flags); + + if (bgp_debug_zebra(NULL)) { + char buf[ETHER_ADDR_STRLEN]; + char buf1[PREFIX_STRLEN]; + + zlog_debug("VRF %s vni %u type-2 route evp %s RMAC %s nexthop %s", + vpn->bgp_vrf ? + vrf_id_to_name(vpn->bgp_vrf->vrf_id) : " ", + vpn->vni, + prefix2str(p, buf1, sizeof(buf1)), + prefix_mac2str(&attr.rmac, buf, + sizeof(buf)), + inet_ntoa(attr.mp_nexthop_global_in)); + } + } + vni2label(vpn->vni, &(attr.label)); /* Include L3 VNI related RTs and RMAC for type-2 routes, if they're @@ -1825,9 +1918,15 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, /* lock ri to prevent freeing in evpn_route_select_install */ bgp_path_info_lock(pi); - /* Perform route selection; this is just to set the flags correctly - * as local route in the VNI always wins. - */ + + /* Perform route selection. Normally, the local route in the + * VNI is expected to win and be the best route. However, if + * there is a race condition where a host moved from local to + * remote and the remote route was received in BGP just prior + * to the local MACIP notification from zebra, the remote + * route would win, and we should evict the defunct local route + * and (re)install the remote route into zebra. + */ evpn_route_select_install(bgp, vpn, rn); /* * If the new local route was not selected evict it and tell zebra @@ -2071,7 +2170,8 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - bgpevpn_get_rmac(vpn, &attr.rmac); + bgp_evpn_get_rmac_nexthop(vpn, evp, &attr, + tmp_pi->extra->af_flags); if (evpn_route_is_sticky(bgp, rn)) attr.sticky = 1; @@ -2081,6 +2181,19 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) attr.router_flag = 1; } + if (bgp_debug_zebra(NULL)) { + char buf[ETHER_ADDR_STRLEN]; + char buf1[PREFIX_STRLEN]; + + zlog_debug("VRF %s vni %u evp %s RMAC %s nexthop %s", + vpn->bgp_vrf ? + vrf_id_to_name(vpn->bgp_vrf->vrf_id) : " ", + vpn->vni, + prefix2str(evp, buf1, sizeof(buf1)), + prefix_mac2str(&attr.rmac, buf, sizeof(buf)), + inet_ntoa(attr.mp_nexthop_global_in)); + } + /* Add L3 VNI RTs and RMAC for non IPv6 link-local if * using L3 VNI for type-2 routes also. */ @@ -2100,24 +2213,40 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, 0, &pi, 0, seq); - /* Perform route selection; this is just to set the flags - * correctly as local route in the VNI always wins. + /* lock ri to prevent freeing in evpn_route_select_install */ + bgp_path_info_lock(pi); + + /* Perform route selection. Normally, the local route in the + * VNI is expected to win and be the best route. However, + * under peculiar situations (e.g., tunnel (next hop) IP change + * that causes best selection to be based on next hop), a + * remote route could win. If the local route is the best, + * ensure it is updated in the global EVPN route table and + * advertised to peers; otherwise, ensure it is evicted and + * (re)install the remote route into zebra. */ evpn_route_select_install(bgp, vpn, rn); - - attr_new = pi->attr; - - /* Update route in global routing table. */ - rd_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, - (struct prefix *)evp, &vpn->prd); - assert(rd_rn); - update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, attr_new, 0, - &global_pi, 0, - mac_mobility_seqnum(attr_new)); - - /* Schedule for processing and unlock node. */ - bgp_process(bgp, rd_rn, afi, safi); - bgp_unlock_node(rd_rn); + if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) { + evpn_cleanup_local_non_best_route(bgp, vpn, rn, pi); + /* unlock pi */ + bgp_path_info_unlock(pi); + } else { + attr_new = pi->attr; + /* unlock pi */ + bgp_path_info_unlock(pi); + + /* Update route in global routing table. */ + rd_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + (struct prefix *)evp, &vpn->prd); + assert(rd_rn); + update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, + attr_new, 0, &global_pi, 0, + mac_mobility_seqnum(attr_new)); + + /* Schedule for processing and unlock node. */ + bgp_process(bgp, rd_rn, afi, safi); + bgp_unlock_node(rd_rn); + } /* Unintern temporary. */ aspath_unintern(&attr.aspath); @@ -2268,7 +2397,7 @@ static int bgp_evpn_vni_flood_mode_get(struct bgp *bgp, * situations need the route in the per-VNI table as well as the global * table to be updated (as attributes change). */ -static int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) +int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { int ret; struct prefix_evpn p; @@ -3527,8 +3656,14 @@ static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf) * update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5 * routes */ -static void update_advertise_vrf_routes(struct bgp *bgp_vrf) +void update_advertise_vrf_routes(struct bgp *bgp_vrf) { + struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */ + + bgp_evpn = bgp_get_evpn(); + if (!bgp_evpn) + return; + /* update all ipv4 routes */ if (advertise_type5_routes(bgp_vrf, AFI_IP)) bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST); @@ -4586,6 +4721,9 @@ void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf, */ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) { + struct listnode *node; + struct bgp *bgp_vrf; + if (withdraw) { /* delete and withdraw all the type-5 routes @@ -4600,8 +4738,34 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw) (void (*)(struct hash_bucket *, void *))withdraw_router_id_vni, bgp); + + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) { + if (bgp_vrf->evpn_info->advertise_pip && + (bgp_vrf->evpn_info->pip_ip_static.s_addr + == INADDR_ANY)) + bgp_vrf->evpn_info->pip_ip.s_addr + = INADDR_ANY; + } + } } else { + /* Assign new default instance router-id */ + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) { + if (bgp_vrf->evpn_info->advertise_pip && + (bgp_vrf->evpn_info->pip_ip_static.s_addr + == INADDR_ANY)) { + bgp_vrf->evpn_info->pip_ip = + bgp->router_id; + /* advertise type-5 routes with + * new nexthop + */ + update_advertise_vrf_routes(bgp_vrf); + } + } + } + /* advertise all routes in the vrf as type-5 routes with the new * RD */ @@ -5395,8 +5559,9 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp) if (!(pi->type == ZEBRA_ROUTE_BGP && pi->sub_type == BGP_ROUTE_NORMAL)) continue; - - if (bgp_nexthop_self(bgp, pi->attr->nexthop)) { + if (bgp_nexthop_self(bgp, afi, + pi->type, pi->sub_type, + pi->attr, rn)) { char attr_str[BUFSIZ] = {0}; char pbuf[PREFIX_STRLEN]; @@ -5512,9 +5677,12 @@ static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket, bgpevpn_link_to_l3vni(vpn); } -int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, +int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, + struct ethaddr *svi_rmac, + struct ethaddr *vrr_rmac, struct in_addr originator_ip, int filter, - ifindex_t svi_ifindex) + ifindex_t svi_ifindex, + bool is_anycast_mac) { struct bgp *bgp_vrf = NULL; /* bgp VRF instance */ struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */ @@ -5561,10 +5729,35 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, /* associate the vrf with l3vni and related parameters */ bgp_vrf->l3vni = l3vni; - memcpy(&bgp_vrf->rmac, rmac, sizeof(struct ethaddr)); bgp_vrf->originator_ip = originator_ip; bgp_vrf->l3vni_svi_ifindex = svi_ifindex; + bgp_vrf->evpn_info->is_anycast_mac = is_anycast_mac; + + /* copy anycast MAC from VRR MAC */ + memcpy(&bgp_vrf->rmac, vrr_rmac, ETH_ALEN); + /* copy sys RMAC from SVI MAC */ + memcpy(&bgp_vrf->evpn_info->pip_rmac_zebra, svi_rmac, ETH_ALEN); + /* PIP user configured mac is not present use svi mac as sys mac */ + if (is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_static)) + memcpy(&bgp_vrf->evpn_info->pip_rmac, svi_rmac, ETH_ALEN); + if (bgp_debug_zebra(NULL)) { + char buf[ETHER_ADDR_STRLEN]; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[ETHER_ADDR_STRLEN]; + + zlog_debug("VRF %s vni %u pip %s RMAC %s sys RMAC %s static RMAC %s is_anycast_mac %s", + vrf_id_to_name(bgp_vrf->vrf_id), + bgp_vrf->l3vni, + bgp_vrf->evpn_info->advertise_pip ? "enable" + : "disable", + prefix_mac2str(&bgp_vrf->rmac, buf, sizeof(buf)), + prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac, + buf1, sizeof(buf1)), + prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac_static, + buf2, sizeof(buf2)), + is_anycast_mac ? "Enable" : "Disable"); + } /* set the right filter - are we using l3vni only for prefix routes? */ if (filter) SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY); @@ -5645,6 +5838,10 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) /* remove the Rmac from the BGP vrf */ memset(&bgp_vrf->rmac, 0, sizeof(struct ethaddr)); + memset(&bgp_vrf->evpn_info->pip_rmac_zebra, 0, ETH_ALEN); + if (is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_static) && + !is_zero_mac(&bgp_vrf->evpn_info->pip_rmac)) + memset(&bgp_vrf->evpn_info->pip_rmac, 0, ETH_ALEN); /* remove default import RT or Unmap non-default import RT */ if (!list_isempty(bgp_vrf->vrf_import_rtl)) { @@ -6004,6 +6201,15 @@ void bgp_evpn_init(struct bgp *bgp) bgp->evpn_info->dad_freeze_time = 0; /* Initialize zebra vxlan */ bgp_zebra_dup_addr_detection(bgp); + /* Enable PIP feature by default for bgp vrf instance */ + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) { + struct bgp *bgp_default; + + bgp->evpn_info->advertise_pip = true; + bgp_default = bgp_get_default(); + if (bgp_default) + bgp->evpn_info->pip_ip = bgp_default->router_id; + } } /* Default BUM handling is to do head-end replication. */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 798c3e59bc..b030f0a33e 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -174,8 +174,9 @@ extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, uint8_t flags, uint32_t seq); extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct ethaddr *rmac, + struct ethaddr *vrr_rmac, struct in_addr originator_ip, int filter, - ifindex_t svi_ifindex); + ifindex_t svi_ifindex, bool is_anycast_mac); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, @@ -192,5 +193,6 @@ extern void bgp_evpn_cleanup(struct bgp *bgp); extern void bgp_evpn_init(struct bgp *bgp); extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx); extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx); +extern void update_advertise_vrf_routes(struct bgp *bgp_vrf); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index f6bde2e9fa..76cf8b2cd6 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -188,6 +188,16 @@ struct bgp_evpn_info { /* EVPN enable - advertise svi macip routes */ int advertise_svi_macip; + /* PIP feature knob */ + bool advertise_pip; + /* PIP IP (sys ip) */ + struct in_addr pip_ip; + struct in_addr pip_ip_static; + /* PIP MAC (sys MAC) */ + struct ethaddr pip_rmac; + struct ethaddr pip_rmac_static; + struct ethaddr pip_rmac_zebra; + bool is_anycast_mac; }; static inline int is_vrf_rd_configured(struct bgp *bgp_vrf) @@ -501,6 +511,16 @@ static inline int is_es_local(struct evpnes *es) return CHECK_FLAG(es->flags, EVPNES_LOCAL) ? 1 : 0; } +static inline bool bgp_evpn_is_svi_macip_enabled(struct bgpevpn *vpn) +{ + struct bgp *bgp_evpn = NULL; + + bgp_evpn = bgp_get_evpn(); + + return (bgp_evpn->evpn_info->advertise_svi_macip || + vpn->advertise_svi_macip); +} + extern void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf, afi_t afi, safi_t safi, bool add); @@ -543,4 +563,5 @@ extern struct evpnes *bgp_evpn_es_new(struct bgp *bgp, esi_t *esi, struct ipaddr *originator_ip); extern void bgp_evpn_es_free(struct bgp *bgp, struct evpnes *es); extern bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni); +extern int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn); #endif /* _BGP_EVPN_PRIVATE_H */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 3bc8345140..d316a28dcb 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -364,6 +364,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, struct ecommunity *ecom; json_object *json_import_rtl = NULL; json_object *json_export_rtl = NULL; + char buf2[ETHER_ADDR_STRLEN]; json_import_rtl = json_export_rtl = 0; @@ -382,6 +383,19 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, json_object_string_add(json, "advertiseSviMacip", "n/a"); json_object_to_json_string_ext(json, JSON_C_TO_STRING_NOSLASHESCAPE); + json_object_string_add(json, "advertisePip", + bgp_vrf->evpn_info->advertise_pip ? + "Enabled" : "Disabled"); + json_object_string_add(json, "sysIP", + inet_ntop(AF_INET, + &bgp_vrf->evpn_info->pip_ip, + buf1, INET_ADDRSTRLEN)); + json_object_string_add(json, "sysMac", + prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac, + buf2, sizeof(buf2))); + json_object_string_add(json, "rmac", + prefix_mac2str(&bgp_vrf->rmac, + buf2, sizeof(buf2))); } else { vty_out(vty, "VNI: %d", bgp_vrf->l3vni); vty_out(vty, " (known to the kernel)"); @@ -396,6 +410,17 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, inet_ntoa(bgp_vrf->originator_ip)); vty_out(vty, " Advertise-gw-macip : %s\n", "n/a"); vty_out(vty, " Advertise-svi-macip : %s\n", "n/a"); + vty_out(vty, " Advertise-pip: %s\n", + bgp_vrf->evpn_info->advertise_pip ? "Yes" : "No"); + vty_out(vty, " System-IP: %s\n", + inet_ntop(AF_INET, &bgp_vrf->evpn_info->pip_ip, + buf1, INET_ADDRSTRLEN)); + vty_out(vty, " System-MAC: %s\n", + prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac, + buf2, sizeof(buf2))); + vty_out(vty, " Router-MAC: %s\n", + prefix_mac2str(&bgp_vrf->rmac, + buf2, sizeof(buf2))); } if (!json) @@ -3650,6 +3675,139 @@ DEFUN (no_bgp_evpn_advertise_type5, return CMD_SUCCESS; } +DEFPY (bgp_evpn_advertise_pip_ip_mac, + bgp_evpn_advertise_pip_ip_mac_cmd, + "[no$no] advertise-pip [ip <A.B.C.D> [mac <X:X:X:X:X:X|X:X:X:X:X:X/M>]]", + NO_STR + "evpn system primary IP\n" + IP_STR + "ip address\n" + MAC_STR MAC_STR MAC_STR) +{ + struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */ + struct bgp *bgp_evpn = NULL; + + if (EVPN_ENABLED(bgp_vrf)) { + vty_out(vty, + "This command is supported under L3VNI BGP EVPN VRF\n"); + return CMD_WARNING_CONFIG_FAILED; + } + bgp_evpn = bgp_get_evpn(); + + if (!no) { + /* pip is already enabled */ + if (argc == 1 && bgp_vrf->evpn_info->advertise_pip) + return CMD_SUCCESS; + + bgp_vrf->evpn_info->advertise_pip = true; + if (ip.s_addr != INADDR_ANY) { + /* Already configured with same IP */ + if (IPV4_ADDR_SAME(&ip, + &bgp_vrf->evpn_info->pip_ip_static)) + return CMD_SUCCESS; + + bgp_vrf->evpn_info->pip_ip_static = ip; + bgp_vrf->evpn_info->pip_ip = ip; + } else { + bgp_vrf->evpn_info->pip_ip_static.s_addr + = INADDR_ANY; + /* default instance router-id assignemt */ + if (bgp_evpn) + bgp_vrf->evpn_info->pip_ip = + bgp_evpn->router_id; + } + /* parse sys mac */ + if (!is_zero_mac(&mac->eth_addr)) { + /* Already configured with same MAC */ + if (memcmp(&bgp_vrf->evpn_info->pip_rmac_static, + &mac->eth_addr, ETH_ALEN) == 0) + return CMD_SUCCESS; + + memcpy(&bgp_vrf->evpn_info->pip_rmac_static, + &mac->eth_addr, ETH_ALEN); + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_static, + ETH_ALEN); + } else { + /* Copy zebra sys mac */ + if (!is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_zebra)) + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_zebra, + ETH_ALEN); + } + } else { + if (argc == 2) { + if (!bgp_vrf->evpn_info->advertise_pip) + return CMD_SUCCESS; + /* Disable PIP feature */ + bgp_vrf->evpn_info->advertise_pip = false; + /* copy anycast mac */ + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->rmac, ETH_ALEN); + } else { + /* remove MAC-IP option retain PIP knob. */ + if ((ip.s_addr != INADDR_ANY) && + !IPV4_ADDR_SAME(&ip, + &bgp_vrf->evpn_info->pip_ip_static)) { + vty_out(vty, + "%% BGP EVPN PIP IP does not match\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!is_zero_mac(&mac->eth_addr) && + memcmp(&bgp_vrf->evpn_info->pip_rmac_static, + &mac->eth_addr, ETH_ALEN) != 0) { + vty_out(vty, + "%% BGP EVPN PIP MAC does not match\n"); + return CMD_WARNING_CONFIG_FAILED; + } + /* pip_rmac can carry vrr_rmac reset only if it matches + * with static value. + */ + if (memcmp(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_static, + ETH_ALEN) == 0) { + /* Copy zebra sys mac */ + if (!is_zero_mac( + &bgp_vrf->evpn_info->pip_rmac_zebra)) + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->evpn_info->pip_rmac_zebra, + ETH_ALEN); + else { + /* copy anycast mac */ + memcpy(&bgp_vrf->evpn_info->pip_rmac, + &bgp_vrf->rmac, ETH_ALEN); + } + } + } + /* reset user configured sys MAC */ + memset(&bgp_vrf->evpn_info->pip_rmac_static, 0, ETH_ALEN); + /* reset user configured sys IP */ + bgp_vrf->evpn_info->pip_ip_static.s_addr = INADDR_ANY; + /* Assign default PIP IP (bgp instance router-id) */ + if (bgp_evpn) + bgp_vrf->evpn_info->pip_ip = bgp_evpn->router_id; + else + bgp_vrf->evpn_info->pip_ip.s_addr = INADDR_ANY; + } + + if (is_evpn_enabled()) { + struct listnode *node = NULL; + struct bgpevpn *vpn = NULL; + + update_advertise_vrf_routes(bgp_vrf); + + /* Update (svi) type-2 routes */ + for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn)) { + if (!bgp_evpn_is_svi_macip_enabled(vpn)) + continue; + update_routes_for_vni(bgp_evpn, vpn); + } + } + + return CMD_SUCCESS; +} + /* * Display VNI information - for all or a specific VNI */ @@ -5383,6 +5541,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { char buf1[RD_ADDRSTRLEN]; + char buf2[INET6_ADDRSTRLEN]; if (bgp->vnihash) { struct list *vnilist = hash_to_list(bgp->vnihash); @@ -5457,6 +5616,25 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6)) vty_out(vty, " default-originate ipv6\n"); + if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) { + if (!bgp->evpn_info->advertise_pip) + vty_out(vty, " no advertise-pip\n"); + if (bgp->evpn_info->advertise_pip) { + if (bgp->evpn_info->pip_ip_static.s_addr != INADDR_ANY) + vty_out(vty, " advertise-pip ip %s", + inet_ntop(AF_INET, + &bgp->evpn_info->pip_ip_static, + buf2, INET_ADDRSTRLEN)); + if (!is_zero_mac(&(bgp->evpn_info->pip_rmac_static))) { + char buf[ETHER_ADDR_STRLEN]; + + vty_out(vty, " mac %s", + prefix_mac2str(&bgp->evpn_info->pip_rmac, + buf, sizeof(buf))); + } + vty_out(vty, "\n"); + } + } if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD)) vty_out(vty, " rd %s\n", prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1))); @@ -5527,6 +5705,7 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &dup_addr_detection_auto_recovery_cmd); install_element(BGP_EVPN_NODE, &no_dup_addr_detection_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_flood_control_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_pip_ip_mac_cmd); /* test commands */ install_element(BGP_EVPN_NODE, &test_adv_evpn_type4_route_cmd); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 2e5b2e115c..6460ff76fe 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -62,7 +62,7 @@ DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer)) /* Definition of display strings corresponding to FSM events. This should be * kept consistent with the events defined in bgpd.h */ -static const char *bgp_event_str[] = { +static const char *const bgp_event_str[] = { NULL, "BGP_Start", "BGP_Stop", @@ -101,7 +101,7 @@ static int bgp_peer_reg_with_nht(struct peer *peer) { int connected = 0; - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 + if (peer->sort == BGP_PEER_EBGP && peer->ttl == BGP_DEFAULT_TTL && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) && !bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) connected = 1; @@ -522,7 +522,7 @@ int bgp_routeadv_timer(struct thread *thread) } /* BGP Peer Down Cause */ -const char *peer_down_str[] = {"", +const char *const peer_down_str[] = {"", "Router ID changed", "Remote AS changed", "Local AS change", diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 9d0500ae2c..6f955c71be 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -64,7 +64,7 @@ extern int bgp_stop(struct peer *peer); extern void bgp_timer_set(struct peer *); extern int bgp_routeadv_timer(struct thread *); extern void bgp_fsm_change_status(struct peer *peer, int status); -extern const char *peer_down_str[]; +extern const char *const peer_down_str[]; extern void bgp_update_delay_end(struct bgp *); extern void bgp_maxmed_update(struct bgp *); extern int bgp_maxmed_onstartup_configured(struct bgp *); diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index 9e1c89b71c..fed34e5b65 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -508,7 +508,7 @@ static bool validate_header(struct peer *peer) uint8_t type; struct ringbuf *pkt = peer->ibuf_work; - static uint8_t m_correct[BGP_MARKER_SIZE] = { + static const uint8_t m_correct[BGP_MARKER_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; uint8_t m_rx[BGP_MARKER_SIZE] = {0x00}; diff --git a/bgpd/bgp_keepalives.c b/bgpd/bgp_keepalives.c index 3a49e8bc00..3a5adae874 100644 --- a/bgpd/bgp_keepalives.c +++ b/bgpd/bgp_keepalives.c @@ -95,7 +95,7 @@ static void peer_process(struct hash_bucket *hb, void *arg) static struct timeval ka = {0}; // peer->v_keepalive as a timeval static struct timeval diff; // ka - elapsed - static struct timeval tolerance = {0, 100000}; + static const struct timeval tolerance = {0, 100000}; uint32_t v_ka = atomic_load_explicit(&pkat->peer->v_keepalive, memory_order_relaxed); diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index 89bc9aabb0..523671468b 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -58,7 +58,7 @@ static inline int bgp_is_withdraw_label(mpls_label_t *label) /* The check on pkt[2] for 0x00 or 0x02 is in case bgp_set_valid_label() * was called on the withdraw label */ - if ((pkt[0] == 0x80) && (pkt[1] == 0x00) + if (((pkt[0] == 0x80) || (pkt[0] == 0x00)) && (pkt[1] == 0x00) && ((pkt[2] == 0x00) || (pkt[2] == 0x02))) return 1; return 0; diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index 3243ce96b5..674686b3c4 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -177,15 +177,14 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) { int i; int len; - bool first = true; char *str_buf; - char *str_pnt; uint8_t *pnt; uint32_t global, local1, local2; json_object *json_lcommunity_list = NULL; json_object *json_string = NULL; -#define LCOMMUNITY_STR_DEFAULT_LEN 32 + /* 3 32-bit integers, 2 colons, and a space */ +#define LCOMMUNITY_STRLEN (10 * 3 + 2 + 1) if (!lcom) return; @@ -196,8 +195,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) } if (lcom->size == 0) { - str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, 1); - str_buf[0] = '\0'; + str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, 1); if (make_json) { json_object_string_add(lcom->json, "string", ""); @@ -209,15 +207,13 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) return; } - str_buf = str_pnt = - XMALLOC(MTYPE_LCOMMUNITY_STR, - (LCOMMUNITY_STR_DEFAULT_LEN * lcom->size) + 1); + /* 1 space + lcom->size lcom strings + null terminator */ + size_t str_buf_sz = (LCOMMUNITY_STRLEN * lcom->size) + 2; + str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz); for (i = 0; i < lcom->size; i++) { - if (first) - first = false; - else - *str_pnt++ = ' '; + if (i > 0) + strlcat(str_buf, " ", str_buf_sz); pnt = lcom->val + (i * LCOMMUNITY_SIZE); pnt = ptr_get_be32(pnt, &global); @@ -225,19 +221,21 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) pnt = ptr_get_be32(pnt, &local2); (void)pnt; - len = sprintf(str_pnt, "%u:%u:%u", global, local1, local2); + char lcsb[LCOMMUNITY_STRLEN + 1]; + + snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1, + local2); + + len = strlcat(str_buf, lcsb, str_buf_sz); + assert((unsigned int)len < str_buf_sz); + if (make_json) { - json_string = json_object_new_string(str_pnt); + json_string = json_object_new_string(lcsb); json_object_array_add(json_lcommunity_list, json_string); } - - str_pnt += len; } - str_buf = - XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf, str_pnt - str_buf + 1); - if (make_json) { json_object_string_add(lcom->json, "string", str_buf); json_object_object_add(lcom->json, "list", diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 6b91a2cf1f..08c5d3468d 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -360,7 +360,7 @@ static void bgp_vrf_terminate(void) vrf_terminate(); } -static const struct frr_yang_module_info *bgpd_yang_modules[] = { +static const struct frr_yang_module_info *const bgpd_yang_modules[] = { }; FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 812f0ce16e..7116c80941 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -180,7 +180,7 @@ void bgp_tip_del(struct bgp *bgp, struct in_addr *tip) /* BGP own address structure */ struct bgp_addr { - struct in_addr addr; + struct prefix *p; struct list *ifp_name_list; }; @@ -190,9 +190,19 @@ static void show_address_entry(struct hash_bucket *bucket, void *args) struct bgp_addr *addr = (struct bgp_addr *)bucket->data; char *name; struct listnode *node; - - vty_out(vty, "addr: %s, count: %d : ", inet_ntoa(addr->addr), - addr->ifp_name_list->count); + char str[INET6_ADDRSTRLEN] = {0}; + + if (addr->p->family == AF_INET) { + vty_out(vty, "addr: %s, count: %d : ", inet_ntop(AF_INET, + &(addr->p->u.prefix4), + str, INET_ADDRSTRLEN), + addr->ifp_name_list->count); + } else if (addr->p->family == AF_INET6) { + vty_out(vty, "addr: %s, count: %d : ", inet_ntop(AF_INET6, + &(addr->p->u.prefix6), + str, INET6_ADDRSTRLEN), + addr->ifp_name_list->count); + } for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) { vty_out(vty, " %s,", name); @@ -217,11 +227,12 @@ static void bgp_address_hash_string_del(void *val) static void *bgp_address_hash_alloc(void *p) { - const struct in_addr *val = (const struct in_addr *)p; - struct bgp_addr *addr; + struct bgp_addr *copy_addr = p; + struct bgp_addr *addr = NULL; addr = XMALLOC(MTYPE_BGP_ADDR, sizeof(struct bgp_addr)); - addr->addr.s_addr = val->s_addr; + addr->p = prefix_new(); + prefix_copy(addr->p, copy_addr->p); addr->ifp_name_list = list_new(); addr->ifp_name_list->del = bgp_address_hash_string_del; @@ -233,6 +244,7 @@ static void bgp_address_hash_free(void *data) { struct bgp_addr *addr = data; + prefix_free(&addr->p); list_delete(&addr->ifp_name_list); XFREE(MTYPE_BGP_ADDR, addr); } @@ -241,7 +253,7 @@ static unsigned int bgp_address_hash_key_make(const void *p) { const struct bgp_addr *addr = p; - return jhash_1word(addr->addr.s_addr, 0); + return prefix_hash_key((const void *)(addr->p)); } static bool bgp_address_hash_cmp(const void *p1, const void *p2) @@ -249,14 +261,14 @@ static bool bgp_address_hash_cmp(const void *p1, const void *p2) const struct bgp_addr *addr1 = p1; const struct bgp_addr *addr2 = p2; - return addr1->addr.s_addr == addr2->addr.s_addr; + return prefix_same(addr1->p, addr2->p); } void bgp_address_init(struct bgp *bgp) { bgp->address_hash = hash_create(bgp_address_hash_key_make, bgp_address_hash_cmp, - "BGP Address Hash"); + "BGP Connected Address Hash"); } void bgp_address_destroy(struct bgp *bgp) @@ -276,7 +288,12 @@ static void bgp_address_add(struct bgp *bgp, struct connected *ifc, struct listnode *node; char *name; - tmp.addr = p->u.prefix4; + tmp.p = p; + + if (tmp.p->family == AF_INET) + tmp.p->prefixlen = IPV4_MAX_BITLEN; + else if (tmp.p->family == AF_INET6) + tmp.p->prefixlen = IPV6_MAX_BITLEN; addr = hash_get(bgp->address_hash, &tmp, bgp_address_hash_alloc); @@ -298,7 +315,12 @@ static void bgp_address_del(struct bgp *bgp, struct connected *ifc, struct listnode *node; char *name; - tmp.addr = p->u.prefix4; + tmp.p = p; + + if (tmp.p->family == AF_INET) + tmp.p->prefixlen = IPV4_MAX_BITLEN; + else if (tmp.p->family == AF_INET6) + tmp.p->prefixlen = IPV6_MAX_BITLEN; addr = hash_lookup(bgp->address_hash, &tmp); /* may have been deleted earlier by bgp_interface_down() */ @@ -379,6 +401,8 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc) if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) return; + bgp_address_add(bgp, ifc, addr); + rn = bgp_node_get(bgp->connected_table[AFI_IP6], (struct prefix *)&p); @@ -419,6 +443,8 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc) if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) return; + bgp_address_del(bgp, ifc, addr); + rn = bgp_node_lookup(bgp->connected_table[AFI_IP6], (struct prefix *)&p); } @@ -453,21 +479,85 @@ static void bgp_connected_cleanup(struct route_table *table, } } -int bgp_nexthop_self(struct bgp *bgp, struct in_addr nh_addr) -{ - struct bgp_addr tmp, *addr; - struct tip_addr tmp_tip, *tip; - - tmp.addr = nh_addr; +int bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type, uint8_t sub_type, + struct attr *attr, struct bgp_node *rn) +{ + struct prefix p = {0}; + afi_t new_afi = afi; + struct bgp_addr tmp_addr = {0}, *addr = NULL; + struct tip_addr tmp_tip, *tip = NULL; + + bool is_bgp_static_route = ((type == ZEBRA_ROUTE_BGP) + && (sub_type == BGP_ROUTE_STATIC)) + ? true + : false; + + if (!is_bgp_static_route) + new_afi = BGP_ATTR_NEXTHOP_AFI_IP6(attr) ? AFI_IP6 : AFI_IP; + + switch (new_afi) { + case AFI_IP: + p.family = AF_INET; + if (is_bgp_static_route) { + p.u.prefix4 = rn->p.u.prefix4; + p.prefixlen = rn->p.prefixlen; + } else { + /* Here we need to find out which nexthop to be used*/ + if (attr->flag & + ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { + + p.u.prefix4 = attr->nexthop; + p.prefixlen = IPV4_MAX_BITLEN; + + } else if ((attr->mp_nexthop_len) && + ((attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV4) || + (attr->mp_nexthop_len == + BGP_ATTR_NHLEN_VPNV4))) { + p.u.prefix4 = + attr->mp_nexthop_global_in; + p.prefixlen = IPV4_MAX_BITLEN; + } else + return 0; + } + break; + case AFI_IP6: + p.family = AF_INET6; + + if (is_bgp_static_route) { + p.u.prefix6 = rn->p.u.prefix6; + p.prefixlen = rn->p.prefixlen; + } else { + p.u.prefix6 = attr->mp_nexthop_global; + p.prefixlen = IPV6_MAX_BITLEN; + } + break; + default: + break; + } - addr = hash_lookup(bgp->address_hash, &tmp); + tmp_addr.p = &p; + addr = hash_lookup(bgp->address_hash, &tmp_addr); if (addr) return 1; - tmp_tip.addr = nh_addr; - tip = hash_lookup(bgp->tip_hash, &tmp_tip); - if (tip) - return 1; + if (new_afi == AFI_IP) { + memset(&tmp_tip, 0, sizeof(struct tip_addr)); + tmp_tip.addr = attr->nexthop; + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { + tmp_tip.addr = attr->nexthop; + } else if ((attr->mp_nexthop_len) && + ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) + || (attr->mp_nexthop_len == + BGP_ATTR_NHLEN_VPNV4))) { + tmp_tip.addr = attr->mp_nexthop_global_in; + } + + tip = hash_lookup(bgp->tip_hash, &tmp_tip); + if (tip) + return 1; + } return 0; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index d35f1ad520..af4c0bc047 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -88,7 +88,9 @@ extern int bgp_subgrp_multiaccess_check_v6(struct in6_addr nexthop, extern int bgp_multiaccess_check_v4(struct in_addr nexthop, struct peer *peer); extern int bgp_multiaccess_check_v6(struct in6_addr nexthop, struct peer *peer); extern int bgp_config_write_scan_time(struct vty *); -extern int bgp_nexthop_self(struct bgp *, struct in_addr); +extern int bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type, + uint8_t sub_type, struct attr *attr, + struct bgp_node *rn); extern struct bgp_nexthop_cache *bnc_new(void); extern void bnc_free(struct bgp_nexthop_cache *bnc); extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4fb4faebc2..ae70ea0690 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1854,6 +1854,16 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, if (!bgp_outbound_policy_exists(peer, filter)) return 0; + /* draft-ietf-idr-deprecate-as-set-confed-set + * Filter routes having AS_SET or AS_CONFED_SET in the path. + * Eventually, This document (if approved) updates RFC 4271 + * and RFC 5065 by eliminating AS_SET and AS_CONFED_SET types, + * and obsoletes RFC 6472. + */ + if (peer->bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) + if (aspath_check_as_sets(attr->aspath)) + return 0; + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { @@ -2970,7 +2980,8 @@ static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path, /* Check if received nexthop is valid or not. */ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, - struct attr *attr) + uint8_t type, uint8_t stype, + struct attr *attr, struct bgp_node *rn) { int ret = 0; @@ -2983,7 +2994,8 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { if (attr->nexthop.s_addr == 0 || IPV4_CLASS_DE(ntohl(attr->nexthop.s_addr)) - || bgp_nexthop_self(bgp, attr->nexthop)) + || bgp_nexthop_self(bgp, afi, type, stype, + attr, rn)) return 1; } @@ -2999,8 +3011,8 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, ret = (attr->mp_nexthop_global_in.s_addr == 0 || IPV4_CLASS_DE(ntohl( attr->mp_nexthop_global_in.s_addr)) - || bgp_nexthop_self(bgp, - attr->mp_nexthop_global_in)); + || bgp_nexthop_self(bgp, afi, type, stype, + attr, rn)); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL: @@ -3009,7 +3021,9 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, ret = (IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global) || IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) || IN6_IS_ADDR_MULTICAST( - &attr->mp_nexthop_global)); + &attr->mp_nexthop_global) + || bgp_nexthop_self(bgp, afi, type, stype, + attr, rn)); break; default: @@ -3042,6 +3056,9 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, int do_loop_check = 1; int has_valid_label = 0; afi_t nh_afi; + uint8_t pi_type = 0; + uint8_t pi_sub_type = 0; + #if ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; #endif @@ -3148,6 +3165,19 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } + /* draft-ietf-idr-deprecate-as-set-confed-set + * Filter routes having AS_SET or AS_CONFED_SET in the path. + * Eventually, This document (if approved) updates RFC 4271 + * and RFC 5065 by eliminating AS_SET and AS_CONFED_SET types, + * and obsoletes RFC 6472. + */ + if (peer->bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) + if (aspath_check_as_sets(attr->aspath)) { + reason = + "as-path contains AS_SET or AS_CONFED_SET type;"; + goto filtered; + } + bgp_attr_dup(&new_attr, attr); /* Apply incoming route-map. @@ -3187,9 +3217,15 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, } } + if (pi) { + pi_type = pi->type; + pi_sub_type = pi->sub_type; + } + /* next hop check. */ if (!CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD) - && bgp_update_martian_nexthop(bgp, afi, safi, &new_attr)) { + && bgp_update_martian_nexthop(bgp, afi, safi, pi_type, + pi_sub_type, &new_attr, rn)) { peer->stat_pfx_nh_invalid++; reason = "martian or self next-hop;"; bgp_attr_flush(&new_attr); @@ -3441,7 +3477,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) || (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p))) { - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 + if (safi != SAFI_EVPN && peer->sort == BGP_PEER_EBGP + && peer->ttl == BGP_DEFAULT_TTL && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) && !bgp_flag_check( @@ -3583,7 +3620,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, if (((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) || (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p))) { - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 + if (safi != SAFI_EVPN && peer->sort == BGP_PEER_EBGP + && peer->ttl == BGP_DEFAULT_TTL && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) && !bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) @@ -4468,7 +4506,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, if (addpath_encoded) { /* When packet overflow occurs return immediately. */ - if (pnt + BGP_ADDPATH_ID_LEN > lim) + if (pnt + BGP_ADDPATH_ID_LEN >= lim) return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; addpath_id = ntohl(*((uint32_t *)pnt)); @@ -6377,6 +6415,7 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, /* Aggregate route attribute. */ #define AGGREGATE_SUMMARY_ONLY 1 #define AGGREGATE_AS_SET 1 +#define AGGREGATE_AS_UNSET 0 static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, afi_t afi, safi_t safi) @@ -6479,6 +6518,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, struct prefix p; struct bgp_node *rn; struct bgp_aggregate *aggregate; + uint8_t as_set_new = as_set; /* Convert string to prefix structure. */ ret = str2prefix(prefix_str, &p); @@ -6513,7 +6553,27 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, /* Make aggregate address structure. */ aggregate = bgp_aggregate_new(); aggregate->summary_only = summary_only; - aggregate->as_set = as_set; + + /* Network operators MUST NOT locally generate any new + * announcements containing AS_SET or AS_CONFED_SET. If they have + * announced routes with AS_SET or AS_CONFED_SET in them, then they + * SHOULD withdraw those routes and re-announce routes for the + * aggregate or component prefixes (i.e., the more-specific routes + * subsumed by the previously aggregated route) without AS_SET + * or AS_CONFED_SET in the updates. + */ + if (bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) { + if (as_set == AGGREGATE_AS_SET) { + as_set_new = AGGREGATE_AS_UNSET; + zlog_warn( + "%s: Ignoring as-set because `bgp reject-as-sets` is enabled.\n", + __func__); + vty_out(vty, + "Ignoring as-set because `bgp reject-as-sets` is enabled.\n"); + } + } + + aggregate->as_set = as_set_new; aggregate->safi = safi; if (rmap) { @@ -6548,8 +6608,8 @@ DEFUN (aggregate_address, argv_find(argv, argc, "A.B.C.D/M", &idx); char *prefix = argv[idx]->arg; char *rmap = NULL; - int as_set = - argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; + int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET + : AGGREGATE_AS_UNSET; idx = 0; int summary_only = argv_find(argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY @@ -6583,8 +6643,8 @@ DEFUN (aggregate_address_mask, char *mask = argv[idx + 1]->arg; bool rmap_found; char *rmap = NULL; - int as_set = - argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; + int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET + : AGGREGATE_AS_UNSET; idx = 0; int summary_only = argv_find(argv, argc, "summary-only", &idx) ? AGGREGATE_SUMMARY_ONLY @@ -6672,8 +6732,8 @@ DEFUN (ipv6_aggregate_address, char *prefix = argv[idx]->arg; char *rmap = NULL; bool rmap_found; - int as_set = - argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : 0; + int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET + : AGGREGATE_AS_UNSET; idx = 0; int sum_only = argv_find(argv, argc, "summary-only", &idx) @@ -9356,7 +9416,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, json_object_free(json_paths); json_paths = NULL; first = 0; - } + } else + json_object_free(json_paths); } if (output_cum) { @@ -10585,7 +10646,7 @@ enum bgp_stats { BGP_STATS_MAX, }; -static const char *table_stats_strs[] = { +static const char *const table_stats_strs[] = { [BGP_STATS_PREFIXES] = "Total Prefixes", [BGP_STATS_TOTPLEN] = "Average prefix length", [BGP_STATS_RIB] = "Total Advertisements", @@ -10843,7 +10904,7 @@ enum bgp_pcounts { PCOUNT_MAX, }; -static const char *pcount_strs[] = { +static const char *const pcount_strs[] = { [PCOUNT_ADJ_IN] = "Adj-in", [PCOUNT_DAMPED] = "Damped", [PCOUNT_REMOVED] = "Removed", @@ -12170,6 +12231,12 @@ DEFUN (bgp_damp_set, max = 4 * half; } + /* + * These can't be 0 but our SA doesn't understand the + * way our cli is constructed + */ + assert(reuse); + assert(half); if (suppress < reuse) { vty_out(vty, "Suppress value cannot be less than reuse value \n"); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index a710873ea7..b9f3f3f762 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -114,6 +114,10 @@ struct bgp_path_info_extra { mpls_label_t label[BGP_MAX_LABELS]; uint32_t num_labels; + /* af specific flags */ + uint16_t af_flags; +#define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0) + #if ENABLE_BGP_VNC union { diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 4d73faa87c..ecd770a1d1 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -334,9 +334,12 @@ static void route_match_peer_free(void *rule) } /* Route map commands for ip address matching. */ -struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer, - route_match_peer_compile, - route_match_peer_free}; +static const struct route_map_rule_cmd route_match_peer_cmd = { + "peer", + route_match_peer, + route_match_peer_compile, + route_match_peer_free +}; #if defined(HAVE_LUA) static enum route_map_cmd_result_t @@ -425,7 +428,7 @@ route_match_command_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_command_cmd = { +static const struct route_map_rule_cmd route_match_command_cmd = { "command", route_match_command, route_match_command_compile, @@ -469,9 +472,12 @@ static void route_match_ip_address_free(void *rule) } /* Route map commands for ip address matching. */ -struct route_map_rule_cmd route_match_ip_address_cmd = { - "ip address", route_match_ip_address, route_match_ip_address_compile, - route_match_ip_address_free}; +static const struct route_map_rule_cmd route_match_ip_address_cmd = { + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; /* `match ip next-hop IP_ADDRESS' */ @@ -515,9 +521,12 @@ static void route_match_ip_next_hop_free(void *rule) } /* Route map commands for ip next-hop matching. */ -struct route_map_rule_cmd route_match_ip_next_hop_cmd = { - "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile, - route_match_ip_next_hop_free}; +static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = { + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; /* `match ip route-source ACCESS-LIST' */ @@ -567,9 +576,12 @@ static void route_match_ip_route_source_free(void *rule) } /* Route map commands for ip route-source matching. */ -struct route_map_rule_cmd route_match_ip_route_source_cmd = { - "ip route-source", route_match_ip_route_source, - route_match_ip_route_source_compile, route_match_ip_route_source_free}; +static const struct route_map_rule_cmd route_match_ip_route_source_cmd = { + "ip route-source", + route_match_ip_route_source, + route_match_ip_route_source_compile, + route_match_ip_route_source_free +}; static enum route_map_cmd_result_t route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist, @@ -643,10 +655,13 @@ static void route_match_ip_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { - "ip address prefix-list", route_match_ip_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_address_prefix_list_cmd = { + "ip address prefix-list", + route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, - route_match_ip_address_prefix_list_free}; + route_match_ip_address_prefix_list_free +}; /* `match ip next-hop prefix-list PREFIX_LIST' */ @@ -685,10 +700,13 @@ static void route_match_ip_next_hop_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { - "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_next_hop_prefix_list_cmd = { + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, - route_match_ip_next_hop_prefix_list_free}; + route_match_ip_next_hop_prefix_list_free +}; /* `match ip next-hop type <blackhole>' */ @@ -724,10 +742,13 @@ static void route_match_ip_next_hop_type_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { - "ip next-hop type", route_match_ip_next_hop_type, +static const struct route_map_rule_cmd + route_match_ip_next_hop_type_cmd = { + "ip next-hop type", + route_match_ip_next_hop_type, route_match_ip_next_hop_type_compile, - route_match_ip_next_hop_type_free}; + route_match_ip_next_hop_type_free +}; /* `match ip route-source prefix-list PREFIX_LIST' */ @@ -773,10 +794,13 @@ static void route_match_ip_route_source_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = { - "ip route-source prefix-list", route_match_ip_route_source_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_route_source_prefix_list_cmd = { + "ip route-source prefix-list", + route_match_ip_route_source_prefix_list, route_match_ip_route_source_prefix_list_compile, - route_match_ip_route_source_prefix_list_free}; + route_match_ip_route_source_prefix_list_free +}; /* `match evpn default-route' */ @@ -792,8 +816,13 @@ route_match_evpn_default_route(void *rule, const struct prefix *p, } /* Route map commands for default-route matching. */ -struct route_map_rule_cmd route_match_evpn_default_route_cmd = { - "evpn default-route", route_match_evpn_default_route, NULL, NULL}; +static const struct route_map_rule_cmd + route_match_evpn_default_route_cmd = { + "evpn default-route", + route_match_evpn_default_route, + NULL, + NULL +}; /* `match mac address MAC_ACCESS_LIST' */ @@ -840,9 +869,12 @@ static void route_match_mac_address_free(void *rule) } /* Route map commands for mac address matching. */ -struct route_map_rule_cmd route_match_mac_address_cmd = { - "mac address", route_match_mac_address, route_match_mac_address_compile, - route_match_mac_address_free}; +static const struct route_map_rule_cmd route_match_mac_address_cmd = { + "mac address", + route_match_mac_address, + route_match_mac_address_compile, + route_match_mac_address_free +}; /* * Match function returns: @@ -917,9 +949,12 @@ static void route_match_vni_free(void *rule) } /* Route map commands for vni matching. */ -struct route_map_rule_cmd route_match_evpn_vni_cmd = { - "evpn vni", route_match_vni, route_match_vni_compile, - route_match_vni_free}; +static const struct route_map_rule_cmd route_match_evpn_vni_cmd = { + "evpn vni", + route_match_vni, + route_match_vni_compile, + route_match_vni_free +}; /* `match evpn route-type' */ @@ -965,9 +1000,12 @@ static void route_match_evpn_route_type_free(void *rule) } /* Route map commands for evpn route-type matching. */ -struct route_map_rule_cmd route_match_evpn_route_type_cmd = { - "evpn route-type", route_match_evpn_route_type, - route_match_evpn_route_type_compile, route_match_evpn_route_type_free}; +static const struct route_map_rule_cmd route_match_evpn_route_type_cmd = { + "evpn route-type", + route_match_evpn_route_type, + route_match_evpn_route_type_compile, + route_match_evpn_route_type_free +}; /* `match rd' */ @@ -1022,9 +1060,12 @@ static void route_match_rd_free(void *rule) } /* Route map commands for rd matching. */ -struct route_map_rule_cmd route_match_evpn_rd_cmd = { - "evpn rd", route_match_rd, route_match_rd_compile, - route_match_rd_free}; +static const struct route_map_rule_cmd route_match_evpn_rd_cmd = { + "evpn rd", + route_match_rd, + route_match_rd_compile, + route_match_rd_free +}; /* Route map commands for VRF route leak with source vrf matching */ static enum route_map_cmd_result_t @@ -1068,10 +1109,12 @@ static void route_match_vrl_source_vrf_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = { - "source-vrf", route_match_vrl_source_vrf, +static const struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = { + "source-vrf", + route_match_vrl_source_vrf, route_match_vrl_source_vrf_compile, - route_match_vrl_source_vrf_free}; + route_match_vrl_source_vrf_free +}; /* `match local-preference LOCAL-PREF' */ @@ -1127,9 +1170,12 @@ static void route_match_local_pref_free(void *rule) } /* Route map commands for metric matching. */ -struct route_map_rule_cmd route_match_local_pref_cmd = { - "local-preference", route_match_local_pref, - route_match_local_pref_compile, route_match_local_pref_free}; +static const struct route_map_rule_cmd route_match_local_pref_cmd = { + "local-preference", + route_match_local_pref, + route_match_local_pref_compile, + route_match_local_pref_free +}; /* `match metric METRIC' */ @@ -1150,8 +1196,11 @@ route_match_metric(void *rule, const struct prefix *prefix, } /* Route map commands for metric matching. */ -struct route_map_rule_cmd route_match_metric_cmd = { - "metric", route_match_metric, route_value_compile, route_value_free, +static const struct route_map_rule_cmd route_match_metric_cmd = { + "metric", + route_match_metric, + route_value_compile, + route_value_free, }; /* `match as-path ASPATH' */ @@ -1194,9 +1243,12 @@ static void route_match_aspath_free(void *rule) } /* Route map commands for aspath matching. */ -struct route_map_rule_cmd route_match_aspath_cmd = { - "as-path", route_match_aspath, route_match_aspath_compile, - route_match_aspath_free}; +static const struct route_map_rule_cmd route_match_aspath_cmd = { + "as-path", + route_match_aspath, + route_match_aspath_compile, + route_match_aspath_free +}; /* `match community COMMUNIY' */ struct rmap_community { @@ -1286,9 +1338,13 @@ static void *route_match_get_community_key(void *rule) /* Route map commands for community matching. */ -struct route_map_rule_cmd route_match_community_cmd = { - "community", route_match_community, route_match_community_compile, - route_match_community_free, route_match_get_community_key}; +static const struct route_map_rule_cmd route_match_community_cmd = { + "community", + route_match_community, + route_match_community_compile, + route_match_community_free, + route_match_get_community_key +}; /* Match function for lcommunity match. */ static enum route_map_cmd_result_t @@ -1357,10 +1413,13 @@ static void route_match_lcommunity_free(void *rule) } /* Route map commands for community matching. */ -struct route_map_rule_cmd route_match_lcommunity_cmd = { - "large-community", route_match_lcommunity, - route_match_lcommunity_compile, route_match_lcommunity_free, - route_match_get_community_key}; +static const struct route_map_rule_cmd route_match_lcommunity_cmd = { + "large-community", + route_match_lcommunity, + route_match_lcommunity_compile, + route_match_lcommunity_free, + route_match_get_community_key +}; /* Match function for extcommunity match. */ @@ -1409,9 +1468,12 @@ static void route_match_ecommunity_free(void *rule) } /* Route map commands for community matching. */ -struct route_map_rule_cmd route_match_ecommunity_cmd = { - "extcommunity", route_match_ecommunity, route_match_ecommunity_compile, - route_match_ecommunity_free}; +static const struct route_map_rule_cmd route_match_ecommunity_cmd = { + "extcommunity", + route_match_ecommunity, + route_match_ecommunity_compile, + route_match_ecommunity_free +}; /* `match nlri` and `set nlri` are replaced by `address-family ipv4` and `address-family vpnv4'. */ @@ -1458,9 +1520,12 @@ static void route_match_origin_free(void *rule) } /* Route map commands for origin matching. */ -struct route_map_rule_cmd route_match_origin_cmd = { - "origin", route_match_origin, route_match_origin_compile, - route_match_origin_free}; +static const struct route_map_rule_cmd route_match_origin_cmd = { + "origin", + route_match_origin, + route_match_origin_compile, + route_match_origin_free +}; /* match probability { */ @@ -1511,9 +1576,12 @@ static void route_match_probability_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_probability_cmd = { - "probability", route_match_probability, route_match_probability_compile, - route_match_probability_free}; +static const struct route_map_rule_cmd route_match_probability_cmd = { + "probability", + route_match_probability, + route_match_probability_compile, + route_match_probability_free +}; /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return @@ -1555,9 +1623,12 @@ static void route_match_interface_free(void *rule) } /* Route map commands for ip address matching. */ -struct route_map_rule_cmd route_match_interface_cmd = { - "interface", route_match_interface, route_match_interface_compile, - route_match_interface_free}; +static const struct route_map_rule_cmd route_match_interface_cmd = { + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; /* } */ @@ -1583,8 +1654,10 @@ route_match_tag(void *rule, const struct prefix *prefix, /* Route map commands for tag matching. */ -static struct route_map_rule_cmd route_match_tag_cmd = { - "tag", route_match_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd route_match_tag_cmd = { + "tag", + route_match_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -1694,9 +1767,12 @@ static void route_set_ip_nexthop_free(void *rule) } /* Route map commands for ip nexthop set. */ -struct route_map_rule_cmd route_set_ip_nexthop_cmd = { - "ip next-hop", route_set_ip_nexthop, route_set_ip_nexthop_compile, - route_set_ip_nexthop_free}; +static const struct route_map_rule_cmd route_set_ip_nexthop_cmd = { + "ip next-hop", + route_set_ip_nexthop, + route_set_ip_nexthop_compile, + route_set_ip_nexthop_free +}; /* `set local-preference LOCAL_PREF' */ @@ -1727,8 +1803,10 @@ route_set_local_pref(void *rule, const struct prefix *prefix, } /* Set local preference rule structure. */ -struct route_map_rule_cmd route_set_local_pref_cmd = { - "local-preference", route_set_local_pref, route_value_compile, +static const struct route_map_rule_cmd route_set_local_pref_cmd = { + "local-preference", + route_set_local_pref, + route_value_compile, route_value_free, }; @@ -1755,8 +1833,11 @@ route_set_weight(void *rule, const struct prefix *prefix, } /* Set local preference rule structure. */ -struct route_map_rule_cmd route_set_weight_cmd = { - "weight", route_set_weight, route_value_compile, route_value_free, +static const struct route_map_rule_cmd route_set_weight_cmd = { + "weight", + route_set_weight, + route_value_compile, + route_value_free, }; /* `set distance DISTANCE */ @@ -1776,7 +1857,7 @@ route_set_distance(void *rule, const struct prefix *prefix, } /* set distance rule structure */ -struct route_map_rule_cmd route_set_distance_cmd = { +static const struct route_map_rule_cmd route_set_distance_cmd = { "distance", route_set_distance, route_value_compile, @@ -1809,8 +1890,11 @@ route_set_metric(void *rule, const struct prefix *prefix, } /* Set metric rule structure. */ -struct route_map_rule_cmd route_set_metric_cmd = { - "metric", route_set_metric, route_value_compile, route_value_free, +static const struct route_map_rule_cmd route_set_metric_cmd = { + "metric", + route_set_metric, + route_value_compile, + route_value_free, }; /* `set table (1-4294967295)' */ @@ -1834,9 +1918,11 @@ static enum route_map_cmd_result_t route_set_table_id(void *rule, } /* Set table_id rule structure. */ -static struct route_map_rule_cmd route_set_table_id_cmd = { - "table", route_set_table_id, - route_value_compile, route_value_free +static const struct route_map_rule_cmd route_set_table_id_cmd = { + "table", + route_set_table_id, + route_value_compile, + route_value_free }; /* `set as-path prepend ASPATH' */ @@ -1892,9 +1978,11 @@ static void route_set_aspath_prepend_free(void *rule) /* Set as-path prepend rule structure. */ -struct route_map_rule_cmd route_set_aspath_prepend_cmd = { - "as-path prepend", route_set_aspath_prepend, - route_set_aspath_prepend_compile, route_set_aspath_prepend_free, +static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { + "as-path prepend", + route_set_aspath_prepend, + route_set_aspath_prepend_compile, + route_set_aspath_prepend_free, }; /* `set as-path exclude ASn' */ @@ -1925,8 +2013,10 @@ route_set_aspath_exclude(void *rule, const struct prefix *dummy, } /* Set ASn exlude rule structure. */ -struct route_map_rule_cmd route_set_aspath_exclude_cmd = { - "as-path exclude", route_set_aspath_exclude, route_aspath_compile, +static const struct route_map_rule_cmd route_set_aspath_exclude_cmd = { + "as-path exclude", + route_set_aspath_exclude, + route_aspath_compile, route_aspath_free, }; @@ -2039,8 +2129,10 @@ static void route_set_community_free(void *rule) } /* Set community rule structure. */ -struct route_map_rule_cmd route_set_community_cmd = { - "community", route_set_community, route_set_community_compile, +static const struct route_map_rule_cmd route_set_community_cmd = { + "community", + route_set_community, + route_set_community_compile, route_set_community_free, }; @@ -2157,8 +2249,10 @@ static void route_set_lcommunity_free(void *rule) } /* Set community rule structure. */ -struct route_map_rule_cmd route_set_lcommunity_cmd = { - "large-community", route_set_lcommunity, route_set_lcommunity_compile, +static const struct route_map_rule_cmd route_set_lcommunity_cmd = { + "large-community", + route_set_lcommunity, + route_set_lcommunity_compile, route_set_lcommunity_free, }; @@ -2246,9 +2340,11 @@ static void route_set_lcommunity_delete_free(void *rule) } /* Set lcommunity rule structure. */ -struct route_map_rule_cmd route_set_lcommunity_delete_cmd = { - "large-comm-list", route_set_lcommunity_delete, - route_set_lcommunity_delete_compile, route_set_lcommunity_delete_free, +static const struct route_map_rule_cmd route_set_lcommunity_delete_cmd = { + "large-comm-list", + route_set_lcommunity_delete, + route_set_lcommunity_delete_compile, + route_set_lcommunity_delete_free, }; @@ -2336,9 +2432,11 @@ static void route_set_community_delete_free(void *rule) } /* Set community rule structure. */ -struct route_map_rule_cmd route_set_community_delete_cmd = { - "comm-list", route_set_community_delete, - route_set_community_delete_compile, route_set_community_delete_free, +static const struct route_map_rule_cmd route_set_community_delete_cmd = { + "comm-list", + route_set_community_delete, + route_set_community_delete_compile, + route_set_community_delete_free, }; /* `set extcommunity rt COMMUNITY' */ @@ -2403,9 +2501,11 @@ static void route_set_ecommunity_free(void *rule) } /* Set community rule structure. */ -struct route_map_rule_cmd route_set_ecommunity_rt_cmd = { - "extcommunity rt", route_set_ecommunity, - route_set_ecommunity_rt_compile, route_set_ecommunity_free, +static const struct route_map_rule_cmd route_set_ecommunity_rt_cmd = { + "extcommunity rt", + route_set_ecommunity, + route_set_ecommunity_rt_compile, + route_set_ecommunity_free, }; /* `set extcommunity soo COMMUNITY' */ @@ -2423,9 +2523,11 @@ static void *route_set_ecommunity_soo_compile(const char *arg) } /* Set community rule structure. */ -struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { - "extcommunity soo", route_set_ecommunity, - route_set_ecommunity_soo_compile, route_set_ecommunity_free, +static const struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { + "extcommunity soo", + route_set_ecommunity, + route_set_ecommunity_soo_compile, + route_set_ecommunity_free, }; /* `set origin ORIGIN' */ @@ -2472,8 +2574,10 @@ static void route_set_origin_free(void *rule) } /* Set origin rule structure. */ -struct route_map_rule_cmd route_set_origin_cmd = { - "origin", route_set_origin, route_set_origin_compile, +static const struct route_map_rule_cmd route_set_origin_cmd = { + "origin", + route_set_origin, + route_set_origin_compile, route_set_origin_free, }; @@ -2507,9 +2611,11 @@ static void route_set_atomic_aggregate_free(void *rule) } /* Set atomic aggregate rule structure. */ -struct route_map_rule_cmd route_set_atomic_aggregate_cmd = { - "atomic-aggregate", route_set_atomic_aggregate, - route_set_atomic_aggregate_compile, route_set_atomic_aggregate_free, +static const struct route_map_rule_cmd route_set_atomic_aggregate_cmd = { + "atomic-aggregate", + route_set_atomic_aggregate, + route_set_atomic_aggregate_compile, + route_set_atomic_aggregate_free, }; /* `set aggregator as AS A.B.C.D' */ @@ -2565,9 +2671,11 @@ static void route_set_aggregator_as_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_set_aggregator_as_cmd = { - "aggregator as", route_set_aggregator_as, - route_set_aggregator_as_compile, route_set_aggregator_as_free, +static const struct route_map_rule_cmd route_set_aggregator_as_cmd = { + "aggregator as", + route_set_aggregator_as, + route_set_aggregator_as_compile, + route_set_aggregator_as_free, }; /* Set tag to object. object must be pointer to struct bgp_path_info */ @@ -2590,8 +2698,10 @@ route_set_tag(void *rule, const struct prefix *prefix, } /* Route map commands for tag set. */ -static struct route_map_rule_cmd route_set_tag_cmd = { - "tag", route_set_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd route_set_tag_cmd = { + "tag", + route_set_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -2621,8 +2731,10 @@ route_set_label_index(void *rule, const struct prefix *prefix, } /* Route map commands for label-index set. */ -static struct route_map_rule_cmd route_set_label_index_cmd = { - "label-index", route_set_label_index, route_value_compile, +static const struct route_map_rule_cmd route_set_label_index_cmd = { + "label-index", + route_set_label_index, + route_value_compile, route_value_free, }; @@ -2657,9 +2769,12 @@ static void route_match_ipv6_address_free(void *rule) } /* Route map commands for ip address matching. */ -struct route_map_rule_cmd route_match_ipv6_address_cmd = { - "ipv6 address", route_match_ipv6_address, - route_match_ipv6_address_compile, route_match_ipv6_address_free}; +static const struct route_map_rule_cmd route_match_ipv6_address_cmd = { + "ipv6 address", + route_match_ipv6_address, + route_match_ipv6_address_compile, + route_match_ipv6_address_free +}; /* `match ipv6 next-hop IP_ADDRESS' */ @@ -2708,9 +2823,12 @@ static void route_match_ipv6_next_hop_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = { - "ipv6 next-hop", route_match_ipv6_next_hop, - route_match_ipv6_next_hop_compile, route_match_ipv6_next_hop_free}; +static const struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = { + "ipv6 next-hop", + route_match_ipv6_next_hop, + route_match_ipv6_next_hop_compile, + route_match_ipv6_next_hop_free +}; /* `match ipv6 address prefix-list PREFIX_LIST' */ @@ -2732,10 +2850,13 @@ static void route_match_ipv6_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { - "ipv6 address prefix-list", route_match_ipv6_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ipv6_address_prefix_list_cmd = { + "ipv6 address prefix-list", + route_match_ipv6_address_prefix_list, route_match_ipv6_address_prefix_list_compile, - route_match_ipv6_address_prefix_list_free}; + route_match_ipv6_address_prefix_list_free +}; /* `match ipv6 next-hop type <TYPE>' */ @@ -2779,10 +2900,13 @@ static void route_match_ipv6_next_hop_type_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = { - "ipv6 next-hop type", route_match_ipv6_next_hop_type, +static const struct route_map_rule_cmd + route_match_ipv6_next_hop_type_cmd = { + "ipv6 next-hop type", + route_match_ipv6_next_hop_type, route_match_ipv6_next_hop_type_compile, - route_match_ipv6_next_hop_type_free}; + route_match_ipv6_next_hop_type_free +}; /* `set ipv6 nexthop global IP_ADDRESS' */ @@ -2839,10 +2963,13 @@ static void route_set_ipv6_nexthop_global_free(void *rule) } /* Route map commands for ip nexthop set. */ -struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = { - "ipv6 next-hop global", route_set_ipv6_nexthop_global, +static const struct route_map_rule_cmd + route_set_ipv6_nexthop_global_cmd = { + "ipv6 next-hop global", + route_set_ipv6_nexthop_global, route_set_ipv6_nexthop_global_compile, - route_set_ipv6_nexthop_global_free}; + route_set_ipv6_nexthop_global_free +}; /* Set next-hop preference value. */ static enum route_map_cmd_result_t @@ -2889,10 +3016,13 @@ static void route_set_ipv6_nexthop_prefer_global_free(void *rule) } /* Route map commands for ip nexthop set preferred. */ -struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = { - "ipv6 next-hop prefer-global", route_set_ipv6_nexthop_prefer_global, +static const struct route_map_rule_cmd + route_set_ipv6_nexthop_prefer_global_cmd = { + "ipv6 next-hop prefer-global", + route_set_ipv6_nexthop_prefer_global, route_set_ipv6_nexthop_prefer_global_compile, - route_set_ipv6_nexthop_prefer_global_free}; + route_set_ipv6_nexthop_prefer_global_free +}; /* `set ipv6 nexthop local IP_ADDRESS' */ @@ -2951,10 +3081,13 @@ static void route_set_ipv6_nexthop_local_free(void *rule) } /* Route map commands for ip nexthop set. */ -struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = { - "ipv6 next-hop local", route_set_ipv6_nexthop_local, +static const struct route_map_rule_cmd + route_set_ipv6_nexthop_local_cmd = { + "ipv6 next-hop local", + route_set_ipv6_nexthop_local, route_set_ipv6_nexthop_local_compile, - route_set_ipv6_nexthop_local_free}; + route_set_ipv6_nexthop_local_free +}; /* `set ipv6 nexthop peer-address' */ @@ -3033,9 +3166,12 @@ static void route_set_ipv6_nexthop_peer_free(void *rule) } /* Route map commands for ip nexthop set. */ -struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = { - "ipv6 next-hop peer-address", route_set_ipv6_nexthop_peer, - route_set_ipv6_nexthop_peer_compile, route_set_ipv6_nexthop_peer_free}; +static const struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = { + "ipv6 next-hop peer-address", + route_set_ipv6_nexthop_peer, + route_set_ipv6_nexthop_peer_compile, + route_set_ipv6_nexthop_peer_free +}; /* `set ipv4 vpn next-hop A.B.C.D' */ @@ -3121,14 +3257,20 @@ static void route_set_vpn_nexthop_free(void *rule) } /* Route map commands for ipv4 next-hop set. */ -struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = { - "ipv4 vpn next-hop", route_set_vpnv4_nexthop, - route_set_vpnv4_nexthop_compile, route_set_vpn_nexthop_free}; +static const struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = { + "ipv4 vpn next-hop", + route_set_vpnv4_nexthop, + route_set_vpnv4_nexthop_compile, + route_set_vpn_nexthop_free +}; /* Route map commands for ipv6 next-hop set. */ -struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = { - "ipv6 vpn next-hop", route_set_vpnv6_nexthop, - route_set_vpnv6_nexthop_compile, route_set_vpn_nexthop_free}; +static const struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = { + "ipv6 vpn next-hop", + route_set_vpnv6_nexthop, + route_set_vpnv6_nexthop_compile, + route_set_vpn_nexthop_free +}; /* `set originator-id' */ @@ -3176,9 +3318,11 @@ static void route_set_originator_id_free(void *rule) } /* Set originator-id rule structure. */ -struct route_map_rule_cmd route_set_originator_id_cmd = { - "originator-id", route_set_originator_id, - route_set_originator_id_compile, route_set_originator_id_free, +static const struct route_map_rule_cmd route_set_originator_id_cmd = { + "originator-id", + route_set_originator_id, + route_set_originator_id_compile, + route_set_originator_id_free, }; /* Add bgp route map rule. */ diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 3b89e50ce4..7247210c93 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -143,7 +143,7 @@ static int rpki_sync_socket_rtr; static int rpki_sync_socket_bgpd; static struct cmd_node rpki_node = {RPKI_NODE, "%s(config-rpki)# ", 1}; -static struct route_map_rule_cmd route_match_rpki_cmd = { +static const struct route_map_rule_cmd route_match_rpki_cmd = { "rpki", route_match, route_match_compile, route_match_free}; static void *malloc_wrapper(size_t size) diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 53175bfccf..b75246b172 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -159,7 +159,8 @@ void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p, if (node == NULL) return; - while (node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) { + while (node && + node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) { if (bgp_node_has_bgp_path_info_data(node) && node->p.prefixlen == p->prefixlen) { matched = node; @@ -169,14 +170,20 @@ void bgp_table_range_lookup(const struct bgp_table *table, struct prefix *p, &p->u.prefix, node->p.prefixlen)]); } + if (!node) + return; + if (matched == NULL && node->p.prefixlen <= maxlen && prefix_match(p, &node->p) && node->parent == NULL) matched = node; else if ((matched == NULL && node->p.prefixlen > maxlen) || !node->parent) return; - else if (matched == NULL) + else if (matched == NULL && node->parent) matched = node = bgp_node_from_rnode(node->parent); + if (!matched) + return; + if (bgp_node_has_bgp_path_info_data(matched)) { bgp_lock_node(matched); listnode_add(matches, matched); diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index f922d066c3..b67b0c322e 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -85,9 +85,13 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, if (table == NULL) continue; - + /* + * Initialize variables for each RD + * All prefixes under an RD is aggregated within "json_routes" + */ rd_header = 1; memset(rd_str, 0, sizeof(rd_str)); + json_routes = NULL; for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) { struct bgp_adj_out *adj = NULL; @@ -223,7 +227,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, output_count++; } - if (use_json) + if (use_json && json_routes) json_object_object_add(json_adv, rd_str, json_routes); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 3116e7cad0..fa236a24b7 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1921,6 +1921,56 @@ DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd, return CMD_SUCCESS; } +DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd, + "bgp reject-as-sets", + "BGP specific commands\n" + "Reject routes with AS_SET or AS_CONFED_SET flag\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct peer *peer; + + bgp->reject_as_sets = BGP_REJECT_AS_SETS_ENABLED; + + /* Reset existing BGP sessions to reject routes + * with aspath containing AS_SET or AS_CONFED_SET. + */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + + return CMD_SUCCESS; +} + +DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd, + "no bgp reject-as-sets", + NO_STR + "BGP specific commands\n" + "Reject routes with AS_SET or AS_CONFED_SET flag\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + struct listnode *node, *nnode; + struct peer *peer; + + bgp->reject_as_sets = BGP_REJECT_AS_SETS_DISABLED; + + /* Reset existing BGP sessions to reject routes + * with aspath containing AS_SET or AS_CONFED_SET. + */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } + + return CMD_SUCCESS; +} /* "bgp deterministic-med" configuration. */ DEFUN (bgp_deterministic_med, @@ -7328,7 +7378,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, /* one clear bgp command to rule them all */ DEFUN (clear_ip_bgp_all, clear_ip_bgp_all_cmd, - "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D|X:X::X:X|WORD|(1-4294967295)|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out>]", + "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|(1-4294967295)|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out>]", CLEAR_STR IP_STR BGP_STR @@ -7338,7 +7388,7 @@ DEFUN (clear_ip_bgp_all, BGP_SAFI_WITH_LABEL_HELP_STR "Address Family modifier\n" "Clear all peers\n" - "BGP neighbor address to clear\n" + "BGP IPv4 neighbor to clear\n" "BGP IPv6 neighbor to clear\n" "BGP neighbor on interface to clear\n" "Clear peers with the AS number\n" @@ -10896,7 +10946,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_int_add(json_neigh, "externalBgpNbrMaxHopsAway", p->gtsm_hops); - else if (p->ttl > 1) + else if (p->ttl > BGP_DEFAULT_TTL) json_object_int_add(json_neigh, "externalBgpNbrMaxHopsAway", p->ttl); @@ -10905,7 +10955,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, " External BGP neighbor may be up to %d hops away.\n", p->gtsm_hops); - else if (p->ttl > 1) + else if (p->ttl > BGP_DEFAULT_TTL) vty_out(vty, " External BGP neighbor may be up to %d hops away.\n", p->ttl); @@ -13136,6 +13186,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd); install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd); + /* bgp reject-as-sets */ + install_element(BGP_NODE, &bgp_reject_as_sets_cmd); + install_element(BGP_NODE, &no_bgp_reject_as_sets_cmd); + /* "bgp deterministic-med" commands */ install_element(BGP_NODE, &bgp_deterministic_med_cmd); install_element(BGP_NODE, &no_bgp_deterministic_med_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d0a732b153..e886733ced 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -278,12 +278,14 @@ static int bgp_ifp_down(struct interface *ifp) * 1-hop BFD * tracked (directly connected) IBGP peers. */ - if ((peer->ttl != 1) && (peer->gtsm_hops != 1) + if ((peer->ttl != BGP_DEFAULT_TTL) + && (peer->gtsm_hops != 1) && (!peer->bfd_info || bgp_bfd_is_peer_multihop(peer))) #else /* Take down directly connected EBGP peers */ - if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) + if ((peer->ttl != BGP_DEFAULT_TTL) + && (peer->gtsm_hops != 1)) #endif continue; @@ -448,7 +450,8 @@ static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS) /* Fast external-failover */ if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) + if ((peer->ttl != BGP_DEFAULT_TTL) + && (peer->gtsm_hops != 1)) continue; if (ifp == peer->nexthop.ifp) @@ -1222,7 +1225,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); } - if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) + if ((peer->sort == BGP_PEER_EBGP && peer->ttl != BGP_DEFAULT_TTL) || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) || bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) @@ -2469,30 +2472,37 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) int filter = 0; char buf[ETHER_ADDR_STRLEN]; vni_t l3vni = 0; - struct ethaddr rmac; + struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} }; struct in_addr originator_ip; struct stream *s; ifindex_t svi_ifindex; + bool is_anycast_mac = false; + char buf1[ETHER_ADDR_STRLEN]; - memset(&rmac, 0, sizeof(struct ethaddr)); + memset(&svi_rmac, 0, sizeof(struct ethaddr)); memset(&originator_ip, 0, sizeof(struct in_addr)); s = zclient->ibuf; l3vni = stream_getl(s); if (cmd == ZEBRA_L3VNI_ADD) { - stream_get(&rmac, s, sizeof(struct ethaddr)); + stream_get(&svi_rmac, s, sizeof(struct ethaddr)); originator_ip.s_addr = stream_get_ipv4(s); stream_get(&filter, s, sizeof(int)); svi_ifindex = stream_getl(s); + stream_get(&vrr_rmac, s, sizeof(struct ethaddr)); + is_anycast_mac = stream_getl(s); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC %s filter %s svi-if %u", + zlog_debug("Rx L3-VNI ADD VRF %s VNI %u RMAC svi-mac %s vrr-mac %s filter %s svi-if %u", vrf_id_to_name(vrf_id), l3vni, - prefix_mac2str(&rmac, buf, sizeof(buf)), + prefix_mac2str(&svi_rmac, buf, sizeof(buf)), + prefix_mac2str(&vrr_rmac, buf1, + sizeof(buf1)), filter ? "prefix-routes-only" : "none", svi_ifindex); - bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip, - filter, svi_ifindex); + bgp_evpn_local_l3vni_add(l3vni, vrf_id, &svi_rmac, &vrr_rmac, + originator_ip, filter, svi_ifindex, + is_anycast_mac); } else { if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d4e60b4093..4283fe169e 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2990,6 +2990,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; bgp->dynamic_neighbors_count = 0; bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; + bgp->reject_as_sets = BGP_REJECT_AS_SETS_DISABLED; #if DFLT_BGP_IMPORT_CHECK bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK); #endif @@ -6557,16 +6558,17 @@ int is_ebgp_multihop_configured(struct peer *peer) if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; if ((peer_sort(peer) != BGP_PEER_IBGP) - && (group->conf->ttl != 1)) + && (group->conf->ttl != BGP_DEFAULT_TTL)) return 1; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer1)) { if ((peer_sort(peer1) != BGP_PEER_IBGP) - && (peer1->ttl != 1)) + && (peer1->ttl != BGP_DEFAULT_TTL)) return 1; } } else { - if ((peer_sort(peer) != BGP_PEER_IBGP) && (peer->ttl != 1)) + if ((peer_sort(peer) != BGP_PEER_IBGP) + && (peer->ttl != BGP_DEFAULT_TTL)) return 1; } return 0; @@ -7109,7 +7111,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s passive\n", addr); /* ebgp-multihop */ - if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 + if (peer->sort != BGP_PEER_IBGP && peer->ttl != BGP_DEFAULT_TTL && !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) { if (!peer_group_active(peer) || g_peer->ttl != peer->ttl) { vty_out(vty, " neighbor %s ebgp-multihop %d\n", addr, @@ -7617,6 +7619,10 @@ int bgp_config_write(struct vty *vty) == DEFAULT_EBGP_POLICY_ENABLED) vty_out(vty, " bgp ebgp-requires-policy\n"); + /* draft-ietf-idr-deprecate-as-set-confed-set */ + if (bgp->reject_as_sets == BGP_REJECT_AS_SETS_ENABLED) + vty_out(vty, " bgp reject-as-sets\n"); + /* BGP default ipv4-unicast. */ if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) vty_out(vty, " no bgp default ipv4-unicast\n"); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e27018407f..568438b0ce 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -504,6 +504,13 @@ struct bgp { #define DEFAULT_EBGP_POLICY_DISABLED 0 #define DEFAULT_EBGP_POLICY_ENABLED 1 + /* draft-ietf-idr-deprecate-as-set-confed-set + * Reject aspaths with AS_SET and/or AS_CONFED_SET. + */ + bool reject_as_sets; +#define BGP_REJECT_AS_SETS_DISABLED 0 +#define BGP_REJECT_AS_SETS_ENABLED 1 + struct bgp_evpn_info *evpn_info; /* EVPN - use RFC 8365 to auto-derive RT */ @@ -1203,6 +1210,7 @@ struct peer { #define PEER_DOWN_NBR_ADDR 28 /* Waiting for peer IPv6 IP Addr */ #define PEER_DOWN_VRF_UNINIT 29 /* Associated VRF is not init yet */ #define PEER_DOWN_NOAFI_ACTIVATED 30 /* No AFI/SAFI activated for peer */ +#define PEER_DOWN_AS_SETS_REJECT 31 /* Reject routes with AS_SET */ size_t last_reset_cause_size; uint8_t last_reset_cause[BGP_MAX_PACKET_SIZE]; diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 4fa64075c4..5ad822211b 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -127,8 +127,8 @@ void rfapiRprefixApplyMask(struct rfapi_ip_prefix *rprefix) int index; int offset; - static uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, - 0xf8, 0xfc, 0xfe, 0xff}; + static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, + 0xf8, 0xfc, 0xfe, 0xff}; switch (rprefix->prefix.addr_family) { case AF_INET: diff --git a/bgpd/rfapi/vnc_debug.c b/bgpd/rfapi/vnc_debug.c index 7cac7ac7a1..2c5e188328 100644 --- a/bgpd/rfapi/vnc_debug.c +++ b/bgpd/rfapi/vnc_debug.c @@ -38,7 +38,7 @@ struct vnc_debug { const char *name; }; -struct vnc_debug vncdebug[] = { +static const struct vnc_debug vncdebug[] = { {VNC_DEBUG_RFAPI_QUERY, "rfapi-query"}, {VNC_DEBUG_IMPORT_BI_ATTACH, "import-bi-attach"}, {VNC_DEBUG_IMPORT_DEL_REMOTE, "import-del-remote"}, diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 4b3113cf3b..de75c12e62 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -416,6 +416,14 @@ Require policy on EBGP This command requires incoming and outgoing filters to be applied for eBGP sessions. Without the incoming filter, no routes will be accepted. Without the outgoing filter, no routes will be announced. +Reject routes with AS_SET or AS_CONFED_SET types +------------------------------- + +.. index:: [no] bgp reject-as-sets +.. clicmd:: [no] bgp reject-as-sets + + This command enables rejection of incoming and outgoing routes having AS_SET or AS_CONFED_SET type. + .. _bgp-route-flap-dampening: Route Flap Dampening @@ -2056,6 +2064,61 @@ address-family: the VPN RIB as intermediary. +.. _bgp-evpn: + +Ethernet Virtual Network - EVPN +------------------------------- + +.. _bgp-evpn-advertise-pip: + +EVPN advertise-PIP +^^^^^^^^^^^^^^^^^^ + +In a EVPN symmetric routing MLAG deployment, all EVPN routes advertised +with anycast-IP as next-hop IP and anycast MAC as the Router MAC (RMAC - in +BGP EVPN Extended-Community). +EVPN picks up the next-hop IP from the VxLAN interface's local tunnel IP and +the RMAC is obtained from the MAC of the L3VNI's SVI interface. +Note: Next-hop IP is used for EVPN routes whether symmetric routing is +deployed or not but the RMAC is only relevant for symmetric routing scenario. + +Current behavior is not ideal for Prefix (type-5) and self (type-2) +routes. This is because the traffic from remote VTEPs routed sub optimally +if they land on the system where the route does not belong. + +The advertise-pip feature advertises Prefix (type-5) and self (type-2) +routes with system's individual (primary) IP as the next-hop and individual +(system) MAC as Router-MAC (RMAC), while leaving the behavior unchanged for +other EVPN routes. + +To support this feature there needs to have ability to co-exist a +(system-MAC, system-IP) pair with a (anycast-MAC, anycast-IP) pair with the +ability to terminate VxLAN-encapsulated packets received for either pair on +the same L3VNI (i.e associated VLAN). This capability is need per tenant +VRF instance. + +To derive the system-MAC and the anycast MAC, there needs to have a +separate/additional MAC-VLAN interface corresponding to L3VNI’s SVI. +The SVI interface’s MAC address can be interpreted as system-MAC +and MAC-VLAN interface's MAC as anycast MAC. + +To derive system-IP and anycast-IP, the default BGP instance's router-id is used +as system-IP and the VxLAN interface’s local tunnel IP as the anycast-IP. + +User has an option to configure the system-IP and/or system-MAC value if the +auto derived value is not preferred. + +Note: By default, advertise-pip feature is enabled and user has an option to +disable the feature via configuration CLI. Once the feature is disable under +bgp vrf instance or MAC-VLAN interface is not configured, all the routes follow +the same behavior of using same next-hop and RMAC values. + +.. index:: [no] advertise-pip [ip <addr> [mac <addr>]] +.. clicmd:: [no] advertise-pip [ip <addr> [mac <addr>]] + +Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC +parameters. + .. _bgp-cisco-compatibility: Cisco Compatibility diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst index cc8fd18fee..f3f064b850 100644 --- a/doc/user/ipv6.rst +++ b/doc/user/ipv6.rst @@ -77,6 +77,20 @@ Router Advertisement Default: ``600000`` .. index:: + single: ipv6 nd ra-fast-retrans + single: no ipv6 nd ra-fast-retrans +.. clicmd:: [no] ipv6 nd ra-fast-retrans + + RFC4861 states that consecutive RA packets should be sent no more + frequently than three seconds apart. FRR by default allows faster + transmissions of RA packets in order to speed convergence and + neighbor establishment, particularly for unnumbered peering. By + turning off ipv6 nd ra-fast-retrans, the implementation is + compliant with the RFC at the cost of slower convergence + and neighbor establishment. + Default: enabled + +.. index:: single: ipv6 nd ra-lifetime (0-9000) single: no ipv6 nd ra-lifetime [(0-9000)] .. clicmd:: [no] ipv6 nd ra-lifetime [(0-9000)] diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index fab4343f50..68e460748c 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -107,6 +107,14 @@ end destination. Use this individual nexthop as the place to forward packets when the match commands have matched a packet. +.. clicmd:: set vrf unchanged|NAME + + If unchanged is set, the rule will use the vrf table the interface is in + as its lookup. If NAME is specified, the rule will use that vrf table as + its lookup. + + Not supported with NETNS VRF backend. + .. _pbr-policy: PBR Policy diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 5c2b41b63c..435639c291 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -7,6 +7,9 @@ Route Maps Route maps provide a means to both filter and/or apply actions to route, hence allowing policy to be applied to routes. +For a route reflector to apply a ``route-map`` to reflected routes, be sure to +include ``bgp route-reflector allow-outbound-policy`` in ``router bgp`` mode. + Route maps are an ordered list of route map entries. Each entry may specify up to four distinct sets of clauses: diff --git a/docker/centos/Dockerfile b/docker/centos/Dockerfile new file mode 100644 index 0000000000..088a3201bb --- /dev/null +++ b/docker/centos/Dockerfile @@ -0,0 +1,43 @@ +# This stage builds an rpm from the source +FROM centos:centos7 as centos-builder + +RUN yum install -y rpm-build autoconf automake libtool make \ + readline-devel texinfo net-snmp-devel groff pkgconfig \ + json-c-devel pam-devel bison flex pytest c-ares-devel \ + python-devel systemd-devel python-sphinx libcap-devel \ + https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/CentOS-7-x86_64-Packages/libyang-0.16.111-0.x86_64.rpm \ + https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/CentOS-7-x86_64-Packages/libyang-devel-0.16.111-0.x86_64.rpm \ + https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \ + https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-devel-0.7.0-1.el7.centos.x86_64.rpm + +COPY . /src +ARG PKGVER + +RUN echo '%_smp_mflags %( echo "-j$(/usr/bin/getconf _NPROCESSORS_ONLN)"; )' >> /root/.rpmmacros \ + && cd /src \ + && ./bootstrap.sh \ + && ./configure \ + --enable-rpki \ + --enable-numeric-version \ + --with-pkg-extra-version="_git$PKGVER" \ + && make dist \ + && cd / \ + && mkdir -p /rpmbuild/{SOURCES,SPECS} \ + && cp /src/frr*.tar.gz /rpmbuild/SOURCES \ + && cp /src/redhat/frr.spec /rpmbuild/SPECS \ + && rpmbuild \ + --define "_topdir /rpmbuild" \ + -ba /rpmbuild/SPECS/frr.spec + +# This stage installs frr from the rpm +FROM centos:centos7 +RUN mkdir -p /pkgs/rpm \ + && yum install -y https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/CentOS-7-x86_64-Packages/libyang-0.16.111-0.x86_64.rpm \ + https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm + +COPY --from=centos-builder /rpmbuild/RPMS/ /pkgs/rpm/ + +RUN yum install -y /pkgs/rpm/*/*.rpm \ + && rm -rf /pkgs +COPY docker/centos/docker-start /usr/lib/frr/docker-start +ENTRYPOINT [ "/usr/lib/frr/docker-start" ] diff --git a/docker/centos/build.sh b/docker/centos/build.sh new file mode 100755 index 0000000000..9cd0f618e4 --- /dev/null +++ b/docker/centos/build.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +set -e + +## +# Package version needs to be decimal +## +GITREV="$(git rev-parse --short=10 HEAD)" +PKGVER="$(printf '%u\n' 0x$GITREV)" + +mkdir -p docker/centos/pkgs +docker build \ + --file=docker/centos/Dockerfile \ + --build-arg="PKGVER=$PKGVER" \ + --tag="frr:centos-builder-$GITREV" \ + --target=centos-builder \ + . + +# Copy RPM package from container to host +CONTAINER_ID="$(docker create "frr:centos-builder-$GITREV")" +docker cp "${CONTAINER_ID}:/rpmbuild/RPMS/x86_64/" docker/centos/pkgs +docker rm "${CONTAINER_ID}" + +docker build \ + --cache-from="frr:centos-builder-$GITREV" \ + --file=docker/centos/Dockerfile \ + --build-arg="PKGVER=$PKGVER" \ + --tag="frr:centos-$GITREV" \ + . + +docker rmi "frr:centos-builder-$GITREV" diff --git a/docker/centos/docker-start b/docker/centos/docker-start new file mode 100755 index 0000000000..a3913245b6 --- /dev/null +++ b/docker/centos/docker-start @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e + +## +# Change owner for docker volume mount +## +chown -R frr:frr /etc/frr +/usr/lib/frr/frrinit.sh start + +# Sleep forever +exec tail -f /dev/null diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index 583db6622d..7278b002d8 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -144,55 +144,10 @@ void eigrp_header_dump(struct eigrp_header *eigrph) const char *eigrp_if_name_string(struct eigrp_interface *ei) { - static char buf[EIGRP_IF_STRING_MAXLEN] = ""; - - if (!ei) - return "inactive"; - - snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%s", ei->ifp->name); - return buf; -} - -const char *eigrp_topology_ip_string(struct eigrp_prefix_entry *tn) -{ - static char buf[EIGRP_IF_STRING_MAXLEN] = ""; - uint32_t ifaddr; - - ifaddr = ntohl(tn->destination->u.prefix4.s_addr); - snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u", - (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, - (ifaddr >> 8) & 0xff, ifaddr & 0xff); - return buf; -} - - -const char *eigrp_if_ip_string(struct eigrp_interface *ei) -{ - static char buf[EIGRP_IF_STRING_MAXLEN] = ""; - uint32_t ifaddr; - if (!ei) return "inactive"; - ifaddr = ntohl(ei->address.u.prefix4.s_addr); - snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u", - (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, - (ifaddr >> 8) & 0xff, ifaddr & 0xff); - - return buf; -} - -const char *eigrp_neigh_ip_string(struct eigrp_neighbor *nbr) -{ - static char buf[EIGRP_IF_STRING_MAXLEN] = ""; - uint32_t ifaddr; - - ifaddr = ntohl(nbr->src.s_addr); - snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u", - (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, - (ifaddr >> 8) & 0xff, ifaddr & 0xff); - - return buf; + return ei->ifp->name; } void show_ip_eigrp_interface_header(struct vty *vty, struct eigrp *eigrp) @@ -209,7 +164,7 @@ void show_ip_eigrp_interface_header(struct vty *vty, struct eigrp *eigrp) void show_ip_eigrp_interface_sub(struct vty *vty, struct eigrp *eigrp, struct eigrp_interface *ei) { - vty_out(vty, "%-11s ", eigrp_if_name_string(ei)); + vty_out(vty, "%-11s ", IF_NAME(ei)); vty_out(vty, "%-11u", ei->params.bandwidth); vty_out(vty, "%-11u", ei->params.delay); vty_out(vty, "%-7u", ei->nbrs->count); @@ -250,7 +205,7 @@ void show_ip_eigrp_neighbor_sub(struct vty *vty, struct eigrp_neighbor *nbr, { vty_out(vty, "%-3u %-17s %-21s", 0, eigrp_neigh_ip_string(nbr), - eigrp_if_name_string(nbr->ei)); + IF_NAME(nbr->ei)); if (nbr->t_holddown) vty_out(vty, "%-7lu", thread_timer_remain_second(nbr->t_holddown)); @@ -313,11 +268,11 @@ void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, if (te->adv_router == eigrp->neighbor_self) vty_out(vty, "%-7s%s, %s\n", " ", "via Connected", - eigrp_if_name_string(te->ei)); + IF_NAME(te->ei)); else { vty_out(vty, "%-7s%s%s (%u/%u), %s\n", " ", "via ", inet_ntoa(te->adv_router->src), te->distance, - te->reported_distance, eigrp_if_name_string(te->ei)); + te->reported_distance, IF_NAME(te->ei)); } } diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h index 34b55ab419..f141f3cbc6 100644 --- a/eigrpd/eigrp_dump.h +++ b/eigrpd/eigrp_dump.h @@ -138,9 +138,21 @@ extern unsigned long term_debug_eigrp_zebra; /* Prototypes. */ extern const char *eigrp_if_name_string(struct eigrp_interface *); -extern const char *eigrp_if_ip_string(struct eigrp_interface *); -extern const char *eigrp_neigh_ip_string(struct eigrp_neighbor *); -extern const char *eigrp_topology_ip_string(struct eigrp_prefix_entry *); +static inline const char +*eigrp_topology_ip_string(struct eigrp_prefix_entry *tn) +{ + return inet_ntoa(tn->destination->u.prefix4); +} + +static inline const char *eigrp_if_ip_string(struct eigrp_interface *ei) +{ + return ei ? inet_ntoa(ei->address.u.prefix4) : "inactive"; +} + +static inline const char *eigrp_neigh_ip_string(struct eigrp_neighbor *nbr) +{ + return inet_ntoa(nbr->src); +} extern void eigrp_ip_header_dump(struct ip *); extern void eigrp_header_dump(struct eigrp_header *); diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index cc6d47f488..e43eca0e0d 100644 --- a/eigrpd/eigrp_fsm.c +++ b/eigrpd/eigrp_fsm.c @@ -110,7 +110,7 @@ int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *); * NSM[actual/starting state][occurred event].func * Functions are should be executed within separate thread. */ -struct { +const struct { int (*func)(struct eigrp_fsm_action_message *); } NSM[EIGRP_FSM_STATE_MAX][EIGRP_FSM_EVENT_MAX] = { { diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 299825dd1b..0746b04edb 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -137,7 +137,7 @@ struct quagga_signal_t eigrp_signals[] = { }, }; -static const struct frr_yang_module_info *eigrpd_yang_modules[] = { +static const struct frr_yang_module_info *const eigrpd_yang_modules[] = { &frr_eigrpd_info, &frr_interface_info, }; diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index e7a7cc56aa..df7b9c94ee 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -319,9 +319,12 @@ static void route_match_metric_free(void *rule) } /* Route map commands for metric matching. */ -struct route_map_rule_cmd route_match_metric_cmd = { - "metric", route_match_metric, route_match_metric_compile, - route_match_metric_free}; +static const struct route_map_rule_cmd route_match_metric_cmd = { + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ @@ -366,9 +369,12 @@ static void route_match_interface_free(void *rule) } /* Route map commands for interface matching. */ -struct route_map_rule_cmd route_match_interface_cmd = { - "interface", route_match_interface, route_match_interface_compile, - route_match_interface_free}; +static const struct route_map_rule_cmd route_match_interface_cmd = { + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; /* `match ip next-hop IP_ACCESS_LIST' */ @@ -413,9 +419,12 @@ static void route_match_ip_next_hop_free(void *rule) } /* Route map commands for ip next-hop matching. */ -static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { - "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile, - route_match_ip_next_hop_free}; +static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = { + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; /* `match ip next-hop prefix-list PREFIX_LIST' */ @@ -455,10 +464,13 @@ static void route_match_ip_next_hop_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { - "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_next_hop_prefix_list_cmd = { + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, - route_match_ip_next_hop_prefix_list_free}; + route_match_ip_next_hop_prefix_list_free +}; /* `match ip address IP_ACCESS_LIST' */ @@ -496,9 +508,12 @@ static void route_match_ip_address_free(void *rule) } /* Route map commands for ip address matching. */ -static struct route_map_rule_cmd route_match_ip_address_cmd = { - "ip address", route_match_ip_address, route_match_ip_address_compile, - route_match_ip_address_free}; +static const struct route_map_rule_cmd route_match_ip_address_cmd = { + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; /* `match ip address prefix-list PREFIX_LIST' */ @@ -530,10 +545,13 @@ static void route_match_ip_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { - "ip address prefix-list", route_match_ip_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_address_prefix_list_cmd = { + "ip address prefix-list", + route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, - route_match_ip_address_prefix_list_free}; + route_match_ip_address_prefix_list_free +}; /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ @@ -576,8 +594,12 @@ static void route_match_tag_free(void *rule) } /* Route map commands for tag matching. */ -struct route_map_rule_cmd route_match_tag_cmd = { - "tag", route_match_tag, route_match_tag_compile, route_match_tag_free}; +static const struct route_map_rule_cmd route_match_tag_cmd = { + "tag", + route_match_tag, + route_match_tag_compile, + route_match_tag_free +}; /* Set metric to attribute. */ static enum route_map_cmd_result_t @@ -666,8 +688,10 @@ static void route_set_metric_free(void *rule) } /* Set metric rule structure. */ -static struct route_map_rule_cmd route_set_metric_cmd = { - "metric", route_set_metric, route_set_metric_compile, +static const struct route_map_rule_cmd route_set_metric_cmd = { + "metric", + route_set_metric, + route_set_metric_compile, route_set_metric_free, }; @@ -722,9 +746,12 @@ static void route_set_ip_nexthop_free(void *rule) } /* Route map commands for ip nexthop set. */ -static struct route_map_rule_cmd route_set_ip_nexthop_cmd = { - "ip next-hop", route_set_ip_nexthop, route_set_ip_nexthop_compile, - route_set_ip_nexthop_free}; +static const struct route_map_rule_cmd route_set_ip_nexthop_cmd = { + "ip next-hop", + route_set_ip_nexthop, + route_set_ip_nexthop_compile, + route_set_ip_nexthop_free +}; /* `set tag TAG' */ @@ -768,8 +795,12 @@ static void route_set_tag_free(void *rule) } /* Route map commands for tag set. */ -static struct route_map_rule_cmd route_set_tag_cmd = { - "tag", route_set_tag, route_set_tag_compile, route_set_tag_free}; +static const struct route_map_rule_cmd route_set_tag_cmd = { + "tag", + route_set_tag, + route_set_tag_compile, + route_set_tag_free +}; #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index d6b85b2fa3..e916a50883 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -65,10 +65,13 @@ uint8_t *readbuff = NULL; * ISO 10589 - 8.4.8 */ -uint8_t ALL_L1_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x14}; -uint8_t ALL_L2_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x15}; -uint8_t ALL_ISS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x05}; -uint8_t ALL_ESS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x04}; +static const uint8_t ALL_L1_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x14}; +static const uint8_t ALL_L2_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x15}; +#if 0 +/* missing support for P2P-over-LAN / ES-IS on BSD */ +static const uint8_t ALL_ISS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x05}; +static const uint8_t ALL_ESS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x04}; +#endif static char sock_buff[8192]; diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index 88676dd990..9202ed5a88 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -50,12 +50,12 @@ extern struct isis *isis; -static const char *csm_statestr[] = {"C_STATE_NA", "C_STATE_INIT", +static const char *const csm_statestr[] = {"C_STATE_NA", "C_STATE_INIT", "C_STATE_CONF", "C_STATE_UP"}; #define STATE2STR(S) csm_statestr[S] -static const char *csm_eventstr[] = { +static const char *const csm_eventstr[] = { "NO_STATE", "ISIS_ENABLE", "IF_UP_FROM_Z", "ISIS_DISABLE", "IF_DOWN_FROM_Z", }; diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index 7d3dfcb01e..ea16f4af7f 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -54,10 +54,13 @@ static t_uscalar_t dlpi_ctl[1024]; /* DLPI control messages */ * ISO 10589 - 8.4.8 */ -uint8_t ALL_L1_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x14}; -uint8_t ALL_L2_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x15}; -uint8_t ALL_ISS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x05}; -uint8_t ALL_ESS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x04}; +static const uint8_t ALL_L1_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x14}; +static const uint8_t ALL_L2_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x15}; +static const uint8_t ALL_ISS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x05}; +#if 0 +/* missing support for ES-IS on Solaris */ +static const uint8_t ALL_ESS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x04}; +#endif static uint8_t sock_buff[8192]; diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 2ef0065180..7e79fdea15 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -162,7 +162,7 @@ struct quagga_signal_t isisd_signals[] = { }; -static const struct frr_yang_module_info *isisd_yang_modules[] = { +static const struct frr_yang_module_info *const isisd_yang_modules[] = { &frr_interface_info, #ifndef FABRICD &frr_isisd_info, diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 69ac3fc555..28a1488c32 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -45,7 +45,7 @@ #include "privs.h" /* tcpdump -i eth0 'isis' -dd */ -static struct sock_filter isisfilter[] = { +static const struct sock_filter isisfilter[] = { /* NB: we're in SOCK_DGRAM, so src/dst mac + length are stripped * off! * (OTOH it's a bit more lower-layer agnostic and might work @@ -57,9 +57,9 @@ static struct sock_filter isisfilter[] = { {0x6, 0, 0, 0x00040000}, {0x6, 0, 0, 0x00000000}, }; -static struct sock_fprog bpf = { +static const struct sock_fprog bpf = { .len = array_size(isisfilter), - .filter = isisfilter, + .filter = (struct sock_filter *)isisfilter, }; /* @@ -67,10 +67,10 @@ static struct sock_fprog bpf = { * ISO 10589 - 8.4.8 */ -uint8_t ALL_L1_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x14}; -uint8_t ALL_L2_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x15}; -uint8_t ALL_ISS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x05}; -uint8_t ALL_ESS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x04}; +static const uint8_t ALL_L1_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x14}; +static const uint8_t ALL_L2_ISS[6] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x15}; +static const uint8_t ALL_ISS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x05}; +static const uint8_t ALL_ESS[6] = {0x09, 0x00, 0x2B, 0x00, 0x00, 0x04}; static uint8_t discard_buff[8192]; diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index eb9b661d37..902528e1bb 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -74,9 +74,12 @@ static void route_match_ip_address_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_address_cmd = { - "ip address", route_match_ip_address, route_match_ip_address_compile, - route_match_ip_address_free}; +static const struct route_map_rule_cmd route_match_ip_address_cmd = { + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; /* ------------------------------------------------------------*/ @@ -106,10 +109,13 @@ static void route_match_ip_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { - "ip address prefix-list", route_match_ip_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_address_prefix_list_cmd = { + "ip address prefix-list", + route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, - route_match_ip_address_prefix_list_free}; + route_match_ip_address_prefix_list_free +}; /* ------------------------------------------------------------*/ @@ -139,9 +145,12 @@ static void route_match_ipv6_address_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ipv6_address_cmd = { - "ipv6 address", route_match_ipv6_address, - route_match_ipv6_address_compile, route_match_ipv6_address_free}; +static const struct route_map_rule_cmd route_match_ipv6_address_cmd = { + "ipv6 address", + route_match_ipv6_address, + route_match_ipv6_address_compile, + route_match_ipv6_address_free +}; /* ------------------------------------------------------------*/ @@ -171,10 +180,13 @@ static void route_match_ipv6_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { - "ipv6 address prefix-list", route_match_ipv6_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ipv6_address_prefix_list_cmd = { + "ipv6 address prefix-list", + route_match_ipv6_address_prefix_list, route_match_ipv6_address_prefix_list_compile, - route_match_ipv6_address_prefix_list_free}; + route_match_ipv6_address_prefix_list_free +}; /* ------------------------------------------------------------*/ @@ -215,9 +227,12 @@ static void route_set_metric_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_set_metric_cmd = { - "metric", route_set_metric, route_set_metric_compile, - route_set_metric_free}; +static const struct route_map_rule_cmd route_set_metric_cmd = { + "metric", + route_set_metric, + route_set_metric_compile, + route_set_metric_free +}; void isis_route_map_init(void) { diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 9871d2bcb9..133707d61d 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -60,8 +60,6 @@ #include "isisd/isis_te.h" #include "isisd/isis_zebra.h" -const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"}; - /*------------------------------------------------------------------------* * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 442442152c..df6280e5c3 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -88,7 +88,7 @@ struct pack_order_entry { .what_to_pack = offsetof(struct isis_tlvs, w), \ } -static struct pack_order_entry pack_order[] = { +static const struct pack_order_entry pack_order[] = { PACK_ENTRY(OLDSTYLE_REACH, ISIS_ITEMS, oldstyle_reach), PACK_ENTRY(LAN_NEIGHBORS, ISIS_ITEMS, lan_neighbor), PACK_ENTRY(LSP_ENTRY, ISIS_ITEMS, lsp_entries), @@ -106,7 +106,7 @@ static struct pack_order_entry pack_order[] = { /* This is a forward definition. The table is actually initialized * in at the bottom. */ -static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX]; +static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX]; /* End of _ops forward definition. */ @@ -1003,7 +1003,7 @@ static void free_items(enum isis_tlv_context context, enum isis_tlv_type type, static int pack_items_(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items, struct stream *s, struct isis_tlvs **fragment_tlvs, - struct pack_order_entry *pe, + const struct pack_order_entry *pe, struct isis_tlvs *(*new_fragment)(struct list *l), struct list *new_fragment_arg); #define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__) @@ -3095,7 +3095,7 @@ static void free_items(enum isis_tlv_context context, enum isis_tlv_type type, static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item *i, struct stream *s, struct isis_tlvs **fragment_tlvs, - struct pack_order_entry *pe, uint16_t mtid) + const struct pack_order_entry *pe, uint16_t mtid) { const struct tlv_ops *ops = tlv_table[context][type]; @@ -3107,7 +3107,8 @@ static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type, return 1; } -static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *pe, +static void add_item_to_fragment(struct isis_item *i, + const struct pack_order_entry *pe, struct isis_tlvs *fragment_tlvs, uint16_t mtid) { struct isis_item_list *l; @@ -3126,7 +3127,7 @@ static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *p static int pack_items_(uint16_t mtid, enum isis_tlv_context context, enum isis_tlv_type type, struct isis_item_list *items, struct stream *s, struct isis_tlvs **fragment_tlvs, - struct pack_order_entry *pe, + const struct pack_order_entry *pe, struct isis_tlvs *(*new_fragment)(struct list *l), struct list *new_fragment_arg) { @@ -3401,7 +3402,7 @@ static void format_mt_items(enum isis_tlv_context context, static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type, struct isis_mt_item_list *m, struct stream *s, struct isis_tlvs **fragment_tlvs, - struct pack_order_entry *pe, + const struct pack_order_entry *pe, struct isis_tlvs *(*new_fragment)(struct list *l), struct list *new_fragment_arg) { @@ -3734,7 +3735,7 @@ static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp) } } -static int handle_pack_entry(struct pack_order_entry *pe, +static int handle_pack_entry(const struct pack_order_entry *pe, struct isis_tlvs *tlvs, struct stream *stream, struct isis_tlvs **fragment_tlvs, struct isis_tlvs *(*new_fragment)(struct list *l), @@ -4079,7 +4080,7 @@ TLV_OPS(router_cap, "TLV 242 Router Capability"); ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID"); SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix"); -static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { +static const struct tlv_ops *const tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { [ISIS_CONTEXT_LSP] = { [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops, [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops, diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index a6f0519bd7..dcbcf8ce50 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -120,7 +120,7 @@ char ctl_sock_path[MAXPATHLEN]; /* LDPd options. */ #define OPTION_CTLSOCK 1001 -static struct option longopts[] = +static const struct option longopts[] = { { "ctl_socket", required_argument, NULL, OPTION_CTLSOCK}, { "instance", required_argument, NULL, 'n'}, @@ -177,7 +177,7 @@ static struct quagga_signal_t ldp_signals[] = } }; -static const struct frr_yang_module_info *ldpd_yang_modules[] = { +static const struct frr_yang_module_info *const ldpd_yang_modules[] = { }; FRR_DAEMON_INFO(ldpd, LDP, diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index 78a6131ca4..ae51490c07 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -49,7 +49,7 @@ RB_GENERATE(nbr_addr_head, nbr, addr_tree, nbr_addr_compare) RB_GENERATE(nbr_pid_head, nbr, pid_tree, nbr_pid_compare) RB_GENERATE(nbrp_head, nbr_params, entry, nbr_params_compare) -struct { +const struct { int state; enum nbr_event event; enum nbr_action action; diff --git a/lib/command.c b/lib/command.c index 59668e95fc..9238ae412a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -74,7 +74,7 @@ const struct message tokennames[] = { {0}, }; -const char *node_names[] = { +const char *const node_names[] = { "auth", // AUTH_NODE, "view", // VIEW_NODE, "auth enable", // AUTH_ENABLE_NODE, @@ -370,7 +370,7 @@ const char *cmd_prompt(enum node_type node) } /* Install a command into a node. */ -void install_element(enum node_type ntype, struct cmd_element *cmd) +void install_element(enum node_type ntype, const struct cmd_element *cmd) { struct cmd_node *cnode; @@ -392,7 +392,7 @@ void install_element(enum node_type ntype, struct cmd_element *cmd) exit(EXIT_FAILURE); } - if (hash_lookup(cnode->cmd_hash, cmd) != NULL) { + if (hash_lookup(cnode->cmd_hash, (void *)cmd) != NULL) { fprintf(stderr, "%s[%s]:\n" "\tnode %d (%s) already has this command installed.\n" @@ -401,7 +401,7 @@ void install_element(enum node_type ntype, struct cmd_element *cmd) return; } - assert(hash_get(cnode->cmd_hash, cmd, hash_alloc_intern)); + assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern)); struct graph *graph = graph_new(); struct cmd_token *token = @@ -413,13 +413,13 @@ void install_element(enum node_type ntype, struct cmd_element *cmd) cmd_graph_merge(cnode->cmdgraph, graph, +1); graph_delete_graph(graph); - vector_set(cnode->cmd_vector, cmd); + vector_set(cnode->cmd_vector, (void *)cmd); if (ntype == VIEW_NODE) install_element(ENABLE_NODE, cmd); } -void uninstall_element(enum node_type ntype, struct cmd_element *cmd) +void uninstall_element(enum node_type ntype, const struct cmd_element *cmd) { struct cmd_node *cnode; @@ -441,7 +441,7 @@ void uninstall_element(enum node_type ntype, struct cmd_element *cmd) exit(EXIT_FAILURE); } - if (hash_release(cnode->cmd_hash, cmd) == NULL) { + if (hash_release(cnode->cmd_hash, (void *)cmd) == NULL) { fprintf(stderr, "%s[%s]:\n" "\tnode %d (%s) does not have this command installed.\n" @@ -450,7 +450,7 @@ void uninstall_element(enum node_type ntype, struct cmd_element *cmd) return; } - vector_unset_value(cnode->cmd_vector, cmd); + vector_unset_value(cnode->cmd_vector, (void *)cmd); struct graph *graph = graph_new(); struct cmd_token *token = @@ -1660,7 +1660,7 @@ int cmd_list_cmds(struct vty *vty, int do_permute) permute(vector_slot(node->cmdgraph->nodes, 0), vty); else { /* loop over all commands at this node */ - struct cmd_element *element = NULL; + const struct cmd_element *element = NULL; for (unsigned int i = 0; i < vector_active(node->cmd_vector); i++) if ((element = vector_slot(node->cmd_vector, i)) diff --git a/lib/command.h b/lib/command.h index 68ac86f769..c8dd04604d 100644 --- a/lib/command.h +++ b/lib/command.h @@ -165,7 +165,7 @@ enum node_type { extern vector cmdvec; extern const struct message tokennames[]; -extern const char *node_names[]; +extern const char *const node_names[]; /* Node which has some commands and prompt string and configuration function pointer . */ @@ -217,7 +217,7 @@ struct cmd_node { /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ - static struct cmd_element cmdname = { \ + static const struct cmd_element cmdname = { \ .string = cmdstr, \ .func = funcname, \ .doc = helpstr, \ @@ -421,11 +421,11 @@ struct cmd_node { /* Prototypes. */ extern void install_node(struct cmd_node *, int (*)(struct vty *)); extern void install_default(enum node_type); -extern void install_element(enum node_type, struct cmd_element *); +extern void install_element(enum node_type, const struct cmd_element *); /* known issue with uninstall_element: changes to cmd_token->attr (i.e. * deprecated/hidden) are not reversed. */ -extern void uninstall_element(enum node_type, struct cmd_element *); +extern void uninstall_element(enum node_type, const struct cmd_element *); /* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated string with a space between each element (allocated using diff --git a/lib/command_graph.h b/lib/command_graph.h index 903d515834..1efe8b1803 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -116,7 +116,7 @@ extern struct cmd_token *cmd_token_dup(struct cmd_token *); extern void cmd_token_del(struct cmd_token *); extern void cmd_token_varname_set(struct cmd_token *token, const char *varname); -extern void cmd_graph_parse(struct graph *graph, struct cmd_element *cmd); +extern void cmd_graph_parse(struct graph *graph, const struct cmd_element *cmd); extern void cmd_graph_names(struct graph *graph); extern void cmd_graph_merge(struct graph *old, struct graph *n, int direction); diff --git a/lib/command_parse.y b/lib/command_parse.y index 062a4bb30c..5dc19d2c9b 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -84,7 +84,7 @@ struct parser_ctx { yyscan_t scanner; - struct cmd_element *el; + const struct cmd_element *el; struct graph *graph; struct graph_node *currnode; @@ -379,7 +379,7 @@ selector: '[' selector_seq_seq ']' varname_token DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)") void -cmd_graph_parse (struct graph *graph, struct cmd_element *cmd) +cmd_graph_parse (struct graph *graph, const struct cmd_element *cmd) { struct parser_ctx ctx = { .graph = graph, .el = cmd }; @@ -485,11 +485,11 @@ terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx, { // end of graph should look like this // * -> finalnode -> END_TKN -> cmd_element - struct cmd_element *element = ctx->el; + const struct cmd_element *element = ctx->el; struct graph_node *end_token_node = new_token_node (ctx, END_TKN, CMD_CR_TEXT, ""); struct graph_node *end_element_node = - graph_new_node (ctx->graph, element, NULL); + graph_new_node (ctx->graph, (void *)element, NULL); if (ctx->docstr && strlen (ctx->docstr) > 1) { zlog_debug ("Excessive docstring while parsing '%s'", ctx->el->string); diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 5c71fac10a..55f0b55ed6 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -39,7 +39,7 @@ static int fpt_halt(struct frr_pthread *fpt, void **res); static void frr_pthread_destroy_nolock(struct frr_pthread *fpt); /* default frr_pthread attributes */ -struct frr_pthread_attr frr_pthread_attr_default = { +const struct frr_pthread_attr frr_pthread_attr_default = { .start = fpt_run, .stop = fpt_halt, }; @@ -74,7 +74,7 @@ void frr_pthread_finish(void) } } -struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr, +struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr, const char *name, const char *os_name) { struct frr_pthread *fpt = NULL; diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index f70c8a0db4..89519abae0 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -99,7 +99,7 @@ struct frr_pthread { char os_name[OS_THREAD_NAMELEN]; }; -extern struct frr_pthread_attr frr_pthread_attr_default; +extern const struct frr_pthread_attr frr_pthread_attr_default; /* * Initializes this module. @@ -133,7 +133,7 @@ void frr_pthread_finish(void); * @param os_name - 16 characters (including '\0') thread name to set in os, * @return the created frr_pthread upon success, or NULL upon failure */ -struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr, +struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr, const char *name, const char *os_name); /* @@ -1650,7 +1650,32 @@ static int lib_interface_description_destroy(enum nb_event event, } /* clang-format off */ + +#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__) +/* gcc versions before 5.x miscalculate the size for structs with variable + * length arrays (they just count it as size 0) + */ +struct frr_yang_module_info_size3 { + /* YANG module name. */ + const char *name; + + /* Northbound callbacks. */ + const struct { + /* Data path of this YANG node. */ + const char *xpath; + + /* Callbacks implemented for this node. */ + struct nb_callbacks cbs; + + /* Priority - lower priorities are processed first. */ + uint32_t priority; + } nodes[3]; +}; + +const struct frr_yang_module_info_size3 frr_interface_info_size3 asm("frr_interface_info") = { +#else const struct frr_yang_module_info frr_interface_info = { +#endif .name = "frr-interface", .nodes = { { diff --git a/lib/libfrr.h b/lib/libfrr.h index e2b3db74a3..f964c9e2a1 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -98,7 +98,7 @@ struct frr_daemon_info { struct zebra_privs_t *privs; - const struct frr_yang_module_info **yang_modules; + const struct frr_yang_module_info *const *yang_modules; size_t n_yang_modules; bool log_always; diff --git a/lib/mlag.c b/lib/mlag.c index acdc662924..1daf290725 100644 --- a/lib/mlag.c +++ b/lib/mlag.c @@ -39,3 +39,129 @@ char *mlag_role2str(enum mlag_role role, char *buf, size_t size) return buf; } + +char *mlag_lib_msgid_to_str(enum mlag_msg_type msg_type, char *buf, size_t size) +{ + switch (msg_type) { + case MLAG_REGISTER: + snprintf(buf, size, "Register"); + break; + case MLAG_DEREGISTER: + snprintf(buf, size, "De-Register"); + break; + case MLAG_MROUTE_ADD: + snprintf(buf, size, "Mroute add"); + break; + case MLAG_MROUTE_DEL: + snprintf(buf, size, "Mroute del"); + break; + case MLAG_DUMP: + snprintf(buf, size, "Mlag Replay"); + break; + case MLAG_MROUTE_ADD_BULK: + snprintf(buf, size, "Mroute Add Batch"); + break; + case MLAG_MROUTE_DEL_BULK: + snprintf(buf, size, "Mroute Del Batch"); + break; + case MLAG_STATUS_UPDATE: + snprintf(buf, size, "Mlag Status"); + break; + case MLAG_VXLAN_UPDATE: + snprintf(buf, size, "Mlag vxlan update"); + break; + case MLAG_PEER_FRR_STATUS: + snprintf(buf, size, "Mlag Peer FRR Status"); + break; + default: + snprintf(buf, size, "Unknown %d", msg_type); + break; + } + return buf; +} + + +int mlag_lib_decode_mlag_hdr(struct stream *s, struct mlag_msg *msg) +{ + if (s == NULL || msg == NULL) + return -1; + + STREAM_GETL(s, msg->msg_type); + STREAM_GETW(s, msg->data_len); + STREAM_GETW(s, msg->msg_cnt); + return 0; +stream_failure: + return -1; +} + +int mlag_lib_decode_mroute_add(struct stream *s, struct mlag_mroute_add *msg) +{ + if (s == NULL || msg == NULL) + return -1; + + STREAM_GET(msg->vrf_name, s, VRF_NAMSIZ); + STREAM_GETL(s, msg->source_ip); + STREAM_GETL(s, msg->group_ip); + STREAM_GETL(s, msg->cost_to_rp); + STREAM_GETL(s, msg->owner_id); + STREAM_GETC(s, msg->am_i_dr); + STREAM_GETC(s, msg->am_i_dual_active); + STREAM_GETL(s, msg->vrf_id); + STREAM_GET(msg->intf_name, s, INTERFACE_NAMSIZ); + return 0; +stream_failure: + return -1; +} + +int mlag_lib_decode_mroute_del(struct stream *s, struct mlag_mroute_del *msg) +{ + if (s == NULL || msg == NULL) + return -1; + + STREAM_GET(msg->vrf_name, s, VRF_NAMSIZ); + STREAM_GETL(s, msg->source_ip); + STREAM_GETL(s, msg->group_ip); + STREAM_GETL(s, msg->owner_id); + STREAM_GETL(s, msg->vrf_id); + STREAM_GET(msg->intf_name, s, INTERFACE_NAMSIZ); + return 0; +stream_failure: + return -1; +} + +int mlag_lib_decode_mlag_status(struct stream *s, struct mlag_status *msg) +{ + if (s == NULL || msg == NULL) + return -1; + + STREAM_GET(msg->peerlink_rif, s, INTERFACE_NAMSIZ); + STREAM_GETL(s, msg->my_role); + STREAM_GETL(s, msg->peer_state); + return 0; +stream_failure: + return -1; +} + +int mlag_lib_decode_vxlan_update(struct stream *s, struct mlag_vxlan *msg) +{ + if (s == NULL || msg == NULL) + return -1; + + STREAM_GETL(s, msg->anycast_ip); + STREAM_GETL(s, msg->local_ip); + return 0; + +stream_failure: + return -1; +} + +int mlag_lib_decode_frr_status(struct stream *s, struct mlag_frr_status *msg) +{ + if (s == NULL || msg == NULL) + return -1; + + STREAM_GETL(s, msg->frr_state); + return 0; +stream_failure: + return -1; +} diff --git a/lib/mlag.h b/lib/mlag.h index 2b904d44f4..c531fb5b68 100644 --- a/lib/mlag.h +++ b/lib/mlag.h @@ -26,14 +26,116 @@ extern "C" { #endif +#include "lib/if.h" +#include "lib/vrf.h" +#include "lib/stream.h" + +#define MLAG_MSG_NULL_PAYLOAD 0 +#define MLAG_MSG_NO_BATCH 1 +#define MLAG_BUF_LIMIT 2048 + enum mlag_role { MLAG_ROLE_NONE, MLAG_ROLE_PRIMARY, MLAG_ROLE_SECONDARY }; -extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size); +enum mlag_state { + MLAG_STATE_DOWN, + MLAG_STATE_RUNNING, +}; + +enum mlag_frr_state { + MLAG_FRR_STATE_NONE, + MLAG_FRR_STATE_DOWN, + MLAG_FRR_STATE_UP, +}; + +enum mlag_owner { + MLAG_OWNER_NONE, + MLAG_OWNER_INTERFACE, + MLAG_OWNER_VXLAN, +}; + +/* + * This message definition should match mlag.proto + * Because message registration is based on this + */ +enum mlag_msg_type { + MLAG_MSG_NONE = 0, + MLAG_REGISTER = 1, + MLAG_DEREGISTER = 2, + MLAG_STATUS_UPDATE = 3, + MLAG_MROUTE_ADD = 4, + MLAG_MROUTE_DEL = 5, + MLAG_DUMP = 6, + MLAG_MROUTE_ADD_BULK = 7, + MLAG_MROUTE_DEL_BULK = 8, + MLAG_PIM_CFG_DUMP = 10, + MLAG_VXLAN_UPDATE = 11, + MLAG_PEER_FRR_STATUS = 12, +}; + +struct mlag_frr_status { + enum mlag_frr_state frr_state; +}; +struct mlag_status { + char peerlink_rif[INTERFACE_NAMSIZ]; + enum mlag_role my_role; + enum mlag_state peer_state; +}; + +#define MLAG_ROLE_STRSIZE 16 + +struct mlag_vxlan { + uint32_t anycast_ip; + uint32_t local_ip; +}; + +struct mlag_mroute_add { + char vrf_name[VRF_NAMSIZ]; + uint32_t source_ip; + uint32_t group_ip; + uint32_t cost_to_rp; + enum mlag_owner owner_id; + bool am_i_dr; + bool am_i_dual_active; + vrf_id_t vrf_id; + char intf_name[INTERFACE_NAMSIZ]; +}; + +struct mlag_mroute_del { + char vrf_name[VRF_NAMSIZ]; + uint32_t source_ip; + uint32_t group_ip; + enum mlag_owner owner_id; + vrf_id_t vrf_id; + char intf_name[INTERFACE_NAMSIZ]; +}; + +struct mlag_msg { + enum mlag_msg_type msg_type; + uint16_t data_len; + uint16_t msg_cnt; + uint8_t data[0]; +} __attribute__((packed)); + + +extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size); +extern char *mlag_lib_msgid_to_str(enum mlag_msg_type msg_type, char *buf, + size_t size); +extern int mlag_lib_decode_mlag_hdr(struct stream *s, struct mlag_msg *msg); +extern int mlag_lib_decode_mroute_add(struct stream *s, + struct mlag_mroute_add *msg); +extern int mlag_lib_decode_mroute_del(struct stream *s, + struct mlag_mroute_del *msg); +extern int mlag_lib_decode_mlag_status(struct stream *s, + struct mlag_status *msg); +extern int mlag_lib_decode_vxlan_update(struct stream *s, + struct mlag_vxlan *msg); +extern int mlag_lib_decode_frr_status(struct stream *s, + struct mlag_frr_status *msg); #ifdef __cplusplus } #endif diff --git a/lib/nexthop.c b/lib/nexthop.c index 655a596f50..f314fea697 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -201,7 +201,7 @@ int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2) */ const char *nexthop_type_to_str(enum nexthop_types_t nh_type) { - static const char *desc[] = { + static const char *const desc[] = { "none", "Directly connected", "IPv4 nexthop", "IPv4 nexthop with ifindex", "IPv6 nexthop", "IPv6 nexthop with ifindex", diff --git a/lib/northbound.c b/lib/northbound.c index debd463624..206a88d980 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -1882,7 +1882,8 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module) } void nb_init(struct thread_master *tm, - const struct frr_yang_module_info *modules[], size_t nmodules) + const struct frr_yang_module_info *const modules[], + size_t nmodules) { unsigned int errors = 0; diff --git a/lib/northbound.h b/lib/northbound.h index f52fcc90cf..76a11e518c 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -1010,7 +1010,8 @@ extern const char *nb_client_name(enum nb_client client); * nmodules * Size of the modules array. */ -extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info *modules[], +extern void nb_init(struct thread_master *tm, + const struct frr_yang_module_info *const modules[], size_t nmodules); /* diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index d3e788d5d3..009e5bd824 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -432,12 +432,12 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults) lyd_schema_sort(config->dnode, 1); /* - * When "with-defaults" is used, call lyd_validate() only to create - * default child nodes, ignoring any possible validation error. This - * doesn't need to be done when displaying the running configuration - * since it's always fully validated. + * Call lyd_validate() only to create default child nodes, ignoring + * any possible validation error. This doesn't need to be done when + * displaying the running configuration since it's always fully + * validated. */ - if (with_defaults && config != running_config) + if (config != running_config) (void)lyd_validate(&config->dnode, LYD_OPT_CONFIG | LYD_OPT_WHENAUTODEL, ly_native_ctx); diff --git a/lib/printfrr.h b/lib/printfrr.h index 95dace7021..f9584bcacc 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -124,7 +124,7 @@ void printfrr_ext_reg(const struct printfrr_ext *); #define printfrr_ext_autoreg_p(matchs, print_fn) \ static ssize_t print_fn(char *, size_t, const char *, int, \ const void *); \ - static struct printfrr_ext _printext_##print_fn = { \ + static const struct printfrr_ext _printext_##print_fn = { \ .match = matchs, \ .print_ptr = print_fn, \ }; \ @@ -136,7 +136,7 @@ void printfrr_ext_reg(const struct printfrr_ext *); #define printfrr_ext_autoreg_i(matchs, print_fn) \ static ssize_t print_fn(char *, size_t, const char *, int, uintmax_t); \ - static struct printfrr_ext _printext_##print_fn = { \ + static const struct printfrr_ext _printext_##print_fn = { \ .match = matchs, \ .print_int = print_fn, \ }; \ diff --git a/lib/qobj.c b/lib/qobj.c index 3e3860a96a..1e48b541dc 100644 --- a/lib/qobj.c +++ b/lib/qobj.c @@ -48,7 +48,7 @@ static pthread_rwlock_t nodes_lock; static struct qobj_nodes_head nodes = { }; -void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type) +void qobj_reg(struct qobj_node *node, const struct qobj_nodetype *type) { node->type = type; pthread_rwlock_wrlock(&nodes_lock); @@ -76,7 +76,7 @@ struct qobj_node *qobj_get(uint64_t id) return rv; } -void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type) +void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type) { struct qobj_node dummy = {.nid = id}; struct qobj_node *node; diff --git a/lib/qobj.h b/lib/qobj.h index 415eae02ef..400ae0151c 100644 --- a/lib/qobj.h +++ b/lib/qobj.h @@ -89,7 +89,7 @@ PREDECL_HASH(qobj_nodes) struct qobj_node { uint64_t nid; struct qobj_nodes_item nodehash; - struct qobj_nodetype *type; + const struct qobj_nodetype *type; }; #define QOBJ_FIELDS struct qobj_node qobj_node; @@ -111,20 +111,20 @@ struct qobj_node { * * in the long this may need another touch, e.g. built-in per-object locking. */ -void qobj_reg(struct qobj_node *node, struct qobj_nodetype *type); +void qobj_reg(struct qobj_node *node, const struct qobj_nodetype *type); void qobj_unreg(struct qobj_node *node); struct qobj_node *qobj_get(uint64_t id); -void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type); +void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type); /* type declarations */ #define DECLARE_QOBJ_TYPE(structname) \ - extern struct qobj_nodetype qobj_t_##structname; + extern const struct qobj_nodetype qobj_t_##structname; #define DEFINE_QOBJ_TYPE(structname) \ - struct qobj_nodetype qobj_t_##structname = { \ + const struct qobj_nodetype qobj_t_##structname = { \ .node_member_offset = \ (ptrdiff_t)offsetof(struct structname, qobj_node)}; #define DEFINE_QOBJ_TYPE_INIT(structname, ...) \ - struct qobj_nodetype qobj_t_##structname = { \ + const struct qobj_nodetype qobj_t_##structname = { \ .node_member_offset = \ (ptrdiff_t)offsetof(struct structname, qobj_node), \ __VA_ARGS__}; diff --git a/lib/routemap.c b/lib/routemap.c index 580d898448..c0e01488b2 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -598,7 +598,7 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, /* Route map rule. This rule has both `match' rule and `set' rule. */ struct route_map_rule { /* Rule type. */ - struct route_map_rule_cmd *cmd; + const struct route_map_rule_cmd *cmd; /* For pretty printing. */ char *rule_str; @@ -1228,22 +1228,22 @@ static struct route_map_rule *route_map_rule_new(void) } /* Install rule command to the match list. */ -void route_map_install_match(struct route_map_rule_cmd *cmd) +void route_map_install_match(const struct route_map_rule_cmd *cmd) { - vector_set(route_match_vec, cmd); + vector_set(route_match_vec, (void *)cmd); } /* Install rule command to the set list. */ -void route_map_install_set(struct route_map_rule_cmd *cmd) +void route_map_install_set(const struct route_map_rule_cmd *cmd) { - vector_set(route_set_vec, cmd); + vector_set(route_set_vec, (void *)cmd); } /* Lookup rule command from match list. */ -static struct route_map_rule_cmd *route_map_lookup_match(const char *name) +static const struct route_map_rule_cmd *route_map_lookup_match(const char *name) { unsigned int i; - struct route_map_rule_cmd *rule; + const struct route_map_rule_cmd *rule; for (i = 0; i < vector_active(route_match_vec); i++) if ((rule = vector_slot(route_match_vec, i)) != NULL) @@ -1253,10 +1253,10 @@ static struct route_map_rule_cmd *route_map_lookup_match(const char *name) } /* Lookup rule command from set list. */ -static struct route_map_rule_cmd *route_map_lookup_set(const char *name) +static const struct route_map_rule_cmd *route_map_lookup_set(const char *name) { unsigned int i; - struct route_map_rule_cmd *rule; + const struct route_map_rule_cmd *rule; for (i = 0; i < vector_active(route_set_vec); i++) if ((rule = vector_slot(route_set_vec, i)) != NULL) @@ -1324,7 +1324,7 @@ const char *route_map_get_match_arg(struct route_map_index *index, const char *match_name) { struct route_map_rule *rule; - struct route_map_rule_cmd *cmd; + const struct route_map_rule_cmd *cmd; /* First lookup rule for add match statement. */ cmd = route_map_lookup_match(match_name); @@ -1396,7 +1396,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, { struct route_map_rule *rule; struct route_map_rule *next; - struct route_map_rule_cmd *cmd; + const struct route_map_rule_cmd *cmd; void *compile; int8_t delete_rmap_event_type = 0; const char *rule_key; @@ -1482,7 +1482,7 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index, route_map_event_t type) { struct route_map_rule *rule; - struct route_map_rule_cmd *cmd; + const struct route_map_rule_cmd *cmd; const char *rule_key; cmd = route_map_lookup_match(match_name); @@ -1523,7 +1523,7 @@ enum rmap_compile_rets route_map_add_set(struct route_map_index *index, { struct route_map_rule *rule; struct route_map_rule *next; - struct route_map_rule_cmd *cmd; + const struct route_map_rule_cmd *cmd; void *compile; cmd = route_map_lookup_set(set_name); @@ -1574,7 +1574,7 @@ enum rmap_compile_rets route_map_delete_set(struct route_map_index *index, const char *set_arg) { struct route_map_rule *rule; - struct route_map_rule_cmd *cmd; + const struct route_map_rule_cmd *cmd; cmd = route_map_lookup_set(set_name); if (cmd == NULL) diff --git a/lib/routemap.h b/lib/routemap.h index e6eccd4b29..1ffd0525ae 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -246,7 +246,7 @@ route_map_delete_set(struct route_map_index *index, const char *set_name, const char *set_arg); /* Install rule command to the match list. */ -extern void route_map_install_match(struct route_map_rule_cmd *cmd); +extern void route_map_install_match(const struct route_map_rule_cmd *cmd); /* * Install rule command to the set list. @@ -257,7 +257,7 @@ extern void route_map_install_match(struct route_map_rule_cmd *cmd); * in the apply command). See 'set metric' command * as it is handled in ripd/ripngd and ospfd. */ -extern void route_map_install_set(struct route_map_rule_cmd *cmd); +extern void route_map_install_set(const struct route_map_rule_cmd *cmd); /* Lookup route map by name. */ extern struct route_map *route_map_lookup_by_name(const char *name); diff --git a/lib/table.h b/lib/table.h index 7a69c1664f..7743d51681 100644 --- a/lib/table.h +++ b/lib/table.h @@ -45,7 +45,7 @@ struct route_table; * Function vector that can be used by a client to customize the * behavior of one or more route tables. */ -typedef struct route_table_delegate_t_ route_table_delegate_t; +typedef const struct route_table_delegate_t_ route_table_delegate_t; typedef struct route_node *(*route_table_create_node_func_t)( route_table_delegate_t *, struct route_table *); diff --git a/lib/termtable.c b/lib/termtable.c index b59c1118f8..b22a1ad387 100644 --- a/lib/termtable.c +++ b/lib/termtable.c @@ -27,7 +27,7 @@ DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table") /* clang-format off */ -struct ttable_style ttable_styles[] = { +const struct ttable_style ttable_styles[] = { { // default ascii .corner = '+', .rownums_on = false, @@ -99,7 +99,7 @@ void ttable_del(struct ttable *tt) XFREE(MTYPE_TTABLE, tt); } -struct ttable *ttable_new(struct ttable_style *style) +struct ttable *ttable_new(const struct ttable_style *style) { struct ttable *tt; diff --git a/lib/termtable.h b/lib/termtable.h index 4f7c595ce2..698cc73465 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -80,7 +80,7 @@ struct ttable { #define TTSTYLE_ASCII 0 #define TTSTYLE_BLANK 1 -extern struct ttable_style ttable_styles[2]; +extern const struct ttable_style ttable_styles[2]; /** * Creates a new table with the default style, which looks like this: @@ -95,7 +95,7 @@ extern struct ttable_style ttable_styles[2]; * * @return the created table */ -struct ttable *ttable_new(struct ttable_style *tts); +struct ttable *ttable_new(const struct ttable_style *tts); /** * Deletes a table and releases all associated resources. diff --git a/lib/thread.c b/lib/thread.c index 649fe500cd..651d26dfb2 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -66,7 +66,7 @@ DECLARE_HEAP(thread_timer_list, struct thread, timeritem, #define AWAKEN(m) \ do { \ - static unsigned char wakebyte = 0x01; \ + const unsigned char wakebyte = 0x01; \ write(m->io_pipe[1], &wakebyte, 1); \ } while (0); diff --git a/lib/zclient.c b/lib/zclient.c index a135d18744..7a62e408ea 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2721,6 +2721,57 @@ stream_failure: return; } +void zclient_send_mlag_register(struct zclient *client, uint32_t bit_map) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_MLAG_CLIENT_REGISTER, VRF_DEFAULT); + stream_putl(s, bit_map); + + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(client); +} + +void zclient_send_mlag_deregister(struct zclient *client) +{ + zebra_message_send(client, ZEBRA_MLAG_CLIENT_UNREGISTER, VRF_DEFAULT); +} + +void zclient_send_mlag_data(struct zclient *client, struct stream *client_s) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT); + stream_put(s, client_s->data, client_s->endp); + + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(client); +} + +static void zclient_mlag_process_up(ZAPI_CALLBACK_ARGS) +{ + if (zclient->mlag_process_up) + (*zclient->mlag_process_up)(); +} + +static void zclient_mlag_process_down(ZAPI_CALLBACK_ARGS) +{ + if (zclient->mlag_process_down) + (*zclient->mlag_process_down)(); +} + +static void zclient_mlag_handle_msg(ZAPI_CALLBACK_ARGS) +{ + if (zclient->mlag_handle_msg) + (*zclient->mlag_handle_msg)(zclient->ibuf, length); +} + /* Zebra client message read function. */ static int zclient_read(struct thread *thread) { @@ -3015,6 +3066,15 @@ static int zclient_read(struct thread *thread) (*zclient->vxlan_sg_del)(command, zclient, length, vrf_id); break; + case ZEBRA_MLAG_PROCESS_UP: + zclient_mlag_process_up(command, zclient, length, vrf_id); + break; + case ZEBRA_MLAG_PROCESS_DOWN: + zclient_mlag_process_down(command, zclient, length, vrf_id); + break; + case ZEBRA_MLAG_FORWARD_MSG: + zclient_mlag_handle_msg(command, zclient, length, vrf_id); + break; default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index 2131d4d47a..7adb294a31 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -178,6 +178,11 @@ typedef enum { ZEBRA_VXLAN_SG_ADD, ZEBRA_VXLAN_SG_DEL, ZEBRA_VXLAN_SG_REPLAY, + ZEBRA_MLAG_PROCESS_UP, + ZEBRA_MLAG_PROCESS_DOWN, + ZEBRA_MLAG_CLIENT_REGISTER, + ZEBRA_MLAG_CLIENT_UNREGISTER, + ZEBRA_MLAG_FORWARD_MSG, } zebra_message_types_t; struct redist_proto { @@ -272,6 +277,9 @@ struct zclient { int (*iptable_notify_owner)(ZAPI_CALLBACK_ARGS); int (*vxlan_sg_add)(ZAPI_CALLBACK_ARGS); int (*vxlan_sg_del)(ZAPI_CALLBACK_ARGS); + int (*mlag_process_up)(void); + int (*mlag_process_down)(void); + int (*mlag_handle_msg)(struct stream *msg, int len); }; /* Zebra API message flag. */ @@ -482,6 +490,7 @@ enum zapi_iptable_notify_owner { #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ #define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */ #define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */ +#define ZEBRA_MACIP_TYPE_SVI_IP 0x10 /* SVI MAC-IP */ enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; @@ -694,5 +703,11 @@ static inline void zapi_route_set_blackhole(struct zapi_route *api, SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP); }; +extern void zclient_send_mlag_register(struct zclient *client, + uint32_t bit_map); +extern void zclient_send_mlag_deregister(struct zclient *client); + +extern void zclient_send_mlag_data(struct zclient *client, + struct stream *client_s); #endif /* _ZEBRA_ZCLIENT_H */ diff --git a/mlag/mlag.proto b/mlag/mlag.proto new file mode 100644 index 0000000000..1e302151f8 --- /dev/null +++ b/mlag/mlag.proto @@ -0,0 +1,186 @@ +// See README.txt for information and build instructions. +// +// Note: START and END tags are used in comments to define sections used in +// tutorials. They are not part of the syntax for Protocol Buffers. +// +// To get an in-depth walkthrough of this file and the related examples, see: +// https://developers.google.com/protocol-buffers/docs/tutorials + +// [START declaration] +syntax = "proto3"; +//package tutorial; + +/* + * This Contains the Message structures used for PIM MLAG Active-Active support. + * Mainly there were two types of messages + * + * 1. Messages sent from PIM (Node-1) to PIM (Node-2) + * 2. Messages sent from CLAG to PIM (status Messages) + * + * ProtoBuf supports maximum 32 fields, so to make it more generic message + * encoding is like below. + * __________________________________________ + * | | | + * | Header | bytes | + * ___________________________________________ + * + * + * Header carries Information about + * 1) what Message it is carrying + * 2) Bytes carries the actual payload encoded with protobuf + * + * + * Limitations + *============= + * Since message-type is 32-bit, there were no real limitations on number of + * messages Infra can support, but each message can carry only 32 fields. + * + */ + + +// [START messages] +message ZebraMlag_Header { + enum MessageType { + ZEBRA_MLAG_NONE = 0; //Invalid message-type + ZEBRA_MLAG_REGISTER = 1; + ZEBRA_MLAG_DEREGISTER = 2; + ZEBRA_MLAG_STATUS_UPDATE = 3; + ZEBRA_MLAG_MROUTE_ADD = 4; + ZEBRA_MLAG_MROUTE_DEL = 5; + ZEBRA_MLAG_DUMP = 6; + ZEBRA_MLAG_MROUTE_ADD_BULK = 7; + ZEBRA_MLAG_MROUTE_DEL_BULK = 8; + ZEBRA_MLAG_PIM_CFG_DUMP = 10; + ZEBRA_MLAG_VXLAN_UPDATE = 11; + ZEBRA_MLAG_ZEBRA_STATUS_UPDATE = 12; + } + + /* + * tells what type of message this payload carries + */ + MessageType type = 1; + + /* + * Length of payload + */ + uint32 len = 2; + + /* + * Actual Encoded payload + */ + bytes data = 3; +} + + +/* + * ZEBRA_MLAG_REGISTER & ZEBRA_MLAG_DEREGISTER + * + * After the MLAGD is up, First Zebra has to register to send any data, + * otherwise MLAGD will not accept any data from the client. + * De-register will be used for the Data cleanup at MLAGD + * These are NULL payload message currently + */ + +/* + * ZEBRA_MLAG_STATUS_UPDATE + * + * This message will be posted by CLAGD(an external control plane manager + * which monitors CLAG failures) to inform peerlink/CLAG Failure + * to zebra, after the failure Notification Node with primary role will + * forward the Traffic and Node with standby will drop the traffic + */ + +message ZebraMlagStatusUpdate { + enum ClagState { + CLAG_STATE_DOWN = 0; + CLAG_STATE_RUNNING = 1; + } + + enum ClagRole { + CLAG_ROLE_NONE = 0; + CLAG_ROLE_PRIMAY = 1; + CLAG_ROLE_SECONDARY = 2; + } + + string peerlink = 1; + ClagRole my_role = 2; + ClagState peer_state = 3; +} + +/* + * ZEBRA_MLAG_VXLAN_UPDATE + * + * This message will be posted by CLAGD(an external control plane Manager + * which is responsible for MCLAG) to inform zebra obout anycast/local + * ip updates. + */ +message ZebraMlagVxlanUpdate { + uint32 anycast_ip = 1; + uint32 local_ip = 2; +} + +/* + * ZebraMlagZebraStatusUpdate + * + * This message will be posted by CLAGD to advertise FRR state + * Change Information to peer + */ + +message ZebraMlagZebraStatusUpdate{ + enum FrrState { + FRR_STATE_NONE = 0; + FRR_STATE_DOWN = 1; + FRR_STATE_UP = 2; + } + + FrrState peer_frrstate = 1; +} + +/* + * ZEBRA_MLAG_MROUTE_ADD & ZEBRA_MLAG_MROUTE_DEL + * + * These messages will be sent from PIM (Node-1) to PIM (Node-2) to perform + * DF Election for each Mcast flow. Elected DF will forward the traffic + * towards the host and loser will keep the OIL as empty, so that only single + * copy will be sent to host + * This message will be posted with any change in the params. + * + * ZEBRA_MLAG_MROUTE_DEL is mainly to delete the record at MLAGD when the + * mcast flow is deleted. + * key for the MLAGD lookup is (vrf_id, source_ip & group_ip) + */ + +message ZebraMlagMrouteAdd { + string vrf_name = 1; + uint32 source_ip = 2; + uint32 group_ip = 3; + /* + * This is the IGP Cost to reach Configured RP in case of (*,G) or + * Cost to the source in case of (S,G) entry + */ + uint32 cost_to_rp = 4; + uint32 owner_id = 5; + bool am_i_DR = 6; + bool am_i_Dual_active = 7; + uint32 vrf_id = 8; + string intf_name = 9; +} + +message ZebraMlagMrouteDel { + string vrf_name = 1; + uint32 source_ip = 2; + uint32 group_ip = 3; + uint32 owner_id = 4; + uint32 vrf_id = 5; + string intf_name = 6; +} + +message ZebraMlagMrouteAddBulk { + repeated ZebraMlagMrouteAdd mroute_add = 1; +} + +message ZebraMlagMrouteDelBulk { + repeated ZebraMlagMrouteDel mroute_del = 1; +} + +// [END messages] diff --git a/mlag/subdir.am b/mlag/subdir.am new file mode 100644 index 0000000000..9fab662860 --- /dev/null +++ b/mlag/subdir.am @@ -0,0 +1,19 @@ +if HAVE_PROTOBUF +lib_LTLIBRARIES += mlag/libmlag_pb.la +endif + +mlag_libmlag_pb_la_LDFLAGS = -version-info 0:0:0 +mlag_libmlag_pb_la_CPPFLAGS = $(AM_CPPFLAGS) $(PROTOBUF_C_CFLAGS) +mlag_libmlag_pb_la_SOURCES = \ + # end + +nodist_mlag_libmlag_pb_la_SOURCES = \ + mlag/mlag.pb-c.c \ + # end + +CLEANFILES += \ + mlag/mlag.pb-c.c \ + mlag/mlag.pb-c.h \ + # end + +EXTRA_DIST += mlag/mlag.proto diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index c6c83614ef..a781122b16 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -116,7 +116,7 @@ static struct quagga_signal_t sighandlers[] = { }, }; -static const struct frr_yang_module_info *nhrpd_yang_modules[] = { +static const struct frr_yang_module_info *const nhrpd_yang_modules[] = { &frr_interface_info, }; diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index ca309f2506..3a74b75696 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -657,7 +657,7 @@ enum packet_type_t { PACKET_INDICATION, }; -static struct { +static const struct { enum packet_type_t type; const char *name; void (*handler)(struct nhrp_packet_parser *); diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 0ce53143b8..ff82bb1798 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -1420,7 +1420,7 @@ void install_element_ospf6_debug_abr(void) install_element(CONFIG_NODE, &no_debug_ospf6_abr_cmd); } -struct ospf6_lsa_handler inter_prefix_handler = { +static const struct ospf6_lsa_handler inter_prefix_handler = { .lh_type = OSPF6_LSTYPE_INTER_PREFIX, .lh_name = "Inter-Prefix", .lh_short_name = "IAP", @@ -1428,7 +1428,7 @@ struct ospf6_lsa_handler inter_prefix_handler = { .lh_get_prefix_str = ospf6_inter_area_prefix_lsa_get_prefix_str, .lh_debug = 0}; -struct ospf6_lsa_handler inter_router_handler = { +static const struct ospf6_lsa_handler inter_router_handler = { .lh_type = OSPF6_LSTYPE_INTER_ROUTER, .lh_name = "Inter-Router", .lh_short_name = "IAR", diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 7914412e87..facb6aa63f 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1385,7 +1385,8 @@ static void ospf6_routemap_rule_match_address_prefixlist_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = { +static const struct route_map_rule_cmd + ospf6_routemap_rule_match_address_prefixlist_cmd = { "ipv6 address prefix-list", ospf6_routemap_rule_match_address_prefixlist, ospf6_routemap_rule_match_address_prefixlist_compile, @@ -1427,10 +1428,13 @@ static void ospf6_routemap_rule_match_interface_free(void *rule) } /* Route map commands for interface matching. */ -struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = { - "interface", ospf6_routemap_rule_match_interface, +static const struct route_map_rule_cmd + ospf6_routemap_rule_match_interface_cmd = { + "interface", + ospf6_routemap_rule_match_interface, ospf6_routemap_rule_match_interface_compile, - ospf6_routemap_rule_match_interface_free}; + ospf6_routemap_rule_match_interface_free +}; /* Match function for matching route tags */ static enum route_map_cmd_result_t @@ -1447,8 +1451,11 @@ ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p, return RMAP_NOMATCH; } -static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = { - "tag", ospf6_routemap_rule_match_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd + ospf6_routemap_rule_match_tag_cmd = { + "tag", + ospf6_routemap_rule_match_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -1482,8 +1489,10 @@ static void ospf6_routemap_rule_set_metric_type_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = { - "metric-type", ospf6_routemap_rule_set_metric_type, +static const struct route_map_rule_cmd + ospf6_routemap_rule_set_metric_type_cmd = { + "metric-type", + ospf6_routemap_rule_set_metric_type, ospf6_routemap_rule_set_metric_type_compile, ospf6_routemap_rule_set_metric_type_free, }; @@ -1517,8 +1526,10 @@ static void ospf6_routemap_rule_set_metric_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = { - "metric", ospf6_routemap_rule_set_metric, +static const struct route_map_rule_cmd + ospf6_routemap_rule_set_metric_cmd = { + "metric", + ospf6_routemap_rule_set_metric, ospf6_routemap_rule_set_metric_compile, ospf6_routemap_rule_set_metric_free, }; @@ -1555,8 +1566,10 @@ static void ospf6_routemap_rule_set_forwarding_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = { - "forwarding-address", ospf6_routemap_rule_set_forwarding, +static const struct route_map_rule_cmd + ospf6_routemap_rule_set_forwarding_cmd = { + "forwarding-address", + ospf6_routemap_rule_set_forwarding, ospf6_routemap_rule_set_forwarding_compile, ospf6_routemap_rule_set_forwarding_free, }; @@ -1576,8 +1589,11 @@ ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, return RMAP_OKAY; } -static struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = { - "tag", ospf6_routemap_rule_set_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd + ospf6_routemap_rule_set_tag_cmd = { + "tag", + ospf6_routemap_rule_set_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -1842,7 +1858,7 @@ DEFUN (show_ipv6_ospf6_redistribute, return CMD_SUCCESS; } -struct ospf6_lsa_handler as_external_handler = { +static const struct ospf6_lsa_handler as_external_handler = { .lh_type = OSPF6_LSTYPE_AS_EXTERNAL, .lh_name = "AS-External", .lh_short_name = "ASE", diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index a56ba0a694..93265afc43 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -52,7 +52,7 @@ DEFINE_HOOK(ospf6_interface_change, unsigned char conf_debug_ospf6_interface = 0; -const char *ospf6_interface_state_str[] = { +const char *const ospf6_interface_state_str[] = { "None", "Down", "Loopback", "Waiting", "PointToPoint", "DROther", "BDR", "DR", NULL}; diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 53a8910f4d..05ba698a1b 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -148,7 +148,7 @@ DECLARE_QOBJ_TYPE(ospf6_interface) #define OSPF6_INTERFACE_DR 7 #define OSPF6_INTERFACE_MAX 8 -extern const char *ospf6_interface_state_str[]; +extern const char *const ospf6_interface_state_str[]; /* flags */ #define OSPF6_INTERFACE_DISABLE 0x01 diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 7ae7d682bd..0fde997a20 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -2232,31 +2232,31 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa) __PRETTY_FUNCTION__, oa->name); } -struct ospf6_lsa_handler router_handler = {.lh_type = OSPF6_LSTYPE_ROUTER, - .lh_name = "Router", - .lh_short_name = "Rtr", - .lh_show = ospf6_router_lsa_show, - .lh_get_prefix_str = - ospf6_router_lsa_get_nbr_id, - .lh_debug = 0}; - -struct ospf6_lsa_handler network_handler = {.lh_type = OSPF6_LSTYPE_NETWORK, - .lh_name = "Network", - .lh_short_name = "Net", - .lh_show = ospf6_network_lsa_show, - .lh_get_prefix_str = - ospf6_network_lsa_get_ar_id, - .lh_debug = 0}; - -struct ospf6_lsa_handler link_handler = {.lh_type = OSPF6_LSTYPE_LINK, - .lh_name = "Link", - .lh_short_name = "Lnk", - .lh_show = ospf6_link_lsa_show, - .lh_get_prefix_str = - ospf6_link_lsa_get_prefix_str, - .lh_debug = 0}; - -struct ospf6_lsa_handler intra_prefix_handler = { +static const struct ospf6_lsa_handler router_handler = { + .lh_type = OSPF6_LSTYPE_ROUTER, + .lh_name = "Router", + .lh_short_name = "Rtr", + .lh_show = ospf6_router_lsa_show, + .lh_get_prefix_str = ospf6_router_lsa_get_nbr_id, + .lh_debug = 0}; + +static const struct ospf6_lsa_handler network_handler = { + .lh_type = OSPF6_LSTYPE_NETWORK, + .lh_name = "Network", + .lh_short_name = "Net", + .lh_show = ospf6_network_lsa_show, + .lh_get_prefix_str = ospf6_network_lsa_get_ar_id, + .lh_debug = 0}; + +static const struct ospf6_lsa_handler link_handler = { + .lh_type = OSPF6_LSTYPE_LINK, + .lh_name = "Link", + .lh_short_name = "Lnk", + .lh_show = ospf6_link_lsa_show, + .lh_get_prefix_str = ospf6_link_lsa_get_prefix_str, + .lh_debug = 0}; + +static const struct ospf6_lsa_handler intra_prefix_handler = { .lh_type = OSPF6_LSTYPE_INTRA_PREFIX, .lh_name = "Intra-Prefix", .lh_short_name = "INP", diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 61094c7cdb..0fa5585b80 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -166,7 +166,7 @@ struct quagga_signal_t ospf6_signals[] = { }, }; -static const struct frr_yang_module_info *ospf6d_yang_modules[] = { +static const struct frr_yang_module_info *const ospf6d_yang_modules[] = { &frr_interface_info, }; diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 4318db5225..1e90d4b9b5 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -51,10 +51,16 @@ DEFINE_HOOK(ospf6_neighbor_change, unsigned char conf_debug_ospf6_neighbor = 0; -const char *ospf6_neighbor_state_str[] = { +const char *const ospf6_neighbor_state_str[] = { "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange", "Loading", "Full", NULL}; +const char *const ospf6_neighbor_event_str[] = { + "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone", + "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch", + "BadLSReq", "1-WayReceived", "InactivityTimer", +}; + int ospf6_neighbor_cmp(void *va, void *vb) { struct ospf6_neighbor *ona = (struct ospf6_neighbor *)va; diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 840683cc2f..e221e9d82c 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -123,11 +123,7 @@ struct ospf6_neighbor { #define OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER 10 #define OSPF6_NEIGHBOR_EVENT_MAX_EVENT 11 -static const char *ospf6_neighbor_event_str[] = { - "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone", - "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch", - "BadLSReq", "1-WayReceived", "InactivityTimer", -}; +extern const char *const ospf6_neighbor_event_str[]; static inline const char *ospf6_neighbor_event_string(int event) { @@ -138,7 +134,7 @@ static inline const char *ospf6_neighbor_event_string(int event) return OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING; } -extern const char *ospf6_neighbor_state_str[]; +extern const char *const ospf6_neighbor_state_str[]; /* Function Prototypes */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 441a6f3677..28b15769d7 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -147,19 +147,19 @@ void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf, int size) } /* Global strings for logging */ -const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = { +const char *const ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = { "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", }; -const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = { +const char *const ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = { "?", "R", "N", "D", "L", "A", }; -const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = { +const char *const ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", }; -const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = { +const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = { "??", "IA", "IE", "E1", "E2", }; diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 02002533e6..13b01a3487 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -215,8 +215,8 @@ struct ospf6_route_table { #define OSPF6_ROUTE_TABLE_CREATE(s, t) \ ospf6_route_table_create(OSPF6_SCOPE_TYPE_##s, OSPF6_TABLE_TYPE_##t) -extern const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX]; -extern const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX]; +extern const char *const ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX]; +extern const char *const ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX]; #define OSPF6_DEST_TYPE_NAME(x) \ (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ? ospf6_dest_type_str[(x)] \ : ospf6_dest_type_str[0]) @@ -224,8 +224,8 @@ extern const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX]; (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ? ospf6_dest_type_substr[(x)] \ : ospf6_dest_type_substr[0]) -extern const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX]; -extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; +extern const char *const ospf6_path_type_str[OSPF6_PATH_TYPE_MAX]; +extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; #define OSPF6_PATH_TYPE_NAME(x) \ (0 < (x) && (x) < OSPF6_PATH_TYPE_MAX ? ospf6_path_type_str[(x)] \ : ospf6_path_type_str[0]) diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index aa4a995173..966ef44825 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -435,7 +435,7 @@ void ospf6_spf_table_finish(struct ospf6_route_table *result_table) } } -static const char *ospf6_spf_reason_str[] = { +static const char *const ospf6_spf_reason_str[] = { "R+", "R-", "N+", "N-", "L+", "L-", "R*", "N*", }; diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index d6f1fba28b..bd703bc89d 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -2330,9 +2330,7 @@ void ospf_apiserver_clients_notify_nsm_change(struct ospf_neighbor *nbr) assert(nbr); - if (nbr->oi) { - ifaddr = nbr->oi->address->u.prefix4; - } + ifaddr = nbr->oi->address->u.prefix4; nbraddr = nbr->address.u.prefix4; diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 381fb6820f..c29b464cab 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -328,8 +328,7 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr, ospf_ls_retransmit_delete_nbr_as(ospf, current); break; default: - ospf_ls_retransmit_delete_nbr_area(nbr->oi->area, - current); + ospf_ls_retransmit_delete_nbr_area(oi->area, current); break; } } @@ -345,7 +344,7 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr, procedure cannot overwrite the newly installed LSA until MinLSArrival seconds have elapsed. */ - if (!(new = ospf_lsa_install(ospf, nbr->oi, new))) + if (!(new = ospf_lsa_install(ospf, oi, new))) return -1; /* unknown LSA type or any other error condition */ /* Acknowledge the receipt of the LSA by sending a Link State diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 419081fe59..e394b6f472 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -418,7 +418,7 @@ static int ism_ignore(struct ospf_interface *oi) } /* Interface State Machine */ -struct { +const struct { int (*func)(struct ospf_interface *); int next_state; } ISM[OSPF_ISM_STATE_MAX][OSPF_ISM_EVENT_MAX] = { @@ -512,7 +512,7 @@ struct { }, }; -static const char *ospf_ism_event_str[] = { +static const char *const ospf_ism_event_str[] = { "NoEvent", "InterfaceUp", "WaitTimer", "BackupSeen", "NeighborChange", "LoopInd", "UnLoopInd", "InterfaceDown", }; diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 3e3f288023..6eec87c93e 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -290,7 +290,7 @@ void ospf_lsa_data_free(struct lsa_header *lsah) const char *dump_lsa_key(struct ospf_lsa *lsa) { - static char buf[] = {"Type255,id(255.255.255.255),ar(255.255.255.255)"}; + static char buf[sizeof("Type255,id(255.255.255.255),ar(255.255.255.255)")+1]; struct lsa_header *lsah; if (lsa != NULL && (lsah = lsa->data) != NULL) { diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index bee7bbb21d..a542b4da83 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -72,9 +72,11 @@ struct zebra_privs_t ospfd_privs = { .cap_num_i = 0}; /* OSPFd options. */ -struct option longopts[] = {{"instance", required_argument, NULL, 'n'}, - {"apiserver", no_argument, NULL, 'a'}, - {0}}; +const struct option longopts[] = { + {"instance", required_argument, NULL, 'n'}, + {"apiserver", no_argument, NULL, 'a'}, + {0} +}; /* OSPFd program name */ @@ -123,7 +125,7 @@ struct quagga_signal_t ospf_signals[] = { }, }; -static const struct frr_yang_module_info *ospfd_yang_modules[] = { +static const struct frr_yang_module_info *const ospfd_yang_modules[] = { &frr_interface_info, }; diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index a9247dd0ec..46dfc505ef 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -141,6 +141,8 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) thread_cancel_event(master, nbr); ospf_bfd_info_free(&nbr->bfd_info); + + nbr->oi = NULL; XFREE(MTYPE_OSPF_NEIGHBOR, nbr); } @@ -446,7 +448,7 @@ static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi, nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; if (IS_DEBUG_OSPF_EVENT) - zlog_debug("NSM[%s:%s]: start", IF_NAME(nbr->oi), + zlog_debug("NSM[%s:%s]: start", IF_NAME(oi), inet_ntoa(nbr->router_id)); return nbr; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 110738802c..0fc2cd60f9 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -224,7 +224,7 @@ static int ospf_db_summary_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) case OSPF_OPAQUE_LINK_LSA: /* Exclude type-9 LSAs that does not have the same "oi" with * "nbr". */ - if (nbr->oi && ospf_if_exists(lsa->oi) != nbr->oi) + if (ospf_if_exists(lsa->oi) != nbr->oi) return 0; break; case OSPF_OPAQUE_AREA_LSA: @@ -399,7 +399,7 @@ static int nsm_kill_nbr(struct ospf_neighbor *nbr) } /* Neighbor State Machine */ -struct { +const struct { int (*func)(struct ospf_neighbor *); int next_state; } NSM[OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = { @@ -575,7 +575,7 @@ struct { }, }; -static const char *ospf_nsm_event_str[] = { +static const char *const ospf_nsm_event_str[] = { "NoEvent", "PacketReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone", "BadLSReq", "LoadingDone", "AdjOK?", diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 8634589b11..80ffc3f361 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3746,8 +3746,6 @@ int ospf_hello_reply_timer(struct thread *thread) nbr = THREAD_ARG(thread); nbr->t_hello_reply = NULL; - assert(nbr->oi); - if (IS_DEBUG_OSPF(nsm, NSM_TIMERS)) zlog_debug("NSM[%s:%s]: Timer (hello-reply timer expire)", IF_NAME(nbr->oi), inet_ntoa(nbr->router_id)); @@ -4335,7 +4333,7 @@ void ospf_proactively_arp(struct ospf_neighbor *nbr) char ping_nbr[OSPF_PING_NBR_STR_MAX]; int ret; - if (!nbr || !nbr->oi || !nbr->oi->ifp) + if (!nbr) return; snprintf(ping_nbr, sizeof(ping_nbr), diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index da83c1ddaf..6cabc0c985 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -622,8 +622,10 @@ void ospf_intra_add_stub(struct route_table *rt, struct router_lsa_link *link, zlog_debug("ospf_intra_add_stub(): Stop"); } -const char *ospf_path_type_str[] = {"unknown-type", "intra-area", "inter-area", - "type1-external", "type2-external"}; +static const char *const ospf_path_type_str[] = { + "unknown-type", "intra-area", "inter-area", "type1-external", + "type2-external" +}; void ospf_route_table_dump(struct route_table *rt) { diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 1669c817e6..c89fd3597f 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -164,9 +164,12 @@ static void route_match_ip_nexthop_free(void *rule) } /* Route map commands for metric matching. */ -struct route_map_rule_cmd route_match_ip_nexthop_cmd = { - "ip next-hop", route_match_ip_nexthop, route_match_ip_nexthop_compile, - route_match_ip_nexthop_free}; +static const struct route_map_rule_cmd route_match_ip_nexthop_cmd = { + "ip next-hop", + route_match_ip_nexthop, + route_match_ip_nexthop_compile, + route_match_ip_nexthop_free +}; /* `match ip next-hop prefix-list PREFIX_LIST' */ @@ -204,10 +207,13 @@ static void route_match_ip_next_hop_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { - "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_next_hop_prefix_list_cmd = { + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, - route_match_ip_next_hop_prefix_list_free}; + route_match_ip_next_hop_prefix_list_free +}; /* `match ip next-hop type <blackhole>' */ @@ -238,10 +244,13 @@ static void route_match_ip_next_hop_type_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { - "ip next-hop type", route_match_ip_next_hop_type, +static const struct route_map_rule_cmd + route_match_ip_next_hop_type_cmd = { + "ip next-hop type", + route_match_ip_next_hop_type, route_match_ip_next_hop_type_compile, - route_match_ip_next_hop_type_free}; + route_match_ip_next_hop_type_free +}; /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return @@ -279,9 +288,12 @@ static void route_match_ip_address_free(void *rule) } /* Route map commands for ip address matching. */ -struct route_map_rule_cmd route_match_ip_address_cmd = { - "ip address", route_match_ip_address, route_match_ip_address_compile, - route_match_ip_address_free}; +static const struct route_map_rule_cmd route_match_ip_address_cmd = { + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; /* `match ip address prefix-list PREFIX_LIST' */ static enum route_map_cmd_result_t @@ -312,10 +324,13 @@ static void route_match_ip_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { - "ip address prefix-list", route_match_ip_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_address_prefix_list_cmd = { + "ip address prefix-list", + route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, - route_match_ip_address_prefix_list_free}; + route_match_ip_address_prefix_list_free +}; /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return @@ -353,9 +368,12 @@ static void route_match_interface_free(void *rule) } /* Route map commands for ip address matching. */ -struct route_map_rule_cmd route_match_interface_cmd = { - "interface", route_match_interface, route_match_interface_compile, - route_match_interface_free}; +static const struct route_map_rule_cmd route_match_interface_cmd = { + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; /* Match function return 1 if match is success else return zero. */ static enum route_map_cmd_result_t @@ -376,8 +394,10 @@ route_match_tag(void *rule, const struct prefix *prefix, } /* Route map commands for tag matching. */ -static struct route_map_rule_cmd route_match_tag_cmd = { - "tag", route_match_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd route_match_tag_cmd = { + "tag", + route_match_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -462,8 +482,10 @@ static void route_set_metric_free(void *rule) } /* Set metric rule structure. */ -struct route_map_rule_cmd route_set_metric_cmd = { - "metric", route_set_metric, route_set_metric_compile, +static const struct route_map_rule_cmd route_set_metric_cmd = { + "metric", + route_set_metric, + route_set_metric_compile, route_set_metric_free, }; @@ -513,8 +535,10 @@ static void route_set_metric_type_free(void *rule) } /* Set metric rule structure. */ -struct route_map_rule_cmd route_set_metric_type_cmd = { - "metric-type", route_set_metric_type, route_set_metric_type_compile, +static const struct route_map_rule_cmd route_set_metric_type_cmd = { + "metric-type", + route_set_metric_type, + route_set_metric_type_compile, route_set_metric_type_free, }; @@ -537,8 +561,10 @@ route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, } /* Route map commands for tag set. */ -static struct route_map_rule_cmd route_set_tag_cmd = { - "tag", route_set_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd route_set_tag_cmd = { + "tag", + route_set_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index c26545344a..da3bc6f581 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -2257,8 +2257,6 @@ static uint8_t *ospfNbrEntry(struct variable *v, oid *name, size_t *length, if (!nbr) return NULL; oi = nbr->oi; - if (!oi) - return NULL; /* Return the current value of the variable */ switch (v->magic) { diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index e683636639..8da99843e6 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -69,7 +69,7 @@ */ struct ospf_mpls_te OspfMplsTE; -const char *mode2text[] = {"Off", "AS", "Area"}; +static const char *const mode2text[] = {"Off", "AS", "Area"}; /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for MPLS-TE handling. diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index d11c34f243..4c97615ed1 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -53,7 +53,7 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_bfd.h" -static const char *ospf_network_type_str[] = { +static const char *const ospf_network_type_str[] = { "Null", "POINTOPOINT", "BROADCAST", "NBMA", "POINTOMULTIPOINT", "VIRTUALLINK", "LOOPBACK"}; @@ -2622,11 +2622,14 @@ ALIAS(no_ospf_write_multiplier, no_write_multiplier_cmd, "Write multiplier\n" "Maximum number of interface serviced per write\n") -const char *ospf_abr_type_descr_str[] = {"Unknown", "Standard (RFC2328)", - "Alternative IBM", "Alternative Cisco", - "Alternative Shortcut"}; +static const char *const ospf_abr_type_descr_str[] = { + "Unknown", "Standard (RFC2328)", "Alternative IBM", + "Alternative Cisco", "Alternative Shortcut" +}; -const char *ospf_shortcut_mode_descr_str[] = {"Default", "Enabled", "Disabled"}; +static const char *const ospf_shortcut_mode_descr_str[] = { + "Default", "Enabled", "Disabled" +}; static void show_ip_ospf_area(struct vty *vty, struct ospf_area *area, json_object *json_areas, bool use_json) @@ -5767,7 +5770,7 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self) return 0; } -static const char *show_database_desc[] = { +static const char *const show_database_desc[] = { "unknown", "Router Link States", "Net Link States", @@ -5782,7 +5785,7 @@ static const char *show_database_desc[] = { "AS-external Opaque-LSA", }; -static const char *show_database_header[] = { +static const char *const show_database_header[] = { "", "Link ID ADV Router Age Seq# CkSum Link count", "Link ID ADV Router Age Seq# CkSum", @@ -5834,7 +5837,7 @@ static void show_ip_ospf_database_header(struct vty *vty, struct ospf_lsa *lsa) vty_out(vty, " Length: %d\n\n", ntohs(lsa->data->length)); } -const char *link_type_desc[] = { +static const char *const link_type_desc[] = { "(null)", "another Router (point-to-point)", "a Transit Network", @@ -5842,12 +5845,12 @@ const char *link_type_desc[] = { "a Virtual Link", }; -const char *link_id_desc[] = { +static const char *const link_id_desc[] = { "(null)", "Neighboring Router ID", "Designated Router address", "Net", "Neighboring Router ID", }; -const char *link_data_desc[] = { +static const char *const link_data_desc[] = { "(null)", "Router Interface address", "Router Interface address", "Network Mask", "Router Interface address", }; @@ -6047,7 +6050,7 @@ static int show_opaque_lsa_detail(struct vty *vty, struct ospf_lsa *lsa) return 0; } -int (*show_function[])(struct vty *, struct ospf_lsa *) = { +int (*const show_function[])(struct vty *, struct ospf_lsa *) = { NULL, show_router_lsa_detail, show_network_lsa_detail, @@ -9646,7 +9649,7 @@ DEFUN (show_ip_ospf_vrfs, struct ospf *ospf = NULL; struct listnode *node = NULL; int count = 0; - static char header[] = "Name Id RouterId "; + static const char header[] = "Name Id RouterId "; if (uj) { json = json_object_new_object(); @@ -9703,16 +9706,23 @@ DEFUN (show_ip_ospf_vrfs, return CMD_SUCCESS; } -const char *ospf_abr_type_str[] = {"unknown", "standard", "ibm", "cisco", - "shortcut"}; +static const char *const ospf_abr_type_str[] = { + "unknown", "standard", "ibm", "cisco", "shortcut" +}; -const char *ospf_shortcut_mode_str[] = {"default", "enable", "disable"}; +static const char *const ospf_shortcut_mode_str[] = { + "default", "enable", "disable" +}; -const char *ospf_int_type_str[] = {"unknown", /* should never be used. */ - "point-to-point", "broadcast", - "non-broadcast", "point-to-multipoint", - "virtual-link", /* should never be used. */ - "loopback"}; +static const char *const ospf_int_type_str[] = { + "unknown", /* should never be used. */ + "point-to-point", + "broadcast", + "non-broadcast", + "point-to-multipoint", + "virtual-link", /* should never be used. */ + "loopback" +}; static int config_write_interface_one(struct vty *vty, struct vrf *vrf) { diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c index bb92703ae4..b228847f06 100644 --- a/pbrd/pbr_main.c +++ b/pbrd/pbr_main.c @@ -48,6 +48,7 @@ #include "pbr_zebra.h" #include "pbr_vty.h" #include "pbr_debug.h" +#include "pbr_vrf.h" zebra_capabilities_t _caps_p[] = { ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, @@ -111,7 +112,7 @@ struct quagga_signal_t pbr_signals[] = { #define PBR_VTY_PORT 2615 -static const struct frr_yang_module_info *pbrd_yang_modules[] = { +static const struct frr_yang_module_info *const pbrd_yang_modules[] = { &frr_interface_info, }; @@ -153,7 +154,6 @@ int main(int argc, char **argv, char **envp) pbr_debug_init(); - vrf_init(NULL, NULL, NULL, NULL, NULL); nexthop_group_init(pbr_nhgroup_add_cb, pbr_nhgroup_add_nexthop_cb, pbr_nhgroup_del_nexthop_cb, @@ -169,6 +169,7 @@ int main(int argc, char **argv, char **envp) if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up, pbr_ifp_down, pbr_ifp_destroy); pbr_zebra_init(); + pbr_vrf_init(); pbr_vty_init(); frr_config_fork(); diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 1a8461c6c1..7e34066b47 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -35,6 +35,7 @@ #include "pbr_zebra.h" #include "pbr_memory.h" #include "pbr_debug.h" +#include "pbr_vrf.h" DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map") DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence") @@ -42,6 +43,7 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface") static uint32_t pbr_map_sequence_unique; +static bool pbr_map_check_valid_internal(struct pbr_map *pbrm); static inline int pbr_map_compare(const struct pbr_map *pbrmap1, const struct pbr_map *pbrmap2); @@ -98,9 +100,55 @@ static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi) } } -static const char *pbr_map_reason_str[] = { +static bool pbr_map_interface_is_valid(const struct pbr_map_interface *pmi) +{ + /* Don't install rules without a real ifindex on the incoming interface. + * + * This can happen when we have config for an interface that does not + * exist or when an interface is changing vrfs. + */ + if (pmi->ifp && pmi->ifp->ifindex != IFINDEX_INTERNAL) + return true; + + return false; +} + +static void pbr_map_pbrms_update_common(struct pbr_map_sequence *pbrms, + bool install) +{ + struct pbr_map *pbrm; + struct listnode *node; + struct pbr_map_interface *pmi; + + pbrm = pbrms->parent; + + if (pbrms->nhs_installed && pbrm->incoming->count) { + for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) { + if (!pmi->ifp) + continue; + + if (install && !pbr_map_interface_is_valid(pmi)) + continue; + + pbr_send_pbr_map(pbrms, pmi, install); + } + } +} + +static void pbr_map_pbrms_install(struct pbr_map_sequence *pbrms) +{ + pbr_map_pbrms_update_common(pbrms, true); +} + +static void pbr_map_pbrms_uninstall(struct pbr_map_sequence *pbrms) +{ + pbr_map_pbrms_update_common(pbrms, false); +} + +static const char *const pbr_map_reason_str[] = { "Invalid NH-group", "Invalid NH", "No Nexthops", - "Both NH and NH-Group", "Invalid Src or Dst", "Deleting Sequence", + "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF", + "Deleting Sequence", }; void pbr_map_reason_string(unsigned int reason, char *buf, int size) @@ -168,6 +216,93 @@ void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add) pbr_map_install(pbrm); } +static int +pbr_map_policy_interface_update_common(const struct interface *ifp, + struct pbr_interface **pbr_ifp, + struct pbr_map **pbrm) +{ + if (!ifp->info) { + DEBUGD(&pbr_dbg_map, "%s: %s has no pbr_interface info", + __func__, ifp->name); + return -1; + } + + *pbr_ifp = ifp->info; + + *pbrm = pbrm_find((*pbr_ifp)->mapname); + + if (!*pbrm) { + DEBUGD(&pbr_dbg_map, "%s: applied PBR-MAP(%s) does not exist?", + __func__, (*pbr_ifp)->mapname); + return -1; + } + + return 0; +} + +void pbr_map_policy_interface_update(const struct interface *ifp, bool state_up) +{ + struct pbr_interface *pbr_ifp; + struct pbr_map_sequence *pbrms; + struct pbr_map *pbrm; + struct listnode *node, *inode; + struct pbr_map_interface *pmi; + + if (pbr_map_policy_interface_update_common(ifp, &pbr_ifp, &pbrm)) + return; + + DEBUGD(&pbr_dbg_map, "%s: %s %s rules on interface %s", __func__, + pbr_ifp->mapname, (state_up ? "installing" : "removing"), + ifp->name); + + /* + * Walk the list and install/remove maps on the interface. + */ + for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) + for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) + if (pmi->ifp == ifp && pbr_map_interface_is_valid(pmi)) + pbr_send_pbr_map(pbrms, pmi, state_up); +} + +static void pbrms_vrf_update(struct pbr_map_sequence *pbrms, + const struct pbr_vrf *pbr_vrf) +{ + const char *vrf_name = pbr_vrf_name(pbr_vrf); + + if (pbrms->vrf_lookup + && (strncmp(vrf_name, pbrms->vrf_name, sizeof(pbrms->vrf_name)) + == 0)) { + DEBUGD(&pbr_dbg_map, "\tSeq %u uses vrf %s (%u), updating map", + pbrms->seqno, vrf_name, pbr_vrf_id(pbr_vrf)); + + pbr_map_check(pbrms); + } +} + +/* Vrf enabled/disabled */ +void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf) +{ + struct pbr_map *pbrm; + struct pbr_map_sequence *pbrms; + struct listnode *node; + + if (!pbr_vrf) + return; + + bool enabled = pbr_vrf_is_enabled(pbr_vrf); + + DEBUGD(&pbr_dbg_map, "%s: %s (%u) %s, updating pbr maps", __func__, + pbr_vrf_name(pbr_vrf), pbr_vrf_id(pbr_vrf), + enabled ? "enabled" : "disabled"); + + RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { + DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __PRETTY_FUNCTION__, + pbrm->name); + for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) + pbrms_vrf_update(pbrms, pbr_vrf); + } +} + void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp) { struct pbr_interface *pbr_ifp = ifp->info; @@ -210,16 +345,11 @@ extern void pbr_map_delete(struct pbr_map_sequence *pbrms) } } -void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms) +static void pbr_map_delete_common(struct pbr_map_sequence *pbrms) { struct pbr_map *pbrm = pbrms->parent; - struct listnode *node; - struct pbr_map_interface *pmi; - if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { - for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) - pbr_send_pbr_map(pbrms, pmi, false); - } + pbr_map_pbrms_uninstall(pbrms); pbrm->valid = false; pbrms->nhs_installed = false; @@ -227,6 +357,16 @@ void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms) pbrms->nhgrp_name = NULL; } +void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms) +{ + pbr_map_delete_common(pbrms); +} + +void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms) +{ + pbr_map_delete_common(pbrms); +} + struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex, struct pbr_map_interface **ppmi) { @@ -318,6 +458,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno) pbrms->reason = PBR_MAP_INVALID_EMPTY | PBR_MAP_INVALID_NO_NEXTHOPS; + pbrms->vrf_name[0] = '\0'; QOBJ_REG(pbrms, pbr_map_sequence); listnode_add_sort(pbrm->seqnumbers, pbrms); @@ -329,12 +470,36 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno) static void pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms) { + /* Check if any are present first */ + if (!pbrms->vrf_unchanged && !pbrms->vrf_lookup && !pbrms->nhg + && !pbrms->nhgrp_name) { + pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; + return; + } + + /* + * Check validness of vrf. + */ + + /* This one can be considered always valid */ + if (pbrms->vrf_unchanged) + pbrms->nhs_installed = true; + + if (pbrms->vrf_lookup) { + struct pbr_vrf *pbr_vrf = + pbr_vrf_lookup_by_name(pbrms->vrf_name); + + if (pbr_vrf && pbr_vrf_is_valid(pbr_vrf)) + pbrms->nhs_installed = true; + else + pbrms->reason |= PBR_MAP_INVALID_VRF; + } + /* * Check validness of the nexthop or nexthop-group */ - if (!pbrms->nhg && !pbrms->nhgrp_name) - pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; + /* Only nexthop or nexthop group allowed */ if (pbrms->nhg && pbrms->nhgrp_name) pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP; @@ -458,11 +623,13 @@ void pbr_map_policy_install(const char *name) __PRETTY_FUNCTION__, name, pbrms->seqno, pbrm->valid, pbrms->nhs_installed); - if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { - DEBUGD(&pbr_dbg_map, "\tInstalling %s %u", - pbrm->name, pbrms->seqno); + if (pbrm->valid && pbrms->nhs_installed + && pbrm->incoming->count) { + DEBUGD(&pbr_dbg_map, "\tInstalling %s %u", pbrm->name, + pbrms->seqno); for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) - pbr_send_pbr_map(pbrms, pmi, true); + if (pbr_map_interface_is_valid(pmi)) + pbr_send_pbr_map(pbrms, pmi, true); } } } @@ -525,8 +692,6 @@ void pbr_map_check_nh_group_change(const char *nh_group) void pbr_map_check(struct pbr_map_sequence *pbrms) { struct pbr_map *pbrm; - struct listnode *inode; - struct pbr_map_interface *pmi; bool install; pbrm = pbrms->parent; @@ -551,23 +716,22 @@ void pbr_map_check(struct pbr_map_sequence *pbrms) pbrms->seqno, pbrms->reason); } - for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) { - pbr_send_pbr_map(pbrms, pmi, install); - } + if (install) + pbr_map_pbrms_install(pbrms); + else + pbr_map_pbrms_uninstall(pbrms); } void pbr_map_install(struct pbr_map *pbrm) { - struct listnode *node, *inode; struct pbr_map_sequence *pbrms; - struct pbr_map_interface *pmi; + struct listnode *node; if (!pbrm->incoming->count) return; for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) - for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) - pbr_send_pbr_map(pbrms, pmi, true); + pbr_map_pbrms_install(pbrms); } void pbr_map_init(void) diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 112acfe44e..8bd22cbf2a 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -22,6 +22,8 @@ #include <bitfield.h> +#include "pbr_vrf.h" + struct pbr_map { /* * RB Tree of the pbr_maps @@ -95,6 +97,21 @@ struct pbr_map_sequence { unsigned char family; /* + * Use interface's vrf. + */ + bool vrf_unchanged; + + /* + * The vrf to lookup in was directly configured. + */ + bool vrf_lookup; + + /* + * VRF to lookup. + */ + char vrf_name[VRF_NAMSIZ + 1]; + + /* * The nexthop group we auto create * for when the user specifies a individual * nexthop @@ -122,12 +139,13 @@ struct pbr_map_sequence { * A reason of 0 means we think the pbr_map_sequence is good to go * We can accumuluate multiple failure states */ -#define PBR_MAP_VALID_SEQUENCE_NUMBER 0 -#define PBR_MAP_INVALID_NEXTHOP_GROUP (1 << 0) -#define PBR_MAP_INVALID_NEXTHOP (1 << 1) -#define PBR_MAP_INVALID_NO_NEXTHOPS (1 << 2) -#define PBR_MAP_INVALID_BOTH_NHANDGRP (1 << 3) -#define PBR_MAP_INVALID_EMPTY (1 << 4) +#define PBR_MAP_VALID_SEQUENCE_NUMBER 0 +#define PBR_MAP_INVALID_NEXTHOP_GROUP (1 << 0) +#define PBR_MAP_INVALID_NEXTHOP (1 << 1) +#define PBR_MAP_INVALID_NO_NEXTHOPS (1 << 2) +#define PBR_MAP_INVALID_BOTH_NHANDGRP (1 << 3) +#define PBR_MAP_INVALID_EMPTY (1 << 4) +#define PBR_MAP_INVALID_VRF (1 << 5) uint64_t reason; QOBJ_FIELDS @@ -144,12 +162,21 @@ pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex, extern struct pbr_map *pbrm_find(const char *name); extern void pbr_map_delete(struct pbr_map_sequence *pbrms); -extern void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms); +extern void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms); +extern void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms); extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp); extern void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp); + +/* Update maps installed on interface */ +extern void pbr_map_policy_interface_update(const struct interface *ifp, + bool state_up); + extern void pbr_map_final_interface_deletion(struct pbr_map *pbrm, struct pbr_map_interface *pmi); + +extern void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf); + extern void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp); extern void pbr_map_init(void); diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 7ccd14d1f1..5ab714e617 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -548,20 +548,10 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) struct pbr_nexthop_group_cache find; struct pbr_nexthop_cache *pnhc; struct pbr_nexthop_cache lup; - struct pbr_map *pbrm = pbrms->parent; - struct listnode *node; - struct pbr_map_interface *pmi; struct nexthop *nh; enum nexthop_types_t nh_type = 0; - if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { - for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) - pbr_send_pbr_map(pbrms, pmi, false); - } - - pbrm->valid = false; - pbrms->nhs_installed = false; - pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; + pbr_map_delete_nexthops(pbrms); memset(&find, 0, sizeof(find)); snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name); diff --git a/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c new file mode 100644 index 0000000000..d5a2bd0fef --- /dev/null +++ b/pbrd/pbr_vrf.c @@ -0,0 +1,137 @@ +/* + * PBR - vrf code + * Copyright (C) 2019 Cumulus Networks, Inc. + * Stephen Worley + * + * FRR 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. + * + * FRR 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 "vrf.h" + +#include "pbr_vrf.h" +#include "pbr_memory.h" +#include "pbr_map.h" +#include "pbr_debug.h" + +DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF") + +static struct pbr_vrf *pbr_vrf_alloc(void) +{ + struct pbr_vrf *pbr_vrf; + + pbr_vrf = XCALLOC(MTYPE_PBR_MAP_VRF, sizeof(struct pbr_vrf)); + + return pbr_vrf; +} + +static void pbr_vrf_free(struct pbr_vrf *pbr_vrf) +{ + XFREE(MTYPE_PBR_MAP_VRF, pbr_vrf); +} + +static int pbr_vrf_new(struct vrf *vrf) +{ + struct pbr_vrf *pbr_vrf; + + DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name); + + pbr_vrf = pbr_vrf_alloc(); + vrf->info = pbr_vrf; + pbr_vrf->vrf = vrf; + + return 0; +} + +static int pbr_vrf_enable(struct vrf *vrf) +{ + DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name); + + pbr_map_vrf_update(vrf->info); + + return 0; +} + +static int pbr_vrf_disable(struct vrf *vrf) +{ + DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name); + + pbr_map_vrf_update(vrf->info); + + return 0; +} + +static int pbr_vrf_delete(struct vrf *vrf) +{ + DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name); + + /* + * Make sure vrf is always marked disabled first so we handle + * pbr rules using it. + */ + assert(!vrf_is_enabled(vrf)); + + pbr_vrf_free(vrf->info); + vrf->info = NULL; + + return 0; +} + +struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id) +{ + struct vrf *vrf; + + vrf = vrf_lookup_by_id(vrf_id); + if (vrf) + return ((struct pbr_vrf *)vrf->info); + + return NULL; +} + +struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name) +{ + struct vrf *vrf; + + if (!name) + name = VRF_DEFAULT_NAME; + + vrf = vrf_lookup_by_name(name); + if (vrf) + return ((struct pbr_vrf *)vrf->info); + + return NULL; +} + +bool pbr_vrf_is_enabled(const struct pbr_vrf *pbr_vrf) +{ + return vrf_is_enabled(pbr_vrf->vrf) ? true : false; +} + +bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf) +{ + if (vrf_is_backend_netns()) + return false; + + if (!pbr_vrf->vrf) + return false; + + return pbr_vrf_is_enabled(pbr_vrf); +} + +void pbr_vrf_init(void) +{ + vrf_init(pbr_vrf_new, pbr_vrf_enable, pbr_vrf_disable, pbr_vrf_delete, + NULL); +} diff --git a/pbrd/pbr_vrf.h b/pbrd/pbr_vrf.h new file mode 100644 index 0000000000..c9448762eb --- /dev/null +++ b/pbrd/pbr_vrf.h @@ -0,0 +1,43 @@ +/* + * VRF library for PBR + * Copyright (C) 2019 Cumulus Networks, Inc. + * Stephen Worley + * + * FRR 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. + * + * FRR 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 __PBR_VRF_H__ +#define __PBR_VRF_H__ + +struct pbr_vrf { + struct vrf *vrf; +}; + +static inline const char *pbr_vrf_name(const struct pbr_vrf *pbr_vrf) +{ + return pbr_vrf->vrf->name; +} + +static inline vrf_id_t pbr_vrf_id(const struct pbr_vrf *pbr_vrf) +{ + return pbr_vrf->vrf->vrf_id; +} + +extern struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id); +extern struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name); +extern bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf); +extern bool pbr_vrf_is_enabled(const struct pbr_vrf *pbr_vrf); + +extern void pbr_vrf_init(void); +#endif diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index e0fd147b0e..bc4aa947a9 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -193,14 +193,17 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd, pbr_map_check(pbrms); return CMD_SUCCESS; - } +} + +#define SET_VRF_EXISTS_STR \ + "A `set vrf XX` command already exists, please remove that first\n" DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, - "[no] set nexthop-group NHGNAME$name", - NO_STR - "Set for the PBR-MAP\n" - "nexthop-group to use\n" - "The name of the nexthop-group\n") + "[no] set nexthop-group NHGNAME$name", + NO_STR + "Set for the PBR-MAP\n" + "nexthop-group to use\n" + "The name of the nexthop-group\n") { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); struct nexthop_group_cmd *nhgc; @@ -211,16 +214,22 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, return CMD_WARNING_CONFIG_FAILED; } + if (pbrms->vrf_lookup || pbrms->vrf_unchanged) { + vty_out(vty, SET_VRF_EXISTS_STR); + return CMD_WARNING_CONFIG_FAILED; + } + nhgc = nhgc_find(name); if (!nhgc) { vty_out(vty, "Specified nexthop-group %s does not exist\n", name); - vty_out(vty, "PBR-MAP will not be applied until it is created\n"); + vty_out(vty, + "PBR-MAP will not be applied until it is created\n"); } if (no) { if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0) - pbr_map_delete_nexthop_group(pbrms); + pbr_map_delete_nexthops(pbrms); else { vty_out(vty, "Nexthop Group specified: %s does not exist to remove", @@ -272,6 +281,11 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, return CMD_WARNING_CONFIG_FAILED; } + if (pbrms->vrf_lookup || pbrms->vrf_unchanged) { + vty_out(vty, SET_VRF_EXISTS_STR); + return CMD_WARNING_CONFIG_FAILED; + } + if (vrf_name) vrf = vrf_lookup_by_name(vrf_name); else @@ -372,6 +386,61 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, return CMD_SUCCESS; } +DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, + "[no] set vrf <NAME$vrf_name|unchanged>", + NO_STR + "Set for the PBR-MAP\n" + "Specify the VRF for this map\n" + "The VRF Name\n" + "Use the interface's VRF for lookup\n") +{ + struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + int ret = CMD_SUCCESS; + + if (no) { + pbr_map_delete_vrf(pbrms); + + /* Reset all data */ + pbrms->nhs_installed = false; + pbrms->vrf_name[0] = '\0'; + pbrms->vrf_lookup = false; + pbrms->vrf_unchanged = false; + + goto done; + } + + if (pbrms->nhgrp_name || pbrms->nhg) { + vty_out(vty, + "A `set nexthop/nexthop-group XX` command already exits, please remove that first\n"); + ret = CMD_WARNING_CONFIG_FAILED; + goto done; + } + + if (pbrms->vrf_lookup || pbrms->vrf_unchanged) { + vty_out(vty, SET_VRF_EXISTS_STR); + ret = CMD_WARNING_CONFIG_FAILED; + goto done; + } + + if (vrf_name) { + if (!pbr_vrf_lookup_by_name(vrf_name)) { + vty_out(vty, "Specified: %s is non-existent\n", + vrf_name); + ret = CMD_WARNING_CONFIG_FAILED; + goto done; + } + + pbrms->vrf_lookup = true; + strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name)); + } else + pbrms->vrf_unchanged = true; + + pbr_map_check(pbrms); + +done: + return ret; +} + DEFPY (pbr_policy, pbr_policy_cmd, "[no] pbr-policy PBRMAP$mapname", @@ -500,6 +569,12 @@ DEFPY (show_pbr_map, pbrms->internal_nhg_name), pbr_nht_get_table( pbrms->internal_nhg_name)); + } else if (pbrms->vrf_unchanged) { + vty_out(vty, + "\tVRF Unchanged (use interface vrf)\n"); + } else if (pbrms->vrf_lookup) { + vty_out(vty, "\tVRF Lookup: %s\n", + pbrms->vrf_name); } else { vty_out(vty, "\tNexthop-Group: Unknown Installed: 0(0)\n"); @@ -662,6 +737,12 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty, if (pbrms->mark) vty_out(vty, " match mark %u\n", pbrms->mark); + if (pbrms->vrf_unchanged) + vty_out(vty, " set vrf unchanged\n"); + + if (pbrms->vrf_lookup) + vty_out(vty, " set vrf %s\n", pbrms->vrf_name); + if (pbrms->nhgrp_name) vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); @@ -737,6 +818,7 @@ void pbr_vty_init(void) install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd); install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd); install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd); + install_element(PBRMAP_NODE, &pbr_map_vrf_cmd); install_element(VIEW_NODE, &show_pbr_cmd); install_element(VIEW_NODE, &show_pbr_map_cmd); install_element(VIEW_NODE, &show_pbr_interface_cmd); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 719374e3b9..b0a689a7e4 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -39,6 +39,7 @@ #include "pbr_memory.h" #include "pbr_zebra.h" #include "pbr_debug.h" +#include "pbr_vrf.h" DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface") @@ -67,8 +68,11 @@ int pbr_ifp_create(struct interface *ifp) if (!ifp->info) pbr_if_new(ifp); + /* Update nexthops tracked from a `set nexthop` command */ pbr_nht_nexthop_interface_update(ifp); + pbr_map_policy_interface_update(ifp, true); + return 0; } @@ -77,6 +81,8 @@ int pbr_ifp_destroy(struct interface *ifp) DEBUGD(&pbr_dbg_zebra, "%s: %s", __PRETTY_FUNCTION__, ifp->name); + pbr_map_policy_interface_update(ifp, false); + return 0; } @@ -133,6 +139,29 @@ int pbr_ifp_down(struct interface *ifp) return 0; } +static int interface_vrf_update(ZAPI_CALLBACK_ARGS) +{ + struct interface *ifp; + vrf_id_t new_vrf_id; + + ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, + &new_vrf_id); + + if (!ifp) { + DEBUGD(&pbr_dbg_zebra, "%s: VRF change interface not found", + __func__); + + return 0; + } + + DEBUGD(&pbr_dbg_zebra, "%s: %s VRF change %u -> %u", __func__, + ifp->name, vrf_id, new_vrf_id); + + if_update_to_new_vrf(ifp, new_vrf_id); + + return 0; +} + static int route_notify_owner(ZAPI_CALLBACK_ARGS) { struct prefix p; @@ -421,6 +450,7 @@ void pbr_zebra_init(void) zclient->zebra_connected = zebra_connected; zclient->interface_address_add = interface_address_add; zclient->interface_address_delete = interface_address_delete; + zclient->interface_vrf_update = interface_vrf_update; zclient->route_notify_owner = route_notify_owner; zclient->rule_notify_owner = rule_notify_owner; zclient->nexthop_update = pbr_zebra_nexthop_update; @@ -483,6 +513,26 @@ static void pbr_encode_pbr_map_sequence_prefix(struct stream *s, stream_put(s, &p->u.prefix, prefix_blen(p)); } +static void +pbr_encode_pbr_map_sequence_vrf(struct stream *s, + const struct pbr_map_sequence *pbrms, + const struct interface *ifp) +{ + struct pbr_vrf *pbr_vrf; + + if (pbrms->vrf_unchanged) + pbr_vrf = pbr_vrf_lookup_by_id(ifp->vrf_id); + else + pbr_vrf = pbr_vrf_lookup_by_name(pbrms->vrf_name); + + if (!pbr_vrf) { + DEBUGD(&pbr_dbg_zebra, "%s: VRF not found", __func__); + return; + } + + stream_putl(s, pbr_vrf->vrf->data.l.table_id); +} + static void pbr_encode_pbr_map_sequence(struct stream *s, struct pbr_map_sequence *pbrms, struct interface *ifp) @@ -501,7 +551,10 @@ static void pbr_encode_pbr_map_sequence(struct stream *s, pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family); stream_putw(s, 0); /* dst port */ stream_putl(s, pbrms->mark); - if (pbrms->nhgrp_name) + + if (pbrms->vrf_unchanged || pbrms->vrf_lookup) + pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp); + else if (pbrms->nhgrp_name) stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name)); else if (pbrms->nhg) stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name)); diff --git a/pbrd/subdir.am b/pbrd/subdir.am index 0f2e7ad8bd..41d0e5a0b8 100644 --- a/pbrd/subdir.am +++ b/pbrd/subdir.am @@ -20,6 +20,7 @@ pbrd_libpbr_a_SOURCES = \ pbrd/pbr_memory.c \ pbrd/pbr_nht.c \ pbrd/pbr_debug.c \ + pbrd/pbr_vrf.c \ # end noinst_HEADERS += \ @@ -29,6 +30,7 @@ noinst_HEADERS += \ pbrd/pbr_vty.h \ pbrd/pbr_zebra.h \ pbrd/pbr_debug.h \ + pbrd/pbr_vrf.h \ # end pbrd/pbr_vty_clippy.c: $(CLIPPY_DEPS) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index e7e0573968..ca86017f10 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -61,6 +61,7 @@ #include "pim_nht.h" #include "pim_bfd.h" #include "pim_vxlan.h" +#include "pim_mlag.h" #include "bfd.h" #include "pim_bsm.h" @@ -7460,9 +7461,9 @@ DEFPY_HIDDEN (interface_ip_pim_activeactive, pim_ifp = ifp->info; if (no) - pim_ifp->activeactive = false; + pim_if_unconfigure_mlag_dualactive(pim_ifp); else - pim_ifp->activeactive = true; + pim_if_configure_mlag_dualactive(pim_ifp); return CMD_SUCCESS; } @@ -8380,6 +8381,20 @@ DEFUN (no_debug_pim_zebra, return CMD_SUCCESS; } +DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag", + DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +{ + PIM_DO_DEBUG_MLAG; + return CMD_SUCCESS; +} + +DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag", + NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +{ + PIM_DONT_DEBUG_MLAG; + return CMD_SUCCESS; +} + DEFUN (debug_pim_vxlan, debug_pim_vxlan_cmd, "debug pim vxlan", @@ -10406,6 +10421,8 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element(ENABLE_NODE, &debug_pim_zebra_cmd); install_element(ENABLE_NODE, &no_debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); install_element(ENABLE_NODE, &debug_msdp_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index f5bb316a7a..89a4e6e699 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -54,6 +54,7 @@ #define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n" #define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" #define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" +#define DEBUG_PIM_MLAG_STR "PIM Mlag activity\n" #define DEBUG_PIM_VXLAN_STR "PIM VxLAN events\n" #define DEBUG_SSMPINGD_STR "ssmpingd activity\n" #define CLEAR_IP_IGMP_STR "IGMP clear commands\n" diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 6848d2dabb..955ad14b01 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -34,6 +34,7 @@ #include "pim_ssmpingd.h" #include "pim_vty.h" #include "pim_bsm.h" +#include "pim_mlag.h" static void pim_instance_terminate(struct pim_instance *pim) { @@ -47,6 +48,8 @@ static void pim_instance_terminate(struct pim_instance *pim) if (pim->static_routes) list_delete(&pim->static_routes); + pim_instance_mlag_terminate(pim); + pim_upstream_terminate(pim); pim_rp_free(pim); @@ -115,6 +118,8 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) pim_upstream_init(pim); + pim_instance_mlag_init(pim); + pim->last_route_change_time = -1; return pim; } diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 06d41c4b53..dd3ac8fcb0 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -64,6 +64,17 @@ struct pim_router { vrf_id_t vrf_id; enum mlag_role role; + uint32_t pim_mlag_intf_cnt; + /* if true we have registered with MLAG */ + bool mlag_process_register; + /* if true local MLAG process reported that it is connected + * with the peer MLAG process + */ + bool connected_to_mlag; + /* Holds the client data(unencoded) that need to be pushed to MCLAGD*/ + struct stream_fifo *mlag_fifo; + struct stream *mlag_stream; + struct thread *zpthread_mlag_write; }; /* Per VRF PIM DB */ @@ -122,6 +133,9 @@ struct pim_instance { bool ecmp_enable; bool ecmp_rebalance_enable; + /* No. of Dual active I/fs in pim_instance */ + uint32_t inst_mlag_intf_cnt; + /* Bsm related */ struct bsm_scope global_scope; uint64_t bsm_rcvd; diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 6a7dbe769f..3f79b304e5 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -47,6 +47,7 @@ #include "pim_msdp.h" #include "pim_iface.h" #include "pim_bfd.h" +#include "pim_mlag.h" #include "pim_errors.h" extern struct host host; @@ -71,7 +72,7 @@ struct zebra_privs_t pimd_privs = { .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; -static const struct frr_yang_module_info *pimd_yang_modules[] = { +static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_interface_info, }; @@ -131,6 +132,7 @@ int main(int argc, char **argv, char **envp) pim_ifp_down, pim_ifp_destroy); pim_zebra_init(); pim_bfd_init(); + pim_mlag_init(); frr_config_fork(); diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c new file mode 100644 index 0000000000..f60c18204b --- /dev/null +++ b/pimd/pim_mlag.c @@ -0,0 +1,347 @@ +/* + * This is an implementation of PIM MLAG Functionality + * + * Module name: PIM MLAG + * + * Author: sathesh Kumar karra <sathk@cumulusnetworks.com> + * + * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program 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 "pimd.h" +#include "pim_mlag.h" + +extern struct zclient *zclient; + + +/********************API to process PIM MLAG Data ************************/ + +static void pim_mlag_process_mlagd_state_change(struct mlag_status msg) +{ + char buf[MLAG_ROLE_STRSIZE]; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: msg dump: my_role: %s, peer_state: %s", + __func__, + mlag_role2str(msg.my_role, buf, sizeof(buf)), + (msg.peer_state == MLAG_STATE_RUNNING ? "RUNNING" + : "DOWN")); +} + +static void pim_mlag_process_peer_frr_state_change(struct mlag_frr_status msg) +{ + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: msg dump: peer_frr_state: %s", __func__, + (msg.frr_state == MLAG_FRR_STATE_UP ? "UP" : "DOWN")); +} + +static void pim_mlag_process_vxlan_update(struct mlag_vxlan *msg) +{ +} + +static void pim_mlag_process_mroute_add(struct mlag_mroute_add msg) +{ + if (PIM_DEBUG_MLAG) { + zlog_debug( + "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x cost: %u", + __func__, msg.vrf_name, msg.source_ip, msg.group_ip, + msg.cost_to_rp); + zlog_debug( + "owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s", + msg.owner_id, msg.am_i_dr, msg.am_i_dual_active, + msg.vrf_id, msg.intf_name); + } +} + +static void pim_mlag_process_mroute_del(struct mlag_mroute_del msg) +{ + if (PIM_DEBUG_MLAG) { + zlog_debug( + "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x ", + __func__, msg.vrf_name, msg.source_ip, msg.group_ip); + zlog_debug("owner_id: %d, vrf_id: 0x%x intf_name: %s", + msg.owner_id, msg.vrf_id, msg.intf_name); + } +} + + +int pim_zebra_mlag_handle_msg(struct stream *s, int len) +{ + struct mlag_msg mlag_msg; + char buf[ZLOG_FILTER_LENGTH_MAX]; + int rc = 0; + + rc = mlag_lib_decode_mlag_hdr(s, &mlag_msg); + if (rc) + return (rc); + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Received msg type: %s length: %d, bulk_cnt: %d", + __func__, + mlag_lib_msgid_to_str(mlag_msg.msg_type, buf, + sizeof(buf)), + mlag_msg.data_len, mlag_msg.msg_cnt); + + switch (mlag_msg.msg_type) { + case MLAG_STATUS_UPDATE: { + struct mlag_status msg; + + rc = mlag_lib_decode_mlag_status(s, &msg); + if (rc) + return (rc); + pim_mlag_process_mlagd_state_change(msg); + } break; + case MLAG_PEER_FRR_STATUS: { + struct mlag_frr_status msg; + + rc = mlag_lib_decode_frr_status(s, &msg); + if (rc) + return (rc); + pim_mlag_process_peer_frr_state_change(msg); + } break; + case MLAG_VXLAN_UPDATE: { + struct mlag_vxlan msg; + + rc = mlag_lib_decode_vxlan_update(s, &msg); + if (rc) + return rc; + pim_mlag_process_vxlan_update(&msg); + } break; + case MLAG_MROUTE_ADD: { + struct mlag_mroute_add msg; + + rc = mlag_lib_decode_mroute_add(s, &msg); + if (rc) + return (rc); + pim_mlag_process_mroute_add(msg); + } break; + case MLAG_MROUTE_DEL: { + struct mlag_mroute_del msg; + + rc = mlag_lib_decode_mroute_del(s, &msg); + if (rc) + return (rc); + pim_mlag_process_mroute_del(msg); + } break; + case MLAG_MROUTE_ADD_BULK: { + struct mlag_mroute_add msg; + int i; + + for (i = 0; i < mlag_msg.msg_cnt; i++) { + + rc = mlag_lib_decode_mroute_add(s, &msg); + if (rc) + return (rc); + pim_mlag_process_mroute_add(msg); + } + } break; + case MLAG_MROUTE_DEL_BULK: { + struct mlag_mroute_del msg; + int i; + + for (i = 0; i < mlag_msg.msg_cnt; i++) { + + rc = mlag_lib_decode_mroute_del(s, &msg); + if (rc) + return (rc); + pim_mlag_process_mroute_del(msg); + } + } break; + default: + break; + } + return 0; +} + +/****************End of PIM Mesasge processing handler********************/ + +int pim_zebra_mlag_process_up(void) +{ + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Received Process-Up from Mlag", __func__); + + return 0; +} + +int pim_zebra_mlag_process_down(void) +{ + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Received Process-Down from Mlag", __func__); + + return 0; +} + +static int pim_mlag_register_handler(struct thread *thread) +{ + uint32_t bit_mask = 0; + + if (!zclient) + return -1; + + SET_FLAG(bit_mask, (1 << MLAG_STATUS_UPDATE)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_ADD)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_DEL)); + SET_FLAG(bit_mask, (1 << MLAG_DUMP)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_ADD_BULK)); + SET_FLAG(bit_mask, (1 << MLAG_MROUTE_DEL_BULK)); + SET_FLAG(bit_mask, (1 << MLAG_PIM_CFG_DUMP)); + SET_FLAG(bit_mask, (1 << MLAG_VXLAN_UPDATE)); + SET_FLAG(bit_mask, (1 << MLAG_PEER_FRR_STATUS)); + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Posting Client Register to MLAG mask: 0x%x", + __func__, bit_mask); + + zclient_send_mlag_register(zclient, bit_mask); + return 0; +} + +void pim_mlag_register(void) +{ + if (router->mlag_process_register) + return; + + router->mlag_process_register = true; + + thread_add_event(router->master, pim_mlag_register_handler, NULL, 0, + NULL); +} + +static int pim_mlag_deregister_handler(struct thread *thread) +{ + if (!zclient) + return -1; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Posting Client De-Register to MLAG from PIM", + __func__); + router->connected_to_mlag = false; + zclient_send_mlag_deregister(zclient); + return 0; +} + +void pim_mlag_deregister(void) +{ + /* if somebody still interested in the MLAG channel skip de-reg */ + if (router->pim_mlag_intf_cnt) + return; + + /* not registered; nothing do */ + if (!router->mlag_process_register) + return; + + router->mlag_process_register = false; + + thread_add_event(router->master, pim_mlag_deregister_handler, NULL, 0, + NULL); +} + +void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp) +{ + if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == true) + return; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Configuring active-active on Interface: %s", + __func__, "NULL"); + + pim_ifp->activeactive = true; + if (pim_ifp->pim) + pim_ifp->pim->inst_mlag_intf_cnt++; + + router->pim_mlag_intf_cnt++; + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: Total MLAG configured Interfaces on router: %d, Inst: %d", + __func__, router->pim_mlag_intf_cnt, + pim_ifp->pim->inst_mlag_intf_cnt); + + if (router->pim_mlag_intf_cnt == 1) { + /* + * atleast one Interface is configured for MLAG, send register + * to Zebra for receiving MLAG Updates + */ + pim_mlag_register(); + } +} + +void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp) +{ + if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == false) + return; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s: UnConfiguring active-active on Interface: %s", + __func__, "NULL"); + + pim_ifp->activeactive = false; + pim_ifp->pim->inst_mlag_intf_cnt--; + + router->pim_mlag_intf_cnt--; + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: Total MLAG configured Interfaces on router: %d, Inst: %d", + __func__, router->pim_mlag_intf_cnt, + pim_ifp->pim->inst_mlag_intf_cnt); + + if (router->pim_mlag_intf_cnt == 0) { + /* + * all the Interfaces are MLAG un-configured, post MLAG + * De-register to Zebra + */ + pim_mlag_deregister(); + } +} + + +void pim_instance_mlag_init(struct pim_instance *pim) +{ + if (!pim) + return; + + pim->inst_mlag_intf_cnt = 0; +} + + +void pim_instance_mlag_terminate(struct pim_instance *pim) +{ + struct interface *ifp; + + if (!pim) + return; + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp = ifp->info; + + if (!pim_ifp || pim_ifp->activeactive == false) + continue; + + pim_if_unconfigure_mlag_dualactive(pim_ifp); + } + pim->inst_mlag_intf_cnt = 0; +} + +void pim_mlag_init(void) +{ + router->pim_mlag_intf_cnt = 0; + router->connected_to_mlag = false; + router->mlag_fifo = stream_fifo_new(); + router->zpthread_mlag_write = NULL; + router->mlag_stream = stream_new(MLAG_BUF_LIMIT); +} diff --git a/pimd/pim_mlag.h b/pimd/pim_mlag.h new file mode 100644 index 0000000000..e86fdae78f --- /dev/null +++ b/pimd/pim_mlag.h @@ -0,0 +1,40 @@ +/* + * This is an implementation of PIM MLAG Functionality + * + * Module name: PIM MLAG + * + * Author: sathesh Kumar karra <sathk@cumulusnetworks.com> + * + * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program 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 __PIM_MLAG_H__ +#define __PIM_MLAG_H__ + +#include "mlag.h" +#include "pim_iface.h" + +extern void pim_mlag_init(void); +extern void pim_instance_mlag_init(struct pim_instance *pim); +extern void pim_instance_mlag_terminate(struct pim_instance *pim); +extern void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp); +extern void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp); +extern void pim_mlag_register(void); +extern void pim_mlag_deregister(void); +extern int pim_zebra_mlag_process_up(void); +extern int pim_zebra_mlag_process_down(void); +extern int pim_zebra_mlag_handle_msg(struct stream *msg, int len); +#endif diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index ec06cd7346..2859d26eba 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -147,7 +147,7 @@ static int pim_mroute_set(struct pim_instance *pim, int enable) return 0; } -static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = { +static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = { "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"}; static int pim_mroute_msg_nocache(int fd, struct interface *ifp, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index b297615435..b999188a9b 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -46,11 +46,12 @@ #include "pim_nht.h" #include "pim_ssm.h" #include "pim_vxlan.h" +#include "pim_mlag.h" #undef PIM_DEBUG_IFADDR_DUMP #define PIM_DEBUG_IFADDR_DUMP -static struct zclient *zclient = NULL; +struct zclient *zclient; /* Router-id update message from zebra. */ @@ -587,6 +588,9 @@ void pim_zebra_init(void) zclient->nexthop_update = pim_parse_nexthop_update; zclient->vxlan_sg_add = pim_zebra_vxlan_sg_proc; zclient->vxlan_sg_del = pim_zebra_vxlan_sg_proc; + zclient->mlag_process_up = pim_zebra_mlag_process_up; + zclient->mlag_process_down = pim_zebra_mlag_process_down; + zclient->mlag_handle_msg = pim_zebra_mlag_handle_msg; zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs); if (PIM_DEBUG_PIM_TRACE) { diff --git a/pimd/pimd.h b/pimd/pimd.h index 3b83d3b6c7..70d2766220 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -115,6 +115,7 @@ #define PIM_MASK_MTRACE (1 << 25) #define PIM_MASK_VXLAN (1 << 26) #define PIM_MASK_BSM_PROC (1 << 27) +#define PIM_MASK_MLAG (1 << 28) /* Remember 32 bits!!! */ /* PIM error codes */ @@ -171,6 +172,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DEBUG_IGMP_TRACE_DETAIL \ (router->debugs & (PIM_MASK_IGMP_TRACE_DETAIL | PIM_MASK_IGMP_TRACE)) #define PIM_DEBUG_ZEBRA (router->debugs & PIM_MASK_ZEBRA) +#define PIM_DEBUG_MLAG (router->debugs & PIM_MASK_MLAG) #define PIM_DEBUG_SSMPINGD (router->debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_MROUTE (router->debugs & PIM_MASK_MROUTE) #define PIM_DEBUG_MROUTE_DETAIL \ @@ -217,6 +219,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DO_DEBUG_IGMP_TRACE_DETAIL \ (router->debugs |= PIM_MASK_IGMP_TRACE_DETAIL) #define PIM_DO_DEBUG_ZEBRA (router->debugs |= PIM_MASK_ZEBRA) +#define PIM_DO_DEBUG_MLAG (router->debugs |= PIM_MASK_MLAG) #define PIM_DO_DEBUG_SSMPINGD (router->debugs |= PIM_MASK_SSMPINGD) #define PIM_DO_DEBUG_MROUTE (router->debugs |= PIM_MASK_MROUTE) #define PIM_DO_DEBUG_MROUTE_DETAIL (router->debugs |= PIM_MASK_MROUTE_DETAIL) @@ -248,6 +251,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DONT_DEBUG_IGMP_TRACE_DETAIL \ (router->debugs &= ~PIM_MASK_IGMP_TRACE_DETAIL) #define PIM_DONT_DEBUG_ZEBRA (router->debugs &= ~PIM_MASK_ZEBRA) +#define PIM_DONT_DEBUG_MLAG (router->debugs &= ~PIM_MASK_MLAG) #define PIM_DONT_DEBUG_SSMPINGD (router->debugs &= ~PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_MROUTE (router->debugs &= ~PIM_MASK_MROUTE) #define PIM_DONT_DEBUG_MROUTE_DETAIL (router->debugs &= ~PIM_MASK_MROUTE_DETAIL) diff --git a/pimd/subdir.am b/pimd/subdir.am index 240b62804f..5407e566a5 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -62,6 +62,7 @@ pimd_libpim_a_SOURCES = \ pimd/pim_zebra.c \ pimd/pim_zlookup.c \ pimd/pim_vxlan.c \ + pimd/pim_mlag.c \ pimd/pimd.c \ # end @@ -114,6 +115,7 @@ noinst_HEADERS += \ pimd/pim_zebra.h \ pimd/pim_zlookup.h \ pimd/pim_vxlan.h \ + pimd/pim_mlag.h \ pimd/pim_vxlan_instance.h \ pimd/pimd.h \ pimd/mtracebis_netlink.h \ diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 08cc515856..26504a857d 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -113,7 +113,7 @@ static struct quagga_signal_t ripd_signals[] = { }, }; -static const struct frr_yang_module_info *ripd_yang_modules[] = { +static const struct frr_yang_module_info *const ripd_yang_modules[] = { &frr_interface_info, &frr_ripd_info, }; diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 459188fefd..4e848766d6 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -88,9 +88,12 @@ static void route_match_metric_free(void *rule) } /* Route map commands for metric matching. */ -struct route_map_rule_cmd route_match_metric_cmd = { - "metric", route_match_metric, route_match_metric_compile, - route_match_metric_free}; +static const struct route_map_rule_cmd route_match_metric_cmd = { + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ @@ -134,9 +137,12 @@ static void route_match_interface_free(void *rule) } /* Route map commands for interface matching. */ -struct route_map_rule_cmd route_match_interface_cmd = { - "interface", route_match_interface, route_match_interface_compile, - route_match_interface_free}; +static const struct route_map_rule_cmd route_match_interface_cmd = { + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; /* `match ip next-hop IP_ACCESS_LIST' */ @@ -181,9 +187,12 @@ static void route_match_ip_next_hop_free(void *rule) } /* Route map commands for ip next-hop matching. */ -static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { - "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile, - route_match_ip_next_hop_free}; +static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = { + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; /* `match ip next-hop prefix-list PREFIX_LIST' */ @@ -223,10 +232,13 @@ static void route_match_ip_next_hop_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { - "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_next_hop_prefix_list_cmd = { + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, - route_match_ip_next_hop_prefix_list_free}; + route_match_ip_next_hop_prefix_list_free +}; /* `match ip next-hop type <blackhole>' */ @@ -257,10 +269,13 @@ static void route_match_ip_next_hop_type_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { - "ip next-hop type", route_match_ip_next_hop_type, +static const struct route_map_rule_cmd + route_match_ip_next_hop_type_cmd = { + "ip next-hop type", + route_match_ip_next_hop_type, route_match_ip_next_hop_type_compile, - route_match_ip_next_hop_type_free}; + route_match_ip_next_hop_type_free +}; /* `match ip address IP_ACCESS_LIST' */ @@ -298,9 +313,12 @@ static void route_match_ip_address_free(void *rule) } /* Route map commands for ip address matching. */ -static struct route_map_rule_cmd route_match_ip_address_cmd = { - "ip address", route_match_ip_address, route_match_ip_address_compile, - route_match_ip_address_free}; +static const struct route_map_rule_cmd route_match_ip_address_cmd = { + "ip address", + route_match_ip_address, + route_match_ip_address_compile, + route_match_ip_address_free +}; /* `match ip address prefix-list PREFIX_LIST' */ @@ -332,10 +350,13 @@ static void route_match_ip_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { - "ip address prefix-list", route_match_ip_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_address_prefix_list_cmd = { + "ip address prefix-list", + route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, - route_match_ip_address_prefix_list_free}; + route_match_ip_address_prefix_list_free +}; /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ @@ -362,8 +383,10 @@ route_match_tag(void *rule, const struct prefix *p, route_map_object_t type, } /* Route map commands for tag matching. */ -static struct route_map_rule_cmd route_match_tag_cmd = { - "tag", route_match_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd route_match_tag_cmd = { + "tag", + route_match_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -460,8 +483,10 @@ static void route_set_metric_free(void *rule) } /* Set metric rule structure. */ -static struct route_map_rule_cmd route_set_metric_cmd = { - "metric", route_set_metric, route_set_metric_compile, +static const struct route_map_rule_cmd route_set_metric_cmd = { + "metric", + route_set_metric, + route_set_metric_compile, route_set_metric_free, }; @@ -514,9 +539,12 @@ static void route_set_ip_nexthop_free(void *rule) } /* Route map commands for ip nexthop set. */ -static struct route_map_rule_cmd route_set_ip_nexthop_cmd = { - "ip next-hop", route_set_ip_nexthop, route_set_ip_nexthop_compile, - route_set_ip_nexthop_free}; +static const struct route_map_rule_cmd route_set_ip_nexthop_cmd = { + "ip next-hop", + route_set_ip_nexthop, + route_set_ip_nexthop_compile, + route_set_ip_nexthop_free +}; /* `set tag TAG' */ @@ -541,9 +569,12 @@ route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, } /* Route map commands for tag set. */ -static struct route_map_rule_cmd route_set_tag_cmd = { - "tag", route_set_tag, route_map_rule_tag_compile, - route_map_rule_tag_free}; +static const struct route_map_rule_cmd route_set_tag_cmd = { + "tag", + route_set_tag, + route_map_rule_tag_compile, + route_map_rule_tag_free +}; #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 3f2c0e9da0..0024345500 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -113,7 +113,7 @@ struct quagga_signal_t ripng_signals[] = { }, }; -static const struct frr_yang_module_info *ripngd_yang_modules[] = { +static const struct frr_yang_module_info *const ripngd_yang_modules[] = { &frr_interface_info, &frr_ripngd_info, }; diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index d27ec76a56..6123591429 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -79,9 +79,12 @@ static void route_match_metric_free(void *rule) } /* Route map commands for metric matching. */ -static struct route_map_rule_cmd route_match_metric_cmd = { - "metric", route_match_metric, route_match_metric_compile, - route_match_metric_free}; +static const struct route_map_rule_cmd route_match_metric_cmd = { + "metric", + route_match_metric, + route_match_metric_compile, + route_match_metric_free +}; /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ @@ -121,9 +124,12 @@ static void route_match_interface_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_interface_cmd = { - "interface", route_match_interface, route_match_interface_compile, - route_match_interface_free}; +static const struct route_map_rule_cmd route_match_interface_cmd = { + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ @@ -150,8 +156,10 @@ static enum route_map_cmd_result_t route_match_tag(void *rule, return RMAP_NOMATCH; } -static struct route_map_rule_cmd route_match_tag_cmd = { - "tag", route_match_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd route_match_tag_cmd = { + "tag", + route_match_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -246,8 +254,10 @@ static void route_set_metric_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_set_metric_cmd = { - "metric", route_set_metric, route_set_metric_compile, +static const struct route_map_rule_cmd route_set_metric_cmd = { + "metric", + route_set_metric, + route_set_metric_compile, route_set_metric_free, }; @@ -299,10 +309,13 @@ static void route_set_ipv6_nexthop_local_free(void *rule) } /* Route map commands for ipv6 nexthop local set. */ -static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = { - "ipv6 next-hop local", route_set_ipv6_nexthop_local, +static const struct route_map_rule_cmd + route_set_ipv6_nexthop_local_cmd = { + "ipv6 next-hop local", + route_set_ipv6_nexthop_local, route_set_ipv6_nexthop_local_compile, - route_set_ipv6_nexthop_local_free}; + route_set_ipv6_nexthop_local_free +}; /* `set tag TAG' */ @@ -327,9 +340,12 @@ route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type, } /* Route map commands for tag set. */ -static struct route_map_rule_cmd route_set_tag_cmd = { - "tag", route_set_tag, route_map_rule_tag_compile, - route_map_rule_tag_free}; +static const struct route_map_rule_cmd route_set_tag_cmd = { + "tag", + route_set_tag, + route_map_rule_tag_compile, + route_map_rule_tag_free +}; #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index 39453ee9ad..a00106d686 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -111,7 +111,7 @@ struct quagga_signal_t sharp_signals[] = { #define SHARP_VTY_PORT 2614 -static const struct frr_yang_module_info *sharpd_yang_modules[] = { +static const struct frr_yang_module_info *const sharpd_yang_modules[] = { }; FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT, diff --git a/staticd/static_main.c b/staticd/static_main.c index 77243994e2..18cb9638c9 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -100,7 +100,7 @@ struct quagga_signal_t static_signals[] = { }, }; -static const struct frr_yang_module_info *staticd_yang_modules[] = { +static const struct frr_yang_module_info *const staticd_yang_modules[] = { }; #define STATIC_VTY_PORT 2616 diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 48ad10e90c..8db37589af 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -434,7 +434,7 @@ static int static_route_leak( "%% Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n"); else zlog_warn( - "%s: %s: Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n", + "%s: %s: Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)", __PRETTY_FUNCTION__, dest_str); return CMD_WARNING_CONFIG_FAILED; } diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c index 3180f9f9f3..a28830e088 100644 --- a/tests/lib/northbound/test_oper_data.c +++ b/tests/lib/northbound/test_oper_data.c @@ -271,7 +271,7 @@ const struct frr_yang_module_info frr_test_module_info = { }; /* clang-format on */ -static const struct frr_yang_module_info *modules[] = { +static const struct frr_yang_module_info *const modules[] = { &frr_test_module_info, }; diff --git a/tests/topotests/bgp_reject_as_sets/__init__.py b/tests/topotests/bgp_reject_as_sets/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/__init__.py diff --git a/tests/topotests/bgp_reject_as_sets/r1/bgpd.conf b/tests/topotests/bgp_reject_as_sets/r1/bgpd.conf new file mode 100644 index 0000000000..7b24c4bbf9 --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/r1/bgpd.conf @@ -0,0 +1,8 @@ +! exit1 +router bgp 65001 + neighbor 192.168.255.1 remote-as 65002 + address-family ipv4 unicast + redistribute connected + exit-address-family + ! +! diff --git a/tests/topotests/bgp_reject_as_sets/r1/zebra.conf b/tests/topotests/bgp_reject_as_sets/r1/zebra.conf new file mode 100644 index 0000000000..9904bb4e16 --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/r1/zebra.conf @@ -0,0 +1,9 @@ +! exit1 +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_reject_as_sets/r2/bgpd.conf b/tests/topotests/bgp_reject_as_sets/r2/bgpd.conf new file mode 100644 index 0000000000..c991b5bcd8 --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/r2/bgpd.conf @@ -0,0 +1,10 @@ +! spine +router bgp 65002 + bgp reject-as-sets + neighbor 192.168.255.2 remote-as 65001 + neighbor 192.168.254.2 remote-as 65003 + address-family ipv4 unicast + aggregate-address 172.16.0.0/16 as-set summary-only + exit-address-family + ! +! diff --git a/tests/topotests/bgp_reject_as_sets/r2/zebra.conf b/tests/topotests/bgp_reject_as_sets/r2/zebra.conf new file mode 100644 index 0000000000..f0d357c5ff --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/r2/zebra.conf @@ -0,0 +1,9 @@ +! spine +interface r2-eth0 + ip address 192.168.255.1/30 +! +interface r2-eth1 + ip address 192.168.254.1/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_reject_as_sets/r3/bgpd.conf b/tests/topotests/bgp_reject_as_sets/r3/bgpd.conf new file mode 100644 index 0000000000..bee518c84b --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/r3/bgpd.conf @@ -0,0 +1,9 @@ +! exit2 +router bgp 65003 + neighbor 192.168.254.1 remote-as 65002 + address-family ipv4 unicast + neighbor 192.168.254.1 allowas-in + redistribute connected + exit-address-family + ! +! diff --git a/tests/topotests/bgp_reject_as_sets/r3/zebra.conf b/tests/topotests/bgp_reject_as_sets/r3/zebra.conf new file mode 100644 index 0000000000..f490d97afe --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/r3/zebra.conf @@ -0,0 +1,9 @@ +! exit2 +interface lo + ip address 172.16.254.254/32 +! +interface r3-eth0 + ip address 192.168.254.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py new file mode 100644 index 0000000000..f307edc678 --- /dev/null +++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python + +# +# test_bgp_reject_as_sets.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if an aggregated route with AS_SET is not sent to peers. +Addressing draft-ietf-idr-deprecate-as-set-confed-set recommendations. + +BGP speakers conforming to this document (i.e., conformant BGP + speakers) MUST NOT locally generate BGP UPDATE messages containing + AS_SET or AS_CONFED_SET. Conformant BGP speakers SHOULD NOT send BGP + UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of + such messages, conformant BGP speakers SHOULD use the "Treat-as- + withdraw" error handling behavior as per [RFC7606]. +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 4): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_reject_as_sets(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r2'] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + expected = { + '192.168.255.2': { + 'bgpState': 'Established', + 'addressFamilyInfo': { + 'ipv4Unicast': { + 'acceptedPrefixCounter': 2 + } + } + } + } + return topotest.json_cmp(output, expected) + + def _bgp_has_aggregated_route_with_stripped_as_set(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.0.0/16 json")) + expected = { + 'paths': [ + { + 'aspath': { + 'string': 'Local', + 'segments': [ + ], + 'length': 0 + } + } + ] + } + return topotest.json_cmp(output, expected) + + def _bgp_announce_route_without_as_sets(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.254.2 advertised-routes json")) + expected = { + 'advertisedRoutes': { + '172.16.0.0/16': { + 'asPath': '' + }, + '192.168.254.0/30': { + 'asPath': '65003' + }, + '192.168.255.0/30': { + 'asPath': '65001' + } + }, + 'totalPrefixCounter': 3 + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed bgp convergence in "{}"'.format(router) + + test_func = functools.partial(_bgp_has_aggregated_route_with_stripped_as_set, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed to see an aggregated route in "{}"'.format(router) + + test_func = functools.partial(_bgp_announce_route_without_as_sets, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Route 172.16.0.0/16 should be sent without AS_SET to r3 "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index eed0e8a31a..42bb154f98 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -50,13 +50,13 @@ int vrrp_autoconfig_version; struct vrrp_defaults vd; -const char *vrrp_state_names[3] = { +const char *const vrrp_state_names[3] = { [VRRP_STATE_INITIALIZE] = "Initialize", [VRRP_STATE_MASTER] = "Master", [VRRP_STATE_BACKUP] = "Backup", }; -const char *vrrp_event_names[2] = { +static const char *const vrrp_event_names[2] = { [VRRP_EVENT_STARTUP] = "Startup", [VRRP_EVENT_SHUTDOWN] = "Shutdown", }; @@ -1414,7 +1414,7 @@ static void vrrp_change_state_initialize(struct vrrp_router *r) vrrp_zebra_radv_set(r, false); } -void (*vrrp_change_state_handlers[])(struct vrrp_router *vr) = { +void (*const vrrp_change_state_handlers[])(struct vrrp_router *vr) = { [VRRP_STATE_MASTER] = vrrp_change_state_master, [VRRP_STATE_BACKUP] = vrrp_change_state_backup, [VRRP_STATE_INITIALIZE] = vrrp_change_state_initialize, @@ -1639,7 +1639,7 @@ static int vrrp_shutdown(struct vrrp_router *r) return 0; } -static int (*vrrp_event_handlers[])(struct vrrp_router *r) = { +static int (*const vrrp_event_handlers[])(struct vrrp_router *r) = { [VRRP_EVENT_STARTUP] = vrrp_startup, [VRRP_EVENT_SHUTDOWN] = vrrp_shutdown, }; diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index 5d355d04b5..79283bbb10 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -465,8 +465,7 @@ int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6); #define VRRP_EVENT_STARTUP 0 #define VRRP_EVENT_SHUTDOWN 1 -extern const char *vrrp_state_names[3]; -extern const char *vrrp_event_names[2]; +extern const char *const vrrp_state_names[3]; /* * This hook called whenever the state of a Virtual Router changes, after the diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c index 6afb418ad0..fface1718f 100644 --- a/vrrpd/vrrp_main.c +++ b/vrrpd/vrrp_main.c @@ -105,7 +105,7 @@ struct quagga_signal_t vrrp_signals[] = { }, }; -static const struct frr_yang_module_info *vrrp_yang_modules[] = { +static const struct frr_yang_module_info *const vrrp_yang_modules[] = { &frr_interface_info, }; diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 461310c1e5..e4fee2d792 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -33,7 +33,7 @@ DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet") /* clang-format off */ -const char *vrrp_packet_names[16] = { +static const char *const vrrp_packet_names[16] = { [0] = "Unknown", [VRRP_TYPE_ADVERTISEMENT] = "ADVERTISEMENT", [2] = "Unknown", diff --git a/vrrpd/vrrp_packet.h b/vrrpd/vrrp_packet.h index c2ce22f008..082935f080 100644 --- a/vrrpd/vrrp_packet.h +++ b/vrrpd/vrrp_packet.h @@ -28,8 +28,6 @@ #define VRRP_TYPE_ADVERTISEMENT 1 -extern const char *vrrp_packet_names[16]; - /* * Shared header for VRRPv2/v3 packets. */ diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index ea59655824..4e8502107a 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -76,7 +76,7 @@ typedef enum { PHASE_WAITING_ZEBRA_UP } restart_phase_t; -static const char *phase_str[] = { +static const char *const phase_str[] = { "Idle", "Startup", "Stop jobs running", @@ -144,7 +144,7 @@ typedef enum { #define IS_UP(DMN) \ (((DMN)->state == DAEMON_UP) || ((DMN)->state == DAEMON_UNRESPONSIVE)) -static const char *state_str[] = { +static const char *const state_str[] = { "Init", "Down", "Connecting", "Up", "Unresponsive", }; diff --git a/zebra/interface.c b/zebra/interface.c index eea80652e5..20b05dfb32 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -161,6 +161,7 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */ rtadv->AdvIntervalOption = 0; + rtadv->UseFastRexmit = true; rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new(); @@ -1037,7 +1038,8 @@ void if_up(struct interface *ifp) #if defined(HAVE_RTADV) /* Enable fast tx of RA if enabled && RA interval is not in msecs */ if (zif->rtadv.AdvSendAdvertisements - && (zif->rtadv.MaxRtrAdvInterval >= 1000)) { + && (zif->rtadv.MaxRtrAdvInterval >= 1000) + && zif->rtadv.UseFastRexmit) { zif->rtadv.inFastRexmit = 1; zif->rtadv.NumFastReXmitsRemain = RTADV_NUM_FAST_REXMITS; } @@ -1060,7 +1062,9 @@ void if_up(struct interface *ifp) zif->link_ifindex); if (link_if) zebra_vxlan_svi_up(ifp, link_if); - } + } else if (IS_ZEBRA_IF_MACVLAN(ifp)) + zebra_vxlan_macvlan_up(ifp); + } /* Interface goes down. We have to manage different behavior of based @@ -1092,7 +1096,8 @@ void if_down(struct interface *ifp) zif->link_ifindex); if (link_if) zebra_vxlan_svi_down(ifp, link_if); - } + } else if (IS_ZEBRA_IF_MACVLAN(ifp)) + zebra_vxlan_macvlan_down(ifp); /* Notify to the protocol daemons. */ diff --git a/zebra/interface.h b/zebra/interface.h index 78ccbae623..b7e90a0c31 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -189,6 +189,13 @@ struct rtadvconf { */ struct list *AdvDNSSLList; + /* + * rfc4861 states RAs must be sent at least 3 seconds apart. + * We allow faster retransmits to speed up convergence but can + * turn that capability off to meet the rfc if needed. + */ + bool UseFastRexmit; /* True if fast rexmits are enabled */ + uint8_t inFastRexmit; /* True if we're rexmits faster than usual */ /* Track if RA was configured by BGP or by the Operator or both */ diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c index 709d2176aa..226f722937 100644 --- a/zebra/ipforward_proc.c +++ b/zebra/ipforward_proc.c @@ -30,7 +30,7 @@ extern struct zebra_privs_t zserv_privs; -char proc_net_snmp[] = "/proc/net/snmp"; +static const char proc_net_snmp[] = "/proc/net/snmp"; static void dropline(FILE *fp) { @@ -70,7 +70,7 @@ int ipforward(void) } /* char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/conf/all/forwarding"; */ -char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward"; +static const char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward"; int ipforward_on(void) { @@ -114,7 +114,8 @@ int ipforward_off(void) return ipforward(); } -char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding"; +static const char proc_ipv6_forwarding[] = + "/proc/sys/net/ipv6/conf/all/forwarding"; int ipforward_ipv6(void) { diff --git a/zebra/main.c b/zebra/main.c index 334354eaae..731c4e1614 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -84,7 +84,7 @@ uint32_t nl_rcvbufsize = 4194304; #define OPTION_V6_RR_SEMANTICS 2000 /* Command line options. */ -struct option longopts[] = { +const struct option longopts[] = { {"batch", no_argument, NULL, 'b'}, {"allow_delete", no_argument, NULL, 'a'}, {"keep_kernel", no_argument, NULL, 'k'}, @@ -229,7 +229,7 @@ struct quagga_signal_t zebra_signals[] = { }, }; -static const struct frr_yang_module_info *zebra_yang_modules[] = { +static const struct frr_yang_module_info *const zebra_yang_modules[] = { &frr_interface_info, }; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 42a62c1747..f3a255fd29 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -83,8 +83,8 @@ struct gw_family_t { union g_addr gate; }; -char ipv4_ll_buf[16] = "169.254.0.1"; -struct in_addr ipv4_ll; +static const char ipv4_ll_buf[16] = "169.254.0.1"; +static struct in_addr ipv4_ll; /* * The ipv4_ll data structure is used for all 5549 diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 73b3dd0b40..6909bcb137 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -178,7 +178,7 @@ static int kernel_rtm(int cmd, const struct prefix *p, case NEXTHOP_TYPE_BLACKHOLE: bh_type = nexthop->bh_type; switch (p->family) { - case AFI_IP: { + case AF_INET: { struct in_addr loopback; loopback.s_addr = htonl(INADDR_LOOPBACK); sin_gate.sin.sin_addr = loopback; @@ -189,7 +189,8 @@ static int kernel_rtm(int cmd, const struct prefix *p, gate = true; } break; - case AFI_IP6: + case AF_INET6: + zlog_warn("v6 blackhole routes have not been programmed yet"); break; } } @@ -230,13 +231,13 @@ static int kernel_rtm(int cmd, const struct prefix *p, __func__, prefix_buf); } else { switch (p->family) { - case AFI_IP: + case AF_INET: inet_ntop(AF_INET, &sin_gate.sin.sin_addr, gate_buf, sizeof(gate_buf)); break; - case AFI_IP6: + case AF_INET6: inet_ntop(AF_INET6, &sin_gate.sin6.sin6_addr, gate_buf, sizeof(gate_buf)); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 4903455a2b..0adf654aaf 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -72,7 +72,9 @@ DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL") /* Order is intentional. Matches RFC4191. This array is also used for command matching, so only modify with care. */ -const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0}; +static const char *const rtadv_pref_strs[] = { + "medium", "high", "INVALID", "low", 0 +}; enum rtadv_event { RTADV_START, @@ -495,7 +497,8 @@ static int rtadv_timer(struct thread *thread) zif = ifp->info; if (zif->rtadv.AdvSendAdvertisements) { - if (zif->rtadv.inFastRexmit) { + if (zif->rtadv.inFastRexmit + && zif->rtadv.UseFastRexmit) { /* We assume we fast rexmit every sec so * no * additional vars */ @@ -535,9 +538,28 @@ static int rtadv_timer(struct thread *thread) static void rtadv_process_solicit(struct interface *ifp) { struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); + struct zebra_if *zif; assert(zvrf); - rtadv_send_packet(rtadv_get_socket(zvrf), ifp); + zif = ifp->info; + + /* + * If FastRetransmit is enabled, send the RA immediately. + * If not enabled but it has been more than MIN_DELAY_BETWEEN_RAS + * (3 seconds) since the last RA was sent, send it now and reset + * the timer to start at the max (configured) again. + * If not enabled and it is less than 3 seconds since the last + * RA packet was sent, set the timer for 3 seconds so the next + * one will be sent with a minimum of 3 seconds between RAs. + * RFC4861 sec 6.2.6 + */ + if ((zif->rtadv.UseFastRexmit) + || (zif->rtadv.AdvIntervalTimer <= + (zif->rtadv.MaxRtrAdvInterval - MIN_DELAY_BETWEEN_RAS))) { + rtadv_send_packet(rtadv_get_socket(zvrf), ifp); + zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; + } else + zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS; } /* @@ -904,9 +926,12 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, zif->rtadv.AdvIntervalTimer = 0; zvrf->rtadv.adv_if_count++; - if (zif->rtadv.MaxRtrAdvInterval >= 1000) { - /* Enable Fast RA only when RA interval is in - * secs */ + if ((zif->rtadv.MaxRtrAdvInterval >= 1000) + && zif->rtadv.UseFastRexmit) { + /* + * Enable Fast RA only when RA interval is in + * secs and Fast RA retransmit is enabled + */ zif->rtadv.inFastRexmit = 1; zif->rtadv.NumFastReXmitsRemain = RTADV_NUM_FAST_REXMITS; @@ -996,6 +1021,51 @@ void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS) zebra_interface_radv_set(client, hdr, msg, zvrf, 1); } +DEFUN (ipv6_nd_ra_fast_retrans, + ipv6_nd_ra_fast_retrans_cmd, + "ipv6 nd ra-fast-retrans", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Fast retransmit of RA packets\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + + if (if_is_loopback(ifp) + || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) { + vty_out(vty, + "Cannot configure IPv6 Router Advertisements on this interface\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + zif->rtadv.UseFastRexmit = true; + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_ra_fast_retrans, + no_ipv6_nd_ra_fast_retrans_cmd, + "no ipv6 nd ra-fast-retrans", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Fast retransmit of RA packets\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *zif = ifp->info; + + if (if_is_loopback(ifp) + || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) { + vty_out(vty, + "Cannot configure IPv6 Router Advertisements on this interface\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + zif->rtadv.UseFastRexmit = false; + + return CMD_SUCCESS; +} + DEFUN (ipv6_nd_suppress_ra, ipv6_nd_suppress_ra_cmd, "ipv6 nd suppress-ra", @@ -1954,6 +2024,10 @@ static int nd_dump_vty(struct vty *vty, struct interface *ifp) " ND router advertisements are sent every " "%d seconds\n", interval / 1000); + if (!rtadv->UseFastRexmit) + vty_out(vty, + " ND router advertisements do not use fast retransmit\n"); + if (rtadv->AdvDefaultLifetime != -1) vty_out(vty, " ND router advertisements live for %d seconds\n", @@ -2025,6 +2099,9 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) if (zif->rtadv.AdvIntervalOption) vty_out(vty, " ipv6 nd adv-interval-option\n"); + if (!zif->rtadv.UseFastRexmit) + vty_out(vty, " no ipv6 nd ra-fast-retrans\n"); + if (zif->rtadv.AdvDefaultLifetime != -1) vty_out(vty, " ipv6 nd ra-lifetime %d\n", zif->rtadv.AdvDefaultLifetime); @@ -2173,6 +2250,8 @@ void rtadv_cmd_init(void) hook_register(zebra_if_extra_info, nd_dump_vty); hook_register(zebra_if_config_wr, rtadv_config_write); + install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd); + install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd); install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); diff --git a/zebra/rtadv.h b/zebra/rtadv.h index d692ef2417..409959d08d 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -59,6 +59,11 @@ struct rtadv_prefix { #endif }; +/* RFC4861 minimum delay between RAs */ +#ifndef MIN_DELAY_BETWEEN_RAS +#define MIN_DELAY_BETWEEN_RAS 3000 +#endif + /* RFC4584 Extension to Sockets API for Mobile IPv6 */ #ifndef ND_OPT_ADV_INTERVAL @@ -126,8 +131,6 @@ struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */ } __attribute__((__packed__)); #endif -extern const char *rtadv_pref_strs[]; - #endif /* HAVE_RTADV */ typedef enum { diff --git a/zebra/subdir.am b/zebra/subdir.am index 28847ce09b..d0f32d6a14 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -38,6 +38,9 @@ man8 += $(MANBUILD)/zebra.8 endif zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) +if HAVE_PROTOBUF +zebra_zebra_LDADD += mlag/libmlag_pb.la $(PROTOBUF_C_LIBS) +endif zebra_zebra_SOURCES = \ zebra/connected.c \ zebra/debug.c \ @@ -66,6 +69,7 @@ zebra_zebra_SOURCES = \ zebra/rule_netlink.c \ zebra/rule_socket.c \ zebra/zebra_mlag.c \ + zebra/zebra_mlag_private.c \ zebra/zebra_l2.c \ zebra/zebra_memory.c \ zebra/zebra_dplane.c \ @@ -130,6 +134,7 @@ noinst_HEADERS += \ zebra/rtadv.h \ zebra/rule_netlink.h \ zebra/zebra_mlag.h \ + zebra/zebra_mlag_private.h \ zebra/zebra_fpm_private.h \ zebra/zebra_l2.h \ zebra/zebra_dplane.h \ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 93ee2fc1f9..bf29bda77b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1023,7 +1023,7 @@ static int zsend_table_manager_connect_response(struct zserv *client, /* Inbound message handling ------------------------------------------------ */ -int cmd2type[] = { +const int cmd2type[] = { [ZEBRA_NEXTHOP_REGISTER] = RNH_NEXTHOP_TYPE, [ZEBRA_NEXTHOP_UNREGISTER] = RNH_NEXTHOP_TYPE, [ZEBRA_IMPORT_ROUTE_REGISTER] = RNH_IMPORT_CHECK_TYPE, @@ -1788,7 +1788,7 @@ static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS) struct zapi_nexthop_label *znh; znh = &zl.nexthops[i]; - mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label, + mpls_lsp_install(zvrf, zl.type, zl.local_label, 1, &znh->label, znh->type, &znh->address, znh->ifindex); if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) @@ -1889,7 +1889,7 @@ static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS) struct zapi_nexthop_label *znh; znh = &zl.nexthops[i]; - mpls_lsp_install(zvrf, zl.type, zl.local_label, znh->label, + mpls_lsp_install(zvrf, zl.type, zl.local_label, 1, &znh->label, znh->type, &znh->address, znh->ifindex); if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) { @@ -2288,10 +2288,11 @@ static void zread_vrf_label(ZAPI_HANDLER_ARGS) ifp->ifindex); } - if (nlabel != MPLS_LABEL_NONE) - mpls_lsp_install(def_zvrf, ltype, nlabel, - MPLS_LABEL_IMPLICIT_NULL, NEXTHOP_TYPE_IFINDEX, - NULL, ifp->ifindex); + if (nlabel != MPLS_LABEL_NONE) { + mpls_label_t out_label = MPLS_LABEL_IMPLICIT_NULL; + mpls_lsp_install(def_zvrf, ltype, nlabel, 1, &out_label, + NEXTHOP_TYPE_IFINDEX, NULL, ifp->ifindex); + } zvrf->label[afi] = nlabel; stream_failure: @@ -2491,7 +2492,7 @@ stream_failure: return; } -void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { +void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_ROUTER_ID_ADD] = zread_router_id_add, [ZEBRA_ROUTER_ID_DELETE] = zread_router_id_delete, [ZEBRA_INTERFACE_ADD] = zread_interface_add, @@ -2562,6 +2563,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_IPTABLE_DELETE] = zread_iptable, [ZEBRA_VXLAN_FLOOD_CONTROL] = zebra_vxlan_flood_control, [ZEBRA_VXLAN_SG_REPLAY] = zebra_vxlan_sg_replay, + [ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register, + [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister, + [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, }; #if defined(HANDLE_ZAPI_FUZZING) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 70bb2b6750..bc4f51f70f 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1161,7 +1161,8 @@ zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx, enum nexthop_types_t nh_type, union g_addr *gate, ifindex_t ifindex, - mpls_label_t out_label) + uint8_t num_labels, + mpls_label_t out_labels[]) { zebra_nhlfe_t *nhlfe; @@ -1169,7 +1170,7 @@ zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx, nhlfe = zebra_mpls_lsp_add_nhlfe(&(ctx->u.lsp), lsp_type, nh_type, gate, - ifindex, out_label); + ifindex, num_labels, out_labels); return nhlfe; } @@ -1661,7 +1662,8 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, nhlfe->nexthop->type, &(nhlfe->nexthop->gate), nhlfe->nexthop->ifindex, - nhlfe->nexthop->nh_label->label[0]); + nhlfe->nexthop->nh_label->num_labels, + nhlfe->nexthop->nh_label->label); if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) { ret = ENOMEM; diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index fede3bfcca..c0b04e71b0 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -302,7 +302,8 @@ zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx, enum nexthop_types_t nh_type, union g_addr *gate, ifindex_t ifindex, - mpls_label_t out_label); + uint8_t num_labels, + mpls_label_t out_labels[]); const zebra_nhlfe_t *dplane_ctx_get_best_nhlfe( const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index 5012cc2a49..1a911e429f 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -23,9 +23,13 @@ #include "command.h" #include "hook.h" +#include "frr_pthread.h" +#include "mlag.h" #include "zebra/zebra_mlag.h" +#include "zebra/zebra_mlag_private.h" #include "zebra/zebra_router.h" +#include "zebra/zebra_memory.h" #include "zebra/zapi_msg.h" #include "zebra/debug.h" @@ -33,6 +37,543 @@ #include "zebra/zebra_mlag_clippy.c" #endif +#define ZEBRA_MLAG_METADATA_LEN 4 +#define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF + +uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT]; +uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT]; +uint32_t mlag_rd_buf_offset; + +static bool test_mlag_in_progress; + +static int zebra_mlag_signal_write_thread(void); +static int zebra_mlag_terminate_pthread(struct thread *event); +static int zebra_mlag_post_data_from_main_thread(struct thread *thread); +static void zebra_mlag_publish_process_state(struct zserv *client, + zebra_message_types_t msg_type); + +/**********************MLAG Interaction***************************************/ + +/* + * API to post the Registration to MLAGD + * MLAG will not process any messages with out the registration + */ +void zebra_mlag_send_register(void) +{ + struct stream *s = NULL; + + s = stream_new(sizeof(struct mlag_msg)); + + stream_putl(s, MLAG_REGISTER); + stream_putw(s, MLAG_MSG_NULL_PAYLOAD); + stream_putw(s, MLAG_MSG_NO_BATCH); + stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s); + zebra_mlag_signal_write_thread(); + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ", + __func__); +} + +/* + * API to post the De-Registration to MLAGD + * MLAG will not process any messages after the de-registration + */ +void zebra_mlag_send_deregister(void) +{ + struct stream *s = NULL; + + s = stream_new(sizeof(struct mlag_msg)); + + stream_putl(s, MLAG_DEREGISTER); + stream_putw(s, MLAG_MSG_NULL_PAYLOAD); + stream_putw(s, MLAG_MSG_NO_BATCH); + stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s); + zebra_mlag_signal_write_thread(); + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ", + __func__); +} + +/* + * API To handle MLAG Received data + * Decodes the data using protobuf and enqueue to main thread + * main thread publish this to clients based on client subscription + */ +void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len) +{ + struct stream *s = NULL; + struct stream *s1 = NULL; + int msg_type = 0; + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + msg_type = zebra_mlag_protobuf_decode_message(s, data, len); + + if (msg_type <= 0) { + /* Something went wrong in decoding */ + stream_free(s); + zlog_err("%s: failed to process mlag data-%d, %u", __func__, + msg_type, len); + return; + } + + /* + * additional four bytes are for message type + */ + s1 = stream_new(stream_get_endp(s) + ZEBRA_MLAG_METADATA_LEN); + stream_putl(s1, msg_type); + stream_put(s1, s->data, stream_get_endp(s)); + thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread, + s1, 0, NULL); + stream_free(s); +} + +/**********************End of MLAG Interaction********************************/ + +/************************MLAG Thread Processing*******************************/ + +/* + * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be + * yielded to give CPU for other threads + */ +#define ZEBRA_MLAG_POST_LIMIT 100 + +/* + * This thread reads the clients data from the Global queue and encodes with + * protobuf and pass on to the MLAG socket. + */ +static int zebra_mlag_client_msg_handler(struct thread *event) +{ + struct stream *s; + uint32_t wr_count = 0; + uint32_t msg_type = 0; + uint32_t max_count = 0; + int len = 0; + + wr_count = stream_fifo_count_safe(zrouter.mlag_info.mlag_fifo); + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug(":%s: Processing MLAG write, %u messages in queue", + __func__, wr_count); + + max_count = MIN(wr_count, ZEBRA_MLAG_POST_LIMIT); + + for (wr_count = 0; wr_count < max_count; wr_count++) { + s = stream_fifo_pop_safe(zrouter.mlag_info.mlag_fifo); + if (!s) { + zlog_debug(":%s: Got a NULL Messages, some thing wrong", + __func__); + break; + } + + /* + * Encode the data now + */ + len = zebra_mlag_protobuf_encode_client_data(s, &msg_type); + + /* + * write to MCLAGD + */ + if (len > 0) { + zebra_mlag_private_write_data(mlag_wr_buffer, len); + + /* + * If message type is De-register, send a signal to main + * thread, so that necessary cleanup will be done by + * main thread. + */ + if (msg_type == MLAG_DEREGISTER) { + thread_add_event(zrouter.master, + zebra_mlag_terminate_pthread, + NULL, 0, NULL); + } + } + + stream_free(s); + } + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug(":%s: Posted %d messages to MLAGD", __func__, + wr_count); + /* + * Currently there is only message write task is enqueued to this + * thread, yielding was added for future purpose, so that this thread + * can server other tasks also and in case FIFO is empty, this task will + * be schedule when main thread adds some messages + */ + if (wr_count >= ZEBRA_MLAG_POST_LIMIT) + zebra_mlag_signal_write_thread(); + return 0; +} + +/* + * API to handle the process state. + * In case of Down, Zebra keep monitoring the MLAG state. + * all the state Notifications will be published to clients + */ +void zebra_mlag_handle_process_state(enum zebra_mlag_state state) +{ + if (state == MLAG_UP) { + zrouter.mlag_info.connected = true; + zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_UP); + zebra_mlag_send_register(); + } else if (state == MLAG_DOWN) { + zrouter.mlag_info.connected = false; + zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_DOWN); + zebra_mlag_private_monitor_state(); + } +} + +/***********************End of MLAG Thread processing*************************/ + +/*************************Multi-entratnt Api's********************************/ + +/* + * Provider api to signal that work/events are available + * for the Zebra MLAG Write pthread. + * This API is called from 2 pthreads.. + * 1) by main thread when client posts a MLAG Message + * 2) by MLAG Thread, in case of yield + * though this api, is called from two threads we don't need any locking + * because Thread task enqueue is thread safe means internally it had + * necessary protection + */ +static int zebra_mlag_signal_write_thread(void) +{ + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug(":%s: Scheduling MLAG write", __func__); + /* + * This api will be called from Both main & MLAG Threads. + * main thread writes, "zrouter.mlag_info.th_master" only + * during Zebra Init/after MLAG thread is destroyed. + * so it is safe to use without any locking + */ + thread_add_event(zrouter.mlag_info.th_master, + zebra_mlag_client_msg_handler, NULL, 0, + &zrouter.mlag_info.t_write); + return 0; +} + +/* + * API will be used to publish the MLAG state to interested clients + * In case client is passed, state is posted only for that client, + * otherwise to all interested clients + * this api can be called from two threads. + * 1) from main thread: when client is passed + * 2) from MLAG Thread: when client is NULL + * + * In second case, to avoid global data access data will be post to Main + * thread, so that actual posting to clients will happen from Main thread. + */ +static void zebra_mlag_publish_process_state(struct zserv *client, + zebra_message_types_t msg_type) +{ + struct stream *s; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Publishing MLAG process state:%s to %s Client", + __func__, + (msg_type == ZEBRA_MLAG_PROCESS_UP) ? "UP" : "DOWN", + (client) ? "one" : "all"); + + if (client) { + s = stream_new(ZEBRA_HEADER_SIZE); + zclient_create_header(s, msg_type, VRF_DEFAULT); + zserv_send_message(client, s); + return; + } + + + /* + * additional four bytes are for mesasge type + */ + s = stream_new(ZEBRA_HEADER_SIZE + ZEBRA_MLAG_METADATA_LEN); + stream_putl(s, ZEBRA_MLAG_MSG_BCAST); + zclient_create_header(s, msg_type, VRF_DEFAULT); + thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread, + s, 0, NULL); +} + +/**************************End of Multi-entrant Apis**************************/ + +/***********************Zebra Main thread processing**************************/ + +/* + * To avoid data corruption, messages will be post to clients only from + * main thread, because for that access was needed for clients list. + * so instead of forcing the locks, messages will be posted from main thread. + */ +static int zebra_mlag_post_data_from_main_thread(struct thread *thread) +{ + struct stream *s = THREAD_ARG(thread); + struct stream *zebra_s = NULL; + struct listnode *node; + struct zserv *client; + uint32_t msg_type = 0; + uint32_t msg_len = 0; + + if (!s) + return -1; + + STREAM_GETL(s, msg_type); + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "%s: Posting MLAG data for msg_type:0x%x to interested cleints", + __func__, msg_type); + + msg_len = s->endp - ZEBRA_MLAG_METADATA_LEN; + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { + if (client->mlag_updates_interested == true) { + if (msg_type != ZEBRA_MLAG_MSG_BCAST + && !CHECK_FLAG(client->mlag_reg_mask1, + (1 << msg_type))) { + continue; + } + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "%s: Posting MLAG data of length-%d to client:%d ", + __func__, msg_len, client->proto); + + zebra_s = stream_new(msg_len); + STREAM_GET(zebra_s->data, s, msg_len); + zebra_s->endp = msg_len; + stream_putw_at(zebra_s, 0, msg_len); + + /* + * This stream will be enqueued to client_obuf, it will + * be freed after posting to client socket. + */ + zserv_send_message(client, zebra_s); + zebra_s = NULL; + } + } + + stream_free(s); + return 0; +stream_failure: + stream_free(s); + if (zebra_s) + stream_free(zebra_s); + return 0; +} + +/* + * Start the MLAG Thread, this will be used to write client data on to + * MLAG Process and to read the data from MLAG and post to cleints. + * when all clients are un-registered, this Thread will be + * suspended. + */ +static void zebra_mlag_spawn_pthread(void) +{ + /* Start MLAG write pthread */ + + struct frr_pthread_attr pattr = {.start = + frr_pthread_attr_default.start, + .stop = frr_pthread_attr_default.stop}; + + zrouter.mlag_info.zebra_pth_mlag = + frr_pthread_new(&pattr, "Zebra MLAG thread", "Zebra MLAG"); + + zrouter.mlag_info.th_master = zrouter.mlag_info.zebra_pth_mlag->master; + + + /* Enqueue an initial event to the Newly spawn MLAG pthread */ + zebra_mlag_signal_write_thread(); + + frr_pthread_run(zrouter.mlag_info.zebra_pth_mlag, NULL); +} + +/* + * all clients are un-registered for MLAG Updates, terminate the + * MLAG write thread + */ +static int zebra_mlag_terminate_pthread(struct thread *event) +{ + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Zebra MLAG write thread terminate called"); + + if (zrouter.mlag_info.clients_interested_cnt) { + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "Zebra MLAG: still some clients are interested"); + return 0; + } + + frr_pthread_stop(zrouter.mlag_info.zebra_pth_mlag, NULL); + + /* Destroy pthread */ + frr_pthread_destroy(zrouter.mlag_info.zebra_pth_mlag); + zrouter.mlag_info.zebra_pth_mlag = NULL; + zrouter.mlag_info.th_master = NULL; + zrouter.mlag_info.t_read = NULL; + zrouter.mlag_info.t_write = NULL; + + /* + * Send Notification to clean private data + */ + zebra_mlag_private_cleanup_data(); + return 0; +} + +/* + * API to register zebra client for MLAG Updates + */ +void zebra_mlag_client_register(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + uint32_t reg_mask = 0; + int rc = 0; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Received MLAG Registration from client-proto:%d", + client->proto); + + + /* Get input stream. */ + s = msg; + + /* Get data. */ + STREAM_GETL(s, reg_mask); + + if (client->mlag_updates_interested == true) { + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "Client is registered, existing mask: 0x%x, new mask: 0x%x", + client->mlag_reg_mask1, reg_mask); + if (client->mlag_reg_mask1 != reg_mask) + client->mlag_reg_mask1 = reg_mask; + /* + * Client might missed MLAG-UP Notification, post-it again + */ + zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP); + return; + } + + + client->mlag_updates_interested = true; + client->mlag_reg_mask1 = reg_mask; + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Registering for MLAG Updates with mask: 0x%x, ", + client->mlag_reg_mask1); + + zrouter.mlag_info.clients_interested_cnt++; + + if (zrouter.mlag_info.clients_interested_cnt == 1) { + /* + * First-client for MLAG Updates,open the communication channel + * with MLAG + */ + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "First client, opening the channel with MLAG"); + + zebra_mlag_spawn_pthread(); + rc = zebra_mlag_private_open_channel(); + if (rc < 0) { + /* + * For some reason, zebra not able to open the + * comm-channel with MLAG, so post MLAG-DOWN to client. + * later when the channel is open, zebra will send + * MLAG-UP + */ + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "Fail to open channel with MLAG,rc:%d, post Proto-down", + rc); + zebra_mlag_publish_process_state( + client, ZEBRA_MLAG_PROCESS_DOWN); + } + } + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Client Registered successfully for MLAG Updates"); + + if (zrouter.mlag_info.connected == true) + zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP); +stream_failure: + return; +} + +/* + * API to un-register for MLAG Updates + */ +void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS) +{ + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Received MLAG De-Registration from client-proto:%d", + client->proto); + + if (client->mlag_updates_interested == false) + /* Unexpected */ + return; + + client->mlag_updates_interested = false; + client->mlag_reg_mask1 = 0; + zrouter.mlag_info.clients_interested_cnt--; + + if (zrouter.mlag_info.clients_interested_cnt == 0) { + /* + * No-client is interested for MLAG Updates,close the + * communication channel with MLAG + */ + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Last client for MLAG, close the channel "); + + /* + * Clean up flow: + * ============= + * 1) main thread calls socket close which posts De-register + * to MLAG write thread + * 2) after MLAG write thread posts De-register it sends a + * signal back to main thread to do the thread cleanup + * this was mainly to make sure De-register is posted to MCLAGD. + */ + zebra_mlag_private_close_channel(); + } + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "Client De-Registered successfully for MLAG Updates"); +} + +/* + * Does following things. + * 1) allocated new local stream, and copies the client data and enqueue + * to MLAG Thread + * 2) MLAG Thread after dequeing, encode the client data using protobuf + * and write on to MLAG + */ +void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS) +{ + struct stream *zebra_s; + struct stream *mlag_s; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("Received Client MLAG Data from client-proto:%d", + client->proto); + + /* Get input stream. */ + zebra_s = msg; + mlag_s = stream_new(zebra_s->endp); + + /* + * Client data is | Zebra Header + MLAG Data | + * we need to enqueue only the MLAG data, skipping Zebra Header + */ + stream_put(mlag_s, zebra_s->data + zebra_s->getp, + STREAM_READABLE(zebra_s)); + stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, mlag_s); + zebra_mlag_signal_write_thread(); + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ", + __func__, client->proto); +} + +/***********************End of Zebra Main thread processing*************/ + enum mlag_role zebra_mlag_get_role(void) { return zrouter.mlag_info.role; @@ -45,7 +586,7 @@ DEFUN_HIDDEN (show_mlag, ZEBRA_STR "The mlag role on this machine\n") { - char buf[80]; + char buf[MLAG_ROLE_STRSIZE]; vty_out(vty, "MLag is configured to: %s\n", mlag_role2str(zrouter.mlag_info.role, buf, sizeof(buf))); @@ -53,18 +594,17 @@ DEFUN_HIDDEN (show_mlag, return CMD_SUCCESS; } -DEFPY_HIDDEN (test_mlag, - test_mlag_cmd, - "test zebra mlag <none$none|primary$primary|secondary$secondary>", - "Test code\n" - ZEBRA_STR - "Modify the Mlag state\n" - "Mlag is not setup on the machine\n" - "Mlag is setup to be primary\n" - "Mlag is setup to be the secondary\n") +DEFPY_HIDDEN(test_mlag, test_mlag_cmd, + "test zebra mlag <none$none|primary$primary|secondary$secondary>", + "Test code\n" + ZEBRA_STR + "Modify the Mlag state\n" + "Mlag is not setup on the machine\n" + "Mlag is setup to be primary\n" + "Mlag is setup to be the secondary\n") { enum mlag_role orig = zrouter.mlag_info.role; - char buf1[80], buf2[80]; + char buf1[MLAG_ROLE_STRSIZE], buf2[MLAG_ROLE_STRSIZE]; if (none) zrouter.mlag_info.role = MLAG_ROLE_NONE; @@ -78,8 +618,25 @@ DEFPY_HIDDEN (test_mlag, mlag_role2str(orig, buf1, sizeof(buf1)), mlag_role2str(orig, buf2, sizeof(buf2))); - if (orig != zrouter.mlag_info.role) + if (orig != zrouter.mlag_info.role) { zsend_capabilities_all_clients(); + if (zrouter.mlag_info.role != MLAG_ROLE_NONE) { + if (zrouter.mlag_info.clients_interested_cnt == 0 + && test_mlag_in_progress == false) { + if (zrouter.mlag_info.zebra_pth_mlag == NULL) + zebra_mlag_spawn_pthread(); + zrouter.mlag_info.clients_interested_cnt++; + test_mlag_in_progress = true; + zebra_mlag_private_open_channel(); + } + } else { + if (test_mlag_in_progress == true) { + test_mlag_in_progress = false; + zrouter.mlag_info.clients_interested_cnt--; + zebra_mlag_private_close_channel(); + } + } + } return CMD_SUCCESS; } @@ -88,8 +645,539 @@ void zebra_mlag_init(void) { install_element(VIEW_NODE, &show_mlag_cmd); install_element(ENABLE_NODE, &test_mlag_cmd); + + /* + * Intialiaze the MLAG Global variables + * write thread will be created during actual registration with MCLAG + */ + zrouter.mlag_info.clients_interested_cnt = 0; + zrouter.mlag_info.connected = false; + zrouter.mlag_info.timer_running = false; + zrouter.mlag_info.mlag_fifo = stream_fifo_new(); + zrouter.mlag_info.zebra_pth_mlag = NULL; + zrouter.mlag_info.th_master = NULL; + zrouter.mlag_info.t_read = NULL; + zrouter.mlag_info.t_write = NULL; + test_mlag_in_progress = false; + zebra_mlag_reset_read_buffer(); } void zebra_mlag_terminate(void) { } + + +/* + * + * ProtoBuf Encoding APIs + */ + +#ifdef HAVE_PROTOBUF + +DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF") + +int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type) +{ + ZebraMlagHeader hdr = ZEBRA_MLAG__HEADER__INIT; + struct mlag_msg mlag_msg; + uint8_t tmp_buf[ZEBRA_MLAG_BUF_LIMIT]; + int len = 0; + int n_len = 0; + int rc = 0; + char buf[ZLOG_FILTER_LENGTH_MAX]; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Entering..", __func__); + + rc = mlag_lib_decode_mlag_hdr(s, &mlag_msg); + if (rc) + return rc; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d", + __func__, + mlag_lib_msgid_to_str(mlag_msg.msg_type, buf, + sizeof(buf)), + mlag_msg.data_len); + *msg_type = mlag_msg.msg_type; + switch (mlag_msg.msg_type) { + case MLAG_MROUTE_ADD: { + struct mlag_mroute_add msg; + ZebraMlagMrouteAdd pay_load = ZEBRA_MLAG_MROUTE_ADD__INIT; + uint32_t vrf_name_len = 0; + + rc = mlag_lib_decode_mroute_add(s, &msg); + if (rc) + return rc; + vrf_name_len = strlen(msg.vrf_name) + 1; + pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len); + pay_load.source_ip = msg.source_ip; + pay_load.group_ip = msg.group_ip; + pay_load.cost_to_rp = msg.cost_to_rp; + pay_load.owner_id = msg.owner_id; + pay_load.am_i_dr = msg.am_i_dr; + pay_load.am_i_dual_active = msg.am_i_dual_active; + pay_load.vrf_id = msg.vrf_id; + + if (msg.owner_id == MLAG_OWNER_INTERFACE) { + vrf_name_len = strlen(msg.intf_name) + 1; + pay_load.intf_name = + XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + strlcpy(pay_load.intf_name, msg.intf_name, + vrf_name_len); + } + + len = zebra_mlag_mroute_add__pack(&pay_load, tmp_buf); + XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name); + if (msg.owner_id == MLAG_OWNER_INTERFACE) + XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name); + } break; + case MLAG_MROUTE_DEL: { + struct mlag_mroute_del msg; + ZebraMlagMrouteDel pay_load = ZEBRA_MLAG_MROUTE_DEL__INIT; + uint32_t vrf_name_len = 0; + + rc = mlag_lib_decode_mroute_del(s, &msg); + if (rc) + return rc; + vrf_name_len = strlen(msg.vrf_name) + 1; + pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len); + pay_load.source_ip = msg.source_ip; + pay_load.group_ip = msg.group_ip; + pay_load.owner_id = msg.owner_id; + pay_load.vrf_id = msg.vrf_id; + + if (msg.owner_id == MLAG_OWNER_INTERFACE) { + vrf_name_len = strlen(msg.intf_name) + 1; + pay_load.intf_name = + XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + strlcpy(pay_load.intf_name, msg.intf_name, + vrf_name_len); + } + + len = zebra_mlag_mroute_del__pack(&pay_load, tmp_buf); + XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name); + if (msg.owner_id == MLAG_OWNER_INTERFACE) + XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name); + } break; + case MLAG_MROUTE_ADD_BULK: { + struct mlag_mroute_add msg; + ZebraMlagMrouteAddBulk Bulk_msg = + ZEBRA_MLAG_MROUTE_ADD_BULK__INIT; + ZebraMlagMrouteAdd **pay_load = NULL; + int i; + bool cleanup = false; + + Bulk_msg.n_mroute_add = mlag_msg.msg_cnt; + pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteAdd *) + * mlag_msg.msg_cnt); + + for (i = 0; i < mlag_msg.msg_cnt; i++) { + + uint32_t vrf_name_len = 0; + + rc = mlag_lib_decode_mroute_add(s, &msg); + if (rc) { + cleanup = true; + break; + } + pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF, + sizeof(ZebraMlagMrouteAdd)); + zebra_mlag_mroute_add__init(pay_load[i]); + + vrf_name_len = strlen(msg.vrf_name) + 1; + pay_load[i]->vrf_name = + XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + strlcpy(pay_load[i]->vrf_name, msg.vrf_name, + vrf_name_len); + pay_load[i]->source_ip = msg.source_ip; + pay_load[i]->group_ip = msg.group_ip; + pay_load[i]->cost_to_rp = msg.cost_to_rp; + pay_load[i]->owner_id = msg.owner_id; + pay_load[i]->am_i_dr = msg.am_i_dr; + pay_load[i]->am_i_dual_active = msg.am_i_dual_active; + pay_load[i]->vrf_id = msg.vrf_id; + if (msg.owner_id == MLAG_OWNER_INTERFACE) { + vrf_name_len = strlen(msg.intf_name) + 1; + pay_load[i]->intf_name = + XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + + strlcpy(pay_load[i]->intf_name, msg.intf_name, + vrf_name_len); + } + } + if (cleanup == false) { + Bulk_msg.mroute_add = pay_load; + len = zebra_mlag_mroute_add_bulk__pack(&Bulk_msg, + tmp_buf); + } + + for (i = 0; i < mlag_msg.msg_cnt; i++) { + if (pay_load[i]->vrf_name) + XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name); + if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE + && pay_load[i]->intf_name) + XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name); + if (pay_load[i]) + XFREE(MTYPE_MLAG_PBUF, pay_load[i]); + } + XFREE(MTYPE_MLAG_PBUF, pay_load); + if (cleanup == true) + return -1; + } break; + case MLAG_MROUTE_DEL_BULK: { + struct mlag_mroute_del msg; + ZebraMlagMrouteDelBulk Bulk_msg = + ZEBRA_MLAG_MROUTE_DEL_BULK__INIT; + ZebraMlagMrouteDel **pay_load = NULL; + int i; + bool cleanup = false; + + Bulk_msg.n_mroute_del = mlag_msg.msg_cnt; + pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteDel *) + * mlag_msg.msg_cnt); + + for (i = 0; i < mlag_msg.msg_cnt; i++) { + + uint32_t vrf_name_len = 0; + + rc = mlag_lib_decode_mroute_del(s, &msg); + if (rc) { + cleanup = true; + break; + } + + pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF, + sizeof(ZebraMlagMrouteDel)); + zebra_mlag_mroute_del__init(pay_load[i]); + + vrf_name_len = strlen(msg.vrf_name) + 1; + pay_load[i]->vrf_name = + XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + + strlcpy(pay_load[i]->vrf_name, msg.vrf_name, + vrf_name_len); + pay_load[i]->source_ip = msg.source_ip; + pay_load[i]->group_ip = msg.group_ip; + pay_load[i]->owner_id = msg.owner_id; + pay_load[i]->vrf_id = msg.vrf_id; + if (msg.owner_id == MLAG_OWNER_INTERFACE) { + vrf_name_len = strlen(msg.intf_name) + 1; + pay_load[i]->intf_name = + XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len); + + strlcpy(pay_load[i]->intf_name, msg.intf_name, + vrf_name_len); + } + } + if (!cleanup) { + Bulk_msg.mroute_del = pay_load; + len = zebra_mlag_mroute_del_bulk__pack(&Bulk_msg, + tmp_buf); + } + + for (i = 0; i < mlag_msg.msg_cnt; i++) { + if (pay_load[i]->vrf_name) + XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name); + if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE + && pay_load[i]->intf_name) + XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name); + if (pay_load[i]) + XFREE(MTYPE_MLAG_PBUF, pay_load[i]); + } + XFREE(MTYPE_MLAG_PBUF, pay_load); + if (cleanup) + return -1; + } break; + default: + break; + } + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d", + __func__, + mlag_lib_msgid_to_str(mlag_msg.msg_type, buf, + sizeof(buf)), + len); + hdr.type = (ZebraMlagHeader__MessageType)mlag_msg.msg_type; + if (len != 0) { + hdr.data.len = len; + hdr.data.data = XMALLOC(MTYPE_MLAG_PBUF, len); + memcpy(hdr.data.data, tmp_buf, len); + } + + /* + * ProtoBuf Infra will not support to demarc the pointers whem multiple + * messages are posted inside a single Buffer. + * 2 -solutions exist to solve this + * 1. add Unenoced length at the beginning of every message, this will + * be used to point to next message in the buffer + * 2. another solution is defining all messages insides another message + * But this will permit only 32 messages. this can be extended with + * multiple levels. + * for simplicity we are going with solution-1. + */ + len = zebra_mlag__header__pack(&hdr, + (mlag_wr_buffer + ZEBRA_MLAG_LEN_SIZE)); + n_len = htonl(len); + memcpy(mlag_wr_buffer, &n_len, ZEBRA_MLAG_LEN_SIZE); + len += ZEBRA_MLAG_LEN_SIZE; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "%s: length of Mlag ProtoBuf message:%s with Header %d", + __func__, + mlag_lib_msgid_to_str(mlag_msg.msg_type, buf, + sizeof(buf)), + len); + if (hdr.data.data) + XFREE(MTYPE_MLAG_PBUF, hdr.data.data); + + return len; +} + +int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, + uint32_t len) +{ + uint32_t msg_type; + ZebraMlagHeader *hdr; + char buf[80]; + + hdr = zebra_mlag__header__unpack(NULL, len, data); + if (hdr == NULL) + return -1; + + /* + * ADD The MLAG Header + */ + zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT); + + msg_type = hdr->type; + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__, + mlag_lib_msgid_to_str(msg_type, buf, 80)); + + /* + * Internal MLAG Message-types & MLAG.proto message types should + * always match, otherwise there can be decoding errors + * To avoid exposing clients with Protobuf flags, using internal + * message-types + */ + stream_putl(s, hdr->type); + + if (hdr->data.len == 0) { + /* NULL Payload */ + stream_putw(s, MLAG_MSG_NULL_PAYLOAD); + /* No Batching */ + stream_putw(s, MLAG_MSG_NO_BATCH); + } else { + switch (msg_type) { + case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE: { + ZebraMlagStatusUpdate *msg = NULL; + + msg = zebra_mlag_status_update__unpack( + NULL, hdr->data.len, hdr->data.data); + if (msg == NULL) { + zebra_mlag__header__free_unpacked(hdr, NULL); + return -1; + } + /* Payload len */ + stream_putw(s, sizeof(struct mlag_status)); + /* No Batching */ + stream_putw(s, MLAG_MSG_NO_BATCH); + /* Actual Data */ + stream_put(s, msg->peerlink, INTERFACE_NAMSIZ); + stream_putl(s, msg->my_role); + stream_putl(s, msg->peer_state); + zebra_mlag_status_update__free_unpacked(msg, NULL); + } break; + case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE: { + ZebraMlagVxlanUpdate *msg = NULL; + + msg = zebra_mlag_vxlan_update__unpack( + NULL, hdr->data.len, hdr->data.data); + if (msg == NULL) { + zebra_mlag__header__free_unpacked(hdr, NULL); + return -1; + } + /* Payload len */ + stream_putw(s, sizeof(struct mlag_vxlan)); + /* No Batching */ + stream_putw(s, MLAG_MSG_NO_BATCH); + /* Actual Data */ + stream_putl(s, msg->anycast_ip); + stream_putl(s, msg->local_ip); + zebra_mlag_vxlan_update__free_unpacked(msg, NULL); + } break; + case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD: { + ZebraMlagMrouteAdd *msg = NULL; + + msg = zebra_mlag_mroute_add__unpack(NULL, hdr->data.len, + hdr->data.data); + if (msg == NULL) { + zebra_mlag__header__free_unpacked(hdr, NULL); + return -1; + } + /* Payload len */ + stream_putw(s, sizeof(struct mlag_mroute_add)); + /* No Batching */ + stream_putw(s, MLAG_MSG_NO_BATCH); + /* Actual Data */ + stream_put(s, msg->vrf_name, VRF_NAMSIZ); + + stream_putl(s, msg->source_ip); + stream_putl(s, msg->group_ip); + stream_putl(s, msg->cost_to_rp); + stream_putl(s, msg->owner_id); + stream_putc(s, msg->am_i_dr); + stream_putc(s, msg->am_i_dual_active); + stream_putl(s, msg->vrf_id); + if (msg->owner_id == MLAG_OWNER_INTERFACE) + stream_put(s, msg->intf_name, INTERFACE_NAMSIZ); + else + stream_put(s, NULL, INTERFACE_NAMSIZ); + zebra_mlag_mroute_add__free_unpacked(msg, NULL); + } break; + case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL: { + ZebraMlagMrouteDel *msg = NULL; + + msg = zebra_mlag_mroute_del__unpack(NULL, hdr->data.len, + hdr->data.data); + if (msg == NULL) { + zebra_mlag__header__free_unpacked(hdr, NULL); + return -1; + } + /* Payload len */ + stream_putw(s, sizeof(struct mlag_mroute_del)); + /* No Batching */ + stream_putw(s, MLAG_MSG_NO_BATCH); + /* Actual Data */ + stream_put(s, msg->vrf_name, VRF_NAMSIZ); + + stream_putl(s, msg->source_ip); + stream_putl(s, msg->group_ip); + stream_putl(s, msg->group_ip); + stream_putl(s, msg->owner_id); + stream_putl(s, msg->vrf_id); + if (msg->owner_id == MLAG_OWNER_INTERFACE) + stream_put(s, msg->intf_name, INTERFACE_NAMSIZ); + else + stream_put(s, NULL, INTERFACE_NAMSIZ); + zebra_mlag_mroute_del__free_unpacked(msg, NULL); + } break; + case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: { + ZebraMlagMrouteAddBulk *Bulk_msg = NULL; + ZebraMlagMrouteAdd *msg = NULL; + size_t i; + + Bulk_msg = zebra_mlag_mroute_add_bulk__unpack( + NULL, hdr->data.len, hdr->data.data); + if (Bulk_msg == NULL) { + zebra_mlag__header__free_unpacked(hdr, NULL); + return -1; + } + /* Payload len */ + stream_putw(s, (Bulk_msg->n_mroute_add + * sizeof(struct mlag_mroute_add))); + /* No. of msgs in Batch */ + stream_putw(s, Bulk_msg->n_mroute_add); + + /* Actual Data */ + for (i = 0; i < Bulk_msg->n_mroute_add; i++) { + + msg = Bulk_msg->mroute_add[i]; + + stream_put(s, msg->vrf_name, VRF_NAMSIZ); + stream_putl(s, msg->source_ip); + stream_putl(s, msg->group_ip); + stream_putl(s, msg->cost_to_rp); + stream_putl(s, msg->owner_id); + stream_putc(s, msg->am_i_dr); + stream_putc(s, msg->am_i_dual_active); + stream_putl(s, msg->vrf_id); + if (msg->owner_id == MLAG_OWNER_INTERFACE) + stream_put(s, msg->intf_name, + INTERFACE_NAMSIZ); + else + stream_put(s, NULL, INTERFACE_NAMSIZ); + } + zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg, + NULL); + } break; + case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK: { + ZebraMlagMrouteDelBulk *Bulk_msg = NULL; + ZebraMlagMrouteDel *msg = NULL; + size_t i; + + Bulk_msg = zebra_mlag_mroute_del_bulk__unpack( + NULL, hdr->data.len, hdr->data.data); + if (Bulk_msg == NULL) { + zebra_mlag__header__free_unpacked(hdr, NULL); + return -1; + } + /* Payload len */ + stream_putw(s, (Bulk_msg->n_mroute_del + * sizeof(struct mlag_mroute_del))); + /* No. of msgs in Batch */ + stream_putw(s, Bulk_msg->n_mroute_del); + + /* Actual Data */ + for (i = 0; i < Bulk_msg->n_mroute_del; i++) { + + msg = Bulk_msg->mroute_del[i]; + + stream_put(s, msg->vrf_name, VRF_NAMSIZ); + stream_putl(s, msg->source_ip); + stream_putl(s, msg->group_ip); + stream_putl(s, msg->owner_id); + stream_putl(s, msg->vrf_id); + if (msg->owner_id == MLAG_OWNER_INTERFACE) + stream_put(s, msg->intf_name, + INTERFACE_NAMSIZ); + else + stream_put(s, NULL, INTERFACE_NAMSIZ); + } + zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg, + NULL); + } break; + case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE: { + ZebraMlagZebraStatusUpdate *msg = NULL; + + msg = zebra_mlag_zebra_status_update__unpack( + NULL, hdr->data.len, hdr->data.data); + if (msg == NULL) { + zebra_mlag__header__free_unpacked(hdr, NULL); + return -1; + } + /* Payload len */ + stream_putw(s, sizeof(struct mlag_frr_status)); + /* No Batching */ + stream_putw(s, MLAG_MSG_NO_BATCH); + /* Actual Data */ + stream_putl(s, msg->peer_frrstate); + zebra_mlag_zebra_status_update__free_unpacked(msg, + NULL); + } break; + default: + break; + } + } + zebra_mlag__header__free_unpacked(hdr, NULL); + return msg_type; +} + +#else +int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type) +{ + return 0; +} + +int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, + uint32_t len) +{ + return 0; +} +#endif diff --git a/zebra/zebra_mlag.h b/zebra/zebra_mlag.h index 90a5a41fa4..6f7ef8319f 100644 --- a/zebra/zebra_mlag.h +++ b/zebra/zebra_mlag.h @@ -23,18 +23,45 @@ #define __ZEBRA_MLAG_H__ #include "mlag.h" +#include "zclient.h" +#include "zebra/zserv.h" -#ifdef __cplusplus -extern "C" { +#ifdef HAVE_PROTOBUF +#include "mlag/mlag.pb-c.h" #endif -void zebra_mlag_init(void); -void zebra_mlag_terminate(void); +#define ZEBRA_MLAG_BUF_LIMIT 2048 +#define ZEBRA_MLAG_LEN_SIZE 4 -enum mlag_role zebra_mlag_get_role(void); +extern uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT]; +extern uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT]; +extern uint32_t mlag_rd_buf_offset; -#ifdef __cplusplus +static inline void zebra_mlag_reset_read_buffer(void) +{ + mlag_rd_buf_offset = 0; } -#endif +enum zebra_mlag_state { + MLAG_UP = 1, + MLAG_DOWN = 2, +}; + +void zebra_mlag_init(void); +void zebra_mlag_terminate(void); +enum mlag_role zebra_mlag_get_role(void); +void zebra_mlag_client_register(ZAPI_HANDLER_ARGS); +void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS); +void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS); +void zebra_mlag_send_register(void); +void zebra_mlag_send_deregister(void); +void zebra_mlag_handle_process_state(enum zebra_mlag_state state); +void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len); +/* + * ProtoBuffer Api's + */ +int zebra_mlag_protobuf_encode_client_data(struct stream *s, + uint32_t *msg_type); +int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, + uint32_t len); #endif diff --git a/zebra/zebra_mlag_private.c b/zebra/zebra_mlag_private.c new file mode 100644 index 0000000000..4df7b6dd11 --- /dev/null +++ b/zebra/zebra_mlag_private.c @@ -0,0 +1,299 @@ +/* + * This is an implementation of MLAG Functionality + * + * Module name: Zebra MLAG + * + * Author: sathesh Kumar karra <sathk@cumulusnetworks.com> + * + * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program 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 "hook.h" +#include "module.h" +#include "thread.h" +#include "frr_pthread.h" +#include "libfrr.h" +#include "version.h" +#include "network.h" + +#include "lib/stream.h" + +#include "zebra/debug.h" +#include "zebra/zebra_router.h" +#include "zebra/zebra_mlag.h" +#include "zebra/zebra_mlag_private.h" + +#include <sys/un.h> + + +/* + * This file will have platform specific apis to communicate with MCLAG. + * + */ + +#ifdef HAVE_CUMULUS + +static struct thread_master *zmlag_master; +static int mlag_socket; + +static int zebra_mlag_connect(struct thread *thread); +static int zebra_mlag_read(struct thread *thread); + +/* + * Write the data to MLAGD + */ +int zebra_mlag_private_write_data(uint8_t *data, uint32_t len) +{ + int rc = 0; + + if (IS_ZEBRA_DEBUG_MLAG) { + zlog_debug("%s: Writing %d length Data to clag", __func__, len); + zlog_hexdump(data, len); + } + rc = write(mlag_socket, data, len); + return rc; +} + +static void zebra_mlag_sched_read(void) +{ + thread_add_read(zmlag_master, zebra_mlag_read, NULL, mlag_socket, + &zrouter.mlag_info.t_read); +} + +static int zebra_mlag_read(struct thread *thread) +{ + uint32_t *msglen; + uint32_t h_msglen; + uint32_t tot_len, curr_len = mlag_rd_buf_offset; + + /* + * Received message in sock_stream looks like below + * | len-1 (4 Bytes) | payload-1 (len-1) | + * len-2 (4 Bytes) | payload-2 (len-2) | .. + * + * Idea is read one message completely, then process, until message is + * read completely, keep on reading from the socket + */ + if (curr_len < ZEBRA_MLAG_LEN_SIZE) { + ssize_t data_len; + + data_len = read(mlag_socket, mlag_rd_buffer + curr_len, + ZEBRA_MLAG_LEN_SIZE - curr_len); + if (data_len == 0 || data_len == -1) { + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("MLAG connection closed socket : %d", + mlag_socket); + close(mlag_socket); + zebra_mlag_handle_process_state(MLAG_DOWN); + return -1; + } + mlag_rd_buf_offset += data_len; + if (data_len != (ssize_t)ZEBRA_MLAG_LEN_SIZE - curr_len) { + /* Try again later */ + zebra_mlag_sched_read(); + return 0; + } + curr_len = ZEBRA_MLAG_LEN_SIZE; + } + + /* Get the actual packet length */ + msglen = (uint32_t *)mlag_rd_buffer; + h_msglen = ntohl(*msglen); + + /* This will be the actual length of the packet */ + tot_len = h_msglen + ZEBRA_MLAG_LEN_SIZE; + + if (curr_len < tot_len) { + ssize_t data_len; + + data_len = read(mlag_socket, mlag_rd_buffer + curr_len, + tot_len - curr_len); + if (data_len == 0 || data_len == -1) { + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("MLAG connection closed socket : %d", + mlag_socket); + close(mlag_socket); + zebra_mlag_handle_process_state(MLAG_DOWN); + return -1; + } + mlag_rd_buf_offset += data_len; + if (data_len != (ssize_t)tot_len - curr_len) { + /* Try again later */ + zebra_mlag_sched_read(); + return 0; + } + } + + if (IS_ZEBRA_DEBUG_MLAG) { + zlog_debug("Received a MLAG Message from socket: %d, len:%u ", + mlag_socket, tot_len); + zlog_hexdump(mlag_rd_buffer, tot_len); + } + + tot_len -= ZEBRA_MLAG_LEN_SIZE; + + /* Process the packet */ + zebra_mlag_process_mlag_data(mlag_rd_buffer + ZEBRA_MLAG_LEN_SIZE, + tot_len); + + /* Register read thread. */ + zebra_mlag_reset_read_buffer(); + zebra_mlag_sched_read(); + return 0; +} + +static int zebra_mlag_connect(struct thread *thread) +{ + struct sockaddr_un svr = {0}; + struct ucred ucred; + socklen_t len = 0; + + /* Reset the Timer-running flag */ + zrouter.mlag_info.timer_running = false; + + svr.sun_family = AF_UNIX; +#define MLAG_SOCK_NAME "/var/run/clag-zebra.socket" + strlcpy(svr.sun_path, MLAG_SOCK_NAME, sizeof(MLAG_SOCK_NAME) + 1); + + mlag_socket = socket(svr.sun_family, SOCK_STREAM, 0); + if (mlag_socket < 0) + return -1; + + if (connect(mlag_socket, (struct sockaddr *)&svr, sizeof(svr)) == -1) { + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "Unable to connect to %s try again in 10 secs", + svr.sun_path); + close(mlag_socket); + zrouter.mlag_info.timer_running = true; + thread_add_timer(zmlag_master, zebra_mlag_connect, NULL, 10, + &zrouter.mlag_info.t_read); + return 0; + } + len = sizeof(struct ucred); + ucred.pid = getpid(); + + set_nonblocking(mlag_socket); + setsockopt(mlag_socket, SOL_SOCKET, SO_PEERCRED, &ucred, len); + + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Connection with MLAG is established ", + __func__); + + thread_add_read(zmlag_master, zebra_mlag_read, NULL, mlag_socket, + &zrouter.mlag_info.t_read); + /* + * Connection is established with MLAGD, post to clients + */ + zebra_mlag_handle_process_state(MLAG_UP); + return 0; +} + +/* + * Currently we are doing polling later we will look for better options + */ +void zebra_mlag_private_monitor_state(void) +{ + thread_add_event(zmlag_master, zebra_mlag_connect, NULL, 0, + &zrouter.mlag_info.t_read); +} + +int zebra_mlag_private_open_channel(void) +{ + zmlag_master = zrouter.mlag_info.th_master; + + if (zrouter.mlag_info.connected == true) { + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: Zebra already connected to MLAGD", + __func__); + return 0; + } + + if (zrouter.mlag_info.timer_running == true) { + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug( + "%s: Connection retry is in progress for MLAGD", + __func__); + return 0; + } + + if (zrouter.mlag_info.clients_interested_cnt) { + /* + * Connect only if any clients are showing interest + */ + thread_add_event(zmlag_master, zebra_mlag_connect, NULL, 0, + &zrouter.mlag_info.t_read); + } + return 0; +} + +int zebra_mlag_private_close_channel(void) +{ + if (zmlag_master == NULL) + return -1; + + if (zrouter.mlag_info.clients_interested_cnt) { + if (IS_ZEBRA_DEBUG_MLAG) + zlog_debug("%s: still %d clients are connected, skip", + __func__, + zrouter.mlag_info.clients_interested_cnt); + return -1; + } + + /* + * Post the De-register to MLAG, so that it can do necesasry cleanup + */ + zebra_mlag_send_deregister(); + + return 0; +} + +void zebra_mlag_private_cleanup_data(void) +{ + zmlag_master = NULL; + zrouter.mlag_info.connected = false; + zrouter.mlag_info.timer_running = false; + + close(mlag_socket); +} + +#else /*HAVE_CUMULUS */ + +int zebra_mlag_private_write_data(uint8_t *data, uint32_t len) +{ + return 0; +} + +void zebra_mlag_private_monitor_state(void) +{ +} + +int zebra_mlag_private_open_channel(void) +{ + return 0; +} + +int zebra_mlag_private_close_channel(void) +{ + return 0; +} + +void zebra_mlag_private_cleanup_data(void) +{ +} +#endif /*HAVE_CUMULUS*/ diff --git a/zebra/zebra_mlag_private.h b/zebra/zebra_mlag_private.h new file mode 100644 index 0000000000..f7b68e9ba0 --- /dev/null +++ b/zebra/zebra_mlag_private.h @@ -0,0 +1,37 @@ +/* + * This is an implementation of MLAG Functionality + * + * Module name: Zebra MLAG + * + * Author: sathesh Kumar karra <sathk@cumulusnetworks.com> + * + * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __ZEBRA_MLAG_PRIVATE_H__ +#define __ZEBRA_MLAG_PRIVATE_H__ + + +/* + * all the platform specific API's + */ + +int zebra_mlag_private_open_channel(void); +int zebra_mlag_private_close_channel(void); +void zebra_mlag_private_monitor_state(void); +int zebra_mlag_private_write_data(uint8_t *data, uint32_t len); +void zebra_mlag_private_cleanup_data(void); +#endif diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 87ea0cf0fb..d5d424732a 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -102,7 +102,8 @@ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, ifindex_t ifindex); static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex, mpls_label_t out_label); + ifindex_t ifindex, uint8_t num_labels, + mpls_label_t *labels); static int nhlfe_del(zebra_nhlfe_t *snhlfe); static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe, struct mpls_label_stack *nh_label); @@ -219,7 +220,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, /* Add LSP entry to this nexthop */ nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type, &nexthop->gate, nexthop->ifindex, - nexthop->nh_label->label[0]); + nexthop->nh_label->num_labels, + nexthop->nh_label->label); if (!nhlfe) return -1; @@ -1198,7 +1200,8 @@ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, */ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex, mpls_label_t out_label) + ifindex_t ifindex, uint8_t num_labels, + mpls_label_t labels[]) { zebra_nhlfe_t *nhlfe; struct nexthop *nexthop; @@ -1217,7 +1220,7 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type, XFREE(MTYPE_NHLFE, nhlfe); return NULL; } - nexthop_add_labels(nexthop, lsp_type, 1, &out_label); + nexthop_add_labels(nexthop, lsp_type, num_labels, labels); nexthop->vrf_id = VRF_DEFAULT; nexthop->type = gtype; @@ -2084,10 +2087,12 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp, enum nexthop_types_t gtype, union g_addr *gate, ifindex_t ifindex, - mpls_label_t out_label) + uint8_t num_labels, + mpls_label_t out_labels[]) { /* Just a public pass-through to the internal implementation */ - return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, out_label); + return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels, + out_labels); } /* @@ -2731,9 +2736,9 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, * the out-label for an existing NHLFE (update case). */ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, - mpls_label_t in_label, mpls_label_t out_label, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex) + mpls_label_t in_label, uint8_t num_out_labels, + mpls_label_t out_labels[], enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex) { struct hash *lsp_table; zebra_ile_t tmp_ile; @@ -2760,33 +2765,56 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, /* Clear deleted flag (in case it was set) */ UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED); - if (nh->nh_label->label[0] == out_label) + if (nh->nh_label->num_labels == num_out_labels + && !memcmp(nh->nh_label->label, out_labels, + sizeof(mpls_label_t) * num_out_labels)) /* No change */ return 0; if (IS_ZEBRA_DEBUG_MPLS) { + char buf2[BUFSIZ]; + char buf3[BUFSIZ]; + nhlfe2str(nhlfe, buf, BUFSIZ); + mpls_label2str(num_out_labels, out_labels, buf2, + sizeof(buf2), 0); + mpls_label2str(nh->nh_label->num_labels, + nh->nh_label->label, buf3, sizeof(buf3), + 0); + zlog_debug( "LSP in-label %u type %d nexthop %s " - "out-label changed to %u (old %u)", - in_label, type, buf, out_label, - nh->nh_label->label[0]); + "out-label(s) changed to %s (old %s)", + in_label, type, buf, buf2, buf3); } - /* Update out label, trigger processing. */ - nh->nh_label->label[0] = out_label; + /* Update out label(s), trigger processing. */ + if (nh->nh_label->num_labels == num_out_labels) + memcpy(nh->nh_label->label, out_labels, + sizeof(mpls_label_t) * num_out_labels); + else { + nexthop_del_labels(nh); + nexthop_add_labels(nh, type, num_out_labels, + out_labels); + } } else { /* Add LSP entry to this nexthop */ - nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, out_label); + nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex, + num_out_labels, out_labels); if (!nhlfe) return -1; if (IS_ZEBRA_DEBUG_MPLS) { + char buf2[BUFSIZ]; + nhlfe2str(nhlfe, buf, BUFSIZ); + mpls_label2str(num_out_labels, out_labels, buf2, + sizeof(buf2), 0); + zlog_debug( "Add LSP in-label %u type %d nexthop %s " - "out-label %u", - in_label, type, buf, out_label); + "out-label(s) %s", + in_label, type, buf, buf2); } lsp->addr_family = NHLFE_FAMILY(nhlfe); @@ -3059,8 +3087,8 @@ int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label, } /* (Re)Install LSP in the main table. */ - if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, out_label, gtype, - gate, ifindex)) + if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, 1, &out_label, + gtype, gate, ifindex)) return -1; return 0; diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 157f43ca98..2489e8e510 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -200,7 +200,8 @@ zebra_nhlfe_t *zebra_mpls_lsp_add_nhlfe(zebra_lsp_t *lsp, enum nexthop_types_t gtype, union g_addr *gate, ifindex_t ifindex, - mpls_label_t out_label); + uint8_t num_labels, + mpls_label_t out_labels[]); /* Free an allocated NHLFE */ void zebra_mpls_nhlfe_del(zebra_nhlfe_t *nhlfe); @@ -282,12 +283,12 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, /* * Install/update a NHLFE for an LSP in the forwarding table. This may be * a new LSP entry or a new NHLFE for an existing in-label or an update of - * the out-label for an existing NHLFE (update case). + * the out-label(s) for an existing NHLFE (update case). */ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type, - mpls_label_t in_label, mpls_label_t out_label, - enum nexthop_types_t gtype, union g_addr *gate, - ifindex_t ifindex); + mpls_label_t in_label, uint8_t num_out_labels, + mpls_label_t out_labels[], enum nexthop_types_t gtype, + union g_addr *gate, ifindex_t ifindex); /* * Uninstall a particular NHLFE in the forwarding table. If this is diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 61ca200a53..1a70250627 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1364,6 +1364,17 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } } + if ((top->p.family == AF_INET && top->p.prefixlen == 32 + && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr) + || (top->p.family == AF_INET6 && top->p.prefixlen == 128 + && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug( + "\t:%s: Attempting to install a max prefixlength route through itself", + __PRETTY_FUNCTION__); + return 0; + } + /* Make lookup prefix. */ memset(&p, 0, sizeof(struct prefix)); switch (afi) { @@ -1685,10 +1696,13 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) new_active = nexthop_active_check(rn, re, nexthop); - if (new_active - && nexthop_group_active_nexthop_num(&new_grp) - >= zrouter.multipath_num) { - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + if (new_active && curr_active >= zrouter.multipath_num) { + struct nexthop *nh; + + /* Set it and its resolved nexthop as inactive. */ + for (nh = nexthop; nh; nh = nh->resolved) + UNSET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE); + new_active = 0; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5eeeebd6e3..d525da26ee 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3548,7 +3548,7 @@ struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter) * Array that helps us go over all AFI/SAFI combinations via one * index. */ - static struct { + static const struct { afi_t afi; safi_t safi; } afi_safis[] = { diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 364f5755d8..641fc8799c 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -155,8 +155,10 @@ route_match_tag(void *rule, const struct prefix *prefix, } /* Route map commands for tag matching */ -static struct route_map_rule_cmd route_match_tag_cmd = { - "tag", route_match_tag, route_map_rule_tag_compile, +static const struct route_map_rule_cmd route_match_tag_cmd = { + "tag", + route_match_tag, + route_map_rule_tag_compile, route_map_rule_tag_free, }; @@ -203,22 +205,22 @@ static void show_vrf_proto_rm(struct vty *vty, struct zebra_vrf *zvrf, { int i; - vty_out(vty, "Protocol : route-map\n"); - vty_out(vty, "------------------------\n"); + vty_out(vty, "Protocol : route-map\n"); + vty_out(vty, "-------------------------------------\n"); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (PROTO_RM_NAME(zvrf, af_type, i)) - vty_out(vty, "%-10s : %-10s\n", zebra_route_string(i), + vty_out(vty, "%-24s : %-10s\n", zebra_route_string(i), PROTO_RM_NAME(zvrf, af_type, i)); else - vty_out(vty, "%-10s : none\n", zebra_route_string(i)); + vty_out(vty, "%-24s : none\n", zebra_route_string(i)); } if (PROTO_RM_NAME(zvrf, af_type, i)) - vty_out(vty, "%-10s : %-10s\n", "any", + vty_out(vty, "%-24s : %-10s\n", "any", PROTO_RM_NAME(zvrf, af_type, i)); else - vty_out(vty, "%-10s : none\n", "any"); + vty_out(vty, "%-24s : none\n", "any"); } static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf, @@ -226,22 +228,22 @@ static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf, { int i; - vty_out(vty, "Protocol : route-map\n"); - vty_out(vty, "------------------------\n"); + vty_out(vty, "Protocol : route-map\n"); + vty_out(vty, "-------------------------------------\n"); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (NHT_RM_NAME(zvrf, af_type, i)) - vty_out(vty, "%-10s : %-10s\n", zebra_route_string(i), + vty_out(vty, "%-24s : %-10s\n", zebra_route_string(i), NHT_RM_NAME(zvrf, af_type, i)); else - vty_out(vty, "%-10s : none\n", zebra_route_string(i)); + vty_out(vty, "%-24s : none\n", zebra_route_string(i)); } if (NHT_RM_NAME(zvrf, af_type, i)) - vty_out(vty, "%-10s : %-10s\n", "any", + vty_out(vty, "%-24s : %-10s\n", "any", NHT_RM_NAME(zvrf, af_type, i)); else - vty_out(vty, "%-10s : none\n", "any"); + vty_out(vty, "%-24s : none\n", "any"); } static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all, @@ -310,9 +312,12 @@ static int show_nht_rm(struct vty *vty, int af_type, const char *vrf_all, } /* Route map commands for interface matching */ -struct route_map_rule_cmd route_match_interface_cmd = { - "interface", route_match_interface, route_match_interface_compile, - route_match_interface_free}; +static const struct route_map_rule_cmd route_match_interface_cmd = { + "interface", + route_match_interface, + route_match_interface_compile, + route_match_interface_free +}; static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, afi_t afi, safi_t safi) @@ -1076,9 +1081,12 @@ static void route_match_ip_next_hop_free(void *rule) } /* Route map commands for ip next-hop matching. */ -static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { - "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile, - route_match_ip_next_hop_free}; +static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = { + "ip next-hop", + route_match_ip_next_hop, + route_match_ip_next_hop_compile, + route_match_ip_next_hop_free +}; /* `match ip next-hop prefix-list PREFIX_LIST' */ @@ -1129,10 +1137,13 @@ static void route_match_ip_next_hop_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { - "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_next_hop_prefix_list_cmd = { + "ip next-hop prefix-list", + route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, - route_match_ip_next_hop_prefix_list_free}; + route_match_ip_next_hop_prefix_list_free +}; /* `match ip address IP_ACCESS_LIST' */ @@ -1184,14 +1195,20 @@ static void route_match_address_free(void *rule) } /* Route map commands for ip address matching. */ -static struct route_map_rule_cmd route_match_ip_address_cmd = { - "ip address", route_match_ip_address, route_match_address_compile, - route_match_address_free}; +static const struct route_map_rule_cmd route_match_ip_address_cmd = { + "ip address", + route_match_ip_address, + route_match_address_compile, + route_match_address_free +}; /* Route map commands for ipv6 address matching. */ -static struct route_map_rule_cmd route_match_ipv6_address_cmd = { - "ipv6 address", route_match_ipv6_address, route_match_address_compile, - route_match_address_free}; +static const struct route_map_rule_cmd route_match_ipv6_address_cmd = { + "ipv6 address", + route_match_ipv6_address, + route_match_address_compile, + route_match_address_free +}; /* `match ip address prefix-list PREFIX_LIST' */ @@ -1231,10 +1248,13 @@ static void route_match_address_prefix_list_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { - "ip address prefix-list", route_match_ip_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ip_address_prefix_list_cmd = { + "ip address prefix-list", + route_match_ip_address_prefix_list, route_match_address_prefix_list_compile, - route_match_address_prefix_list_free}; + route_match_address_prefix_list_free +}; static enum route_map_cmd_result_t route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, @@ -1244,10 +1264,13 @@ route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, AFI_IP6)); } -static struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { - "ipv6 address prefix-list", route_match_ipv6_address_prefix_list, +static const struct route_map_rule_cmd + route_match_ipv6_address_prefix_list_cmd = { + "ipv6 address prefix-list", + route_match_ipv6_address_prefix_list, route_match_address_prefix_list_compile, - route_match_address_prefix_list_free}; + route_match_address_prefix_list_free +}; /* `match ipv6 next-hop type <TYPE>' */ @@ -1278,10 +1301,13 @@ static void route_match_ipv6_next_hop_type_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = { - "ipv6 next-hop type", route_match_ipv6_next_hop_type, +static const struct route_map_rule_cmd + route_match_ipv6_next_hop_type_cmd = { + "ipv6 next-hop type", + route_match_ipv6_next_hop_type, route_match_ipv6_next_hop_type_compile, - route_match_ipv6_next_hop_type_free}; + route_match_ipv6_next_hop_type_free +}; /* `match ip address prefix-len PREFIXLEN' */ @@ -1324,15 +1350,21 @@ static void route_match_address_prefix_len_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_address_prefix_len_cmd = { - "ip address prefix-len", route_match_address_prefix_len, +static const struct route_map_rule_cmd + route_match_ip_address_prefix_len_cmd = { + "ip address prefix-len", + route_match_address_prefix_len, route_match_address_prefix_len_compile, - route_match_address_prefix_len_free}; + route_match_address_prefix_len_free +}; -static struct route_map_rule_cmd route_match_ipv6_address_prefix_len_cmd = { - "ipv6 address prefix-len", route_match_address_prefix_len, +static const struct route_map_rule_cmd + route_match_ipv6_address_prefix_len_cmd = { + "ipv6 address prefix-len", + route_match_address_prefix_len, route_match_address_prefix_len_compile, - route_match_address_prefix_len_free}; + route_match_address_prefix_len_free +}; /* `match ip nexthop prefix-len PREFIXLEN' */ @@ -1368,8 +1400,10 @@ route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix, return RMAP_NOMATCH; } -static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = { - "ip next-hop prefix-len", route_match_ip_nexthop_prefix_len, +static const struct route_map_rule_cmd + route_match_ip_nexthop_prefix_len_cmd = { + "ip next-hop prefix-len", + route_match_ip_nexthop_prefix_len, route_match_address_prefix_len_compile, /* reuse */ route_match_address_prefix_len_free /* reuse */ }; @@ -1403,10 +1437,13 @@ static void route_match_ip_next_hop_type_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = { - "ip next-hop type", route_match_ip_next_hop_type, +static const struct route_map_rule_cmd + route_match_ip_next_hop_type_cmd = { + "ip next-hop type", + route_match_ip_next_hop_type, route_match_ip_next_hop_type_compile, - route_match_ip_next_hop_type_free}; + route_match_ip_next_hop_type_free +}; /* `match source-protocol PROTOCOL' */ @@ -1446,9 +1483,12 @@ static void route_match_source_protocol_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_source_protocol_cmd = { - "source-protocol", route_match_source_protocol, - route_match_source_protocol_compile, route_match_source_protocol_free}; +static const struct route_map_rule_cmd route_match_source_protocol_cmd = { + "source-protocol", + route_match_source_protocol, + route_match_source_protocol_compile, + route_match_source_protocol_free +}; /* `source-instance` */ static enum route_map_cmd_result_t @@ -1486,9 +1526,12 @@ static void route_match_source_instance_free(void *rule) XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static struct route_map_rule_cmd route_match_source_instance_cmd = { - "source-instance", route_match_source_instance, - route_match_source_instance_compile, route_match_source_instance_free}; +static const struct route_map_rule_cmd route_match_source_instance_cmd = { + "source-instance", + route_match_source_instance, + route_match_source_instance_compile, + route_match_source_instance_free +}; /* `set src A.B.C.D' */ @@ -1527,8 +1570,11 @@ static void route_set_src_free(void *rule) } /* Set src rule structure. */ -static struct route_map_rule_cmd route_set_src_cmd = { - "src", route_set_src, route_set_src_compile, route_set_src_free, +static const struct route_map_rule_cmd route_set_src_cmd = { + "src", + route_set_src, + route_set_src_compile, + route_set_src_free, }; /* The function checks if the changed routemap specified by parameter rmap diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index ac4c961475..d8ad8a6864 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -71,6 +71,41 @@ struct zebra_mlag_info { /* The system mac being used */ struct ethaddr mac; + /* + * Zebra will open the communication channel with MLAGD only if any + * clients are interested and it is controlled dynamically based on + * client registers & un-registers. + */ + uint32_t clients_interested_cnt; + + /* coomunication channel with MLAGD is established */ + bool connected; + + /* connection retry timer is running */ + bool timer_running; + + /* Holds the client data(unencoded) that need to be pushed to MCLAGD*/ + struct stream_fifo *mlag_fifo; + + /* + * A new Kernel thread will be created to post the data to MCLAGD. + * where as, read will be performed from the zebra main thread, because + * read involves accessing client registartion data structures. + */ + struct frr_pthread *zebra_pth_mlag; + + /* MLAG Thread context 'master' */ + struct thread_master *th_master; + + /* + * Event for Initial MLAG Connection setup & Data Read + * Read can be performed only after successful connection establishment, + * so no issues. + * + */ + struct thread *t_read; + /* Event for MLAG write */ + struct thread *t_write; }; struct zebra_router { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b0436dd40a..eca86d5fe2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2228,7 +2228,7 @@ DEFUN (show_evpn_vni_vni, vni = strtoul(argv[3]->arg, NULL, 10); zvrf = zebra_vrf_get_evpn(); - zebra_vxlan_print_vni(vty, zvrf, vni, uj); + zebra_vxlan_print_vni(vty, zvrf, vni, uj, NULL); return CMD_SUCCESS; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 3efb407fae..086b13d670 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -118,6 +118,8 @@ static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n); static zebra_vni_t *zvni_from_svi(struct interface *ifp, struct interface *br_if); static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if); +static struct interface *zvni_map_to_macvlan(struct interface *br_if, + struct interface *svi_if); /* l3-vni next-hop neigh related APIs */ static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, @@ -1814,6 +1816,8 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx) CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? "prefix-routes-only" : "none"); + vty_out(vty, " System MAC: %s\n", + zl3vni_sysmac2str(zl3vni, buf, sizeof(buf))); vty_out(vty, " Router MAC: %s\n", zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); vty_out(vty, " L2 VNIs: "); @@ -1833,6 +1837,9 @@ static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx) json_object_string_add(json, "state", zl3vni_state2str(zl3vni)); json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni)); json_object_string_add( + json, "sysMac", + zl3vni_sysmac2str(zl3vni, buf, sizeof(buf))); + json_object_string_add( json, "routerMac", zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); json_object_string_add( @@ -1987,6 +1994,7 @@ struct zvni_evpn_show { struct vty *vty; json_object *json; struct zebra_vrf *zvrf; + bool use_json; }; /* print a L3 VNI hash entry in detail*/ @@ -1994,20 +2002,21 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data) { struct vty *vty = NULL; zebra_l3vni_t *zl3vni = NULL; - json_object *json = NULL; + json_object *json_array = NULL; bool use_json = false; struct zvni_evpn_show *zes = data; vty = zes->vty; - json = zes->json; - - if (json) - use_json = true; + json_array = zes->json; + use_json = zes->use_json; zl3vni = (zebra_l3vni_t *)bucket->data; - zebra_vxlan_print_vni(vty, zes->zvrf, zl3vni->vni, use_json); - vty_out(vty, "\n"); + zebra_vxlan_print_vni(vty, zes->zvrf, zl3vni->vni, + use_json, json_array); + + if (!use_json) + vty_out(vty, "\n"); } @@ -2082,20 +2091,20 @@ static void zvni_print_hash_detail(struct hash_bucket *bucket, void *data) { struct vty *vty; zebra_vni_t *zvni; - json_object *json = NULL; + json_object *json_array = NULL; bool use_json = false; struct zvni_evpn_show *zes = data; vty = zes->vty; - json = zes->json; - - if (json) - use_json = true; + json_array = zes->json; + use_json = zes->use_json; zvni = (zebra_vni_t *)bucket->data; - zebra_vxlan_print_vni(vty, zes->zvrf, zvni->vni, use_json); - vty_out(vty, "\n"); + zebra_vxlan_print_vni(vty, zes->zvrf, zvni->vni, use_json, json_array); + + if (!use_json) + vty_out(vty, "\n"); } /* @@ -2491,6 +2500,8 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, /* Set router flag (R-bit) based on local neigh entry add */ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); + if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_SVI_IP)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP); return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD); @@ -2811,6 +2822,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, n->flags, n->loc_seq); } else if (advertise_svi_macip_enabled(zvni)) { + SET_FLAG(n->flags, ZEBRA_NEIGH_SVI_IP); if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "SVI %s(%u) L2-VNI %u, sending SVI MAC %s IP %s add to BGP with flags 0x%x", @@ -3684,7 +3696,7 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp, * of two cases: * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface * linked to the bridge - * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface + * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge interface * itself */ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) @@ -3735,6 +3747,52 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) return found ? tmp_if : NULL; } +/* Map to MAC-VLAN interface corresponding to specified SVI interface. + */ +static struct interface *zvni_map_to_macvlan(struct interface *br_if, + struct interface *svi_if) +{ + struct zebra_ns *zns; + struct route_node *rn; + struct interface *tmp_if = NULL; + struct zebra_if *zif; + int found = 0; + + /* Defensive check, caller expected to invoke only with valid bridge. */ + if (!br_if) + return NULL; + + if (!svi_if) { + zlog_debug("svi_if is not passed."); + return NULL; + } + + /* Determine if bridge is VLAN-aware or not */ + zif = br_if->info; + assert(zif); + + /* Identify corresponding VLAN interface. */ + zns = zebra_ns_lookup(NS_DEFAULT); + for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { + tmp_if = (struct interface *)rn->info; + /* Check oper status of the SVI. */ + if (!tmp_if || !if_is_operative(tmp_if)) + continue; + zif = tmp_if->info; + + if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN) + continue; + + if (zif->link == svi_if) { + found = 1; + break; + } + } + + return found ? tmp_if : NULL; +} + + /* * Install remote MAC into the forwarding plane. */ @@ -4151,6 +4209,16 @@ static void zvni_build_hash_table(void) */ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + /* Associate l3vni to mac-vlan and extract VRR MAC */ + zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("create l3vni %u svi_if %s mac_vlan_if %s", + vni, zl3vni->svi_if ? zl3vni->svi_if->name + : "NIL", + zl3vni->mac_vlan_if ? + zl3vni->mac_vlan_if->name : "NIL"); + if (is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); @@ -5056,6 +5124,24 @@ struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni) return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); } +struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni) +{ + struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */ + + if (!zl3vni) + return NULL; + + if (!zl3vni->vxlan_if) + return NULL; + + zif = zl3vni->vxlan_if->info; + if (!zif) + return NULL; + + return zvni_map_to_macvlan(zif->brslave_info.br_if, zl3vni->svi_if); +} + + zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id) { struct zebra_vrf *zvrf = NULL; @@ -5139,6 +5225,19 @@ static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp, return zl3vni; } +static inline void zl3vni_get_vrr_rmac(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac) +{ + if (!zl3vni) + return; + + if (!is_l3vni_oper_up(zl3vni)) + return; + + if (zl3vni->mac_vlan_if && if_is_operative(zl3vni->mac_vlan_if)) + memcpy(rmac->octet, zl3vni->mac_vlan_if->hw_addr, ETH_ALEN); +} + /* * Inform BGP about l3-vni. */ @@ -5146,35 +5245,54 @@ static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) { struct stream *s = NULL; struct zserv *client = NULL; - struct ethaddr rmac; + struct ethaddr svi_rmac, vrr_rmac = {.octet = {0} }; + struct zebra_vrf *zvrf; char buf[ETHER_ADDR_STRLEN]; + char buf1[ETHER_ADDR_STRLEN]; + bool is_anycast_mac = true; client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); /* BGP may not be running. */ if (!client) return 0; - /* get the rmac */ - memset(&rmac, 0, sizeof(struct ethaddr)); - zl3vni_get_rmac(zl3vni, &rmac); + zvrf = zebra_vrf_lookup_by_id(zl3vni->vrf_id); + assert(zvrf); + + /* get the svi and vrr rmac values */ + memset(&svi_rmac, 0, sizeof(struct ethaddr)); + zl3vni_get_svi_rmac(zl3vni, &svi_rmac); + zl3vni_get_vrr_rmac(zl3vni, &vrr_rmac); + + /* In absence of vrr mac use svi mac as anycast MAC value */ + if (is_zero_mac(&vrr_rmac)) { + memcpy(&vrr_rmac, &svi_rmac, ETH_ALEN); + is_anycast_mac = false; + } s = stream_new(ZEBRA_MAX_PACKET_SIZ); + /* The message is used for both vni add and/or update like + * vrr mac is added for l3vni SVI. + */ zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni)); stream_putl(s, zl3vni->vni); - stream_put(s, &rmac, sizeof(struct ethaddr)); + stream_put(s, &svi_rmac, sizeof(struct ethaddr)); stream_put_in_addr(s, &zl3vni->local_vtep_ip); stream_put(s, &zl3vni->filter, sizeof(int)); stream_putl(s, zl3vni->svi_if->ifindex); + stream_put(s, &vrr_rmac, sizeof(struct ethaddr)); + stream_putl(s, is_anycast_mac); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "Send L3_VNI_ADD %u VRF %s RMAC %s local-ip %s filter %s to %s", + "Send L3_VNI_ADD %u VRF %s RMAC %s VRR %s local-ip %s filter %s to %s", zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), - prefix_mac2str(&rmac, buf, sizeof(buf)), + prefix_mac2str(&svi_rmac, buf, sizeof(buf)), + prefix_mac2str(&vrr_rmac, buf1, sizeof(buf1)), inet_ntoa(zl3vni->local_vtep_ip), CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? "prefix-routes-only" @@ -7169,9 +7287,14 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, /* * Display VNI information (VTY command handler). + * + * use_json flag indicates that output should be in JSON format. + * json_array is non NULL when JSON output needs to be aggregated (by the + * caller) and then printed, otherwise, JSON evpn vni info is printed + * right away. */ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, - bool use_json) + bool use_json, json_object *json_array) { json_object *json = NULL; void *args[2]; @@ -7183,6 +7306,7 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, if (use_json) json = json_object_new_object(); + args[0] = vty; args[1] = json; @@ -7191,21 +7315,25 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, zl3vni_print(zl3vni, (void *)args); } else { zvni = zvni_lookup(vni); - if (!zvni) { - if (use_json) - vty_out(vty, "{}\n"); - else - vty_out(vty, "%% VNI %u does not exist\n", vni); - return; - } - - zvni_print(zvni, (void *)args); + if (zvni) + zvni_print(zvni, (void *)args); + else if (!json) + vty_out(vty, "%% VNI %u does not exist\n", vni); } if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + /* + * Each "json" object contains info about 1 VNI. + * When "json_array" is non-null, we aggreggate the json output + * into json_array and print it as a JSON array. + */ + if (json_array) + json_object_array_add(json_array, json); + else { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } } @@ -7362,7 +7490,7 @@ stream_failure: void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, bool use_json) { - json_object *json = NULL; + json_object *json_array = NULL; struct zebra_ns *zns = NULL; struct zvni_evpn_show zes; @@ -7373,13 +7501,13 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, if (!zns) return; - if (use_json) - json = json_object_new_object(); + json_array = json_object_new_array(); zes.vty = vty; - zes.json = json; + zes.json = json_array; zes.zvrf = zvrf; + zes.use_json = use_json; /* Display all L2-VNIs */ hash_iterate( @@ -7396,8 +7524,8 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, if (use_json) { vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + json_array, JSON_C_TO_STRING_PRETTY)); + json_object_free(json_array); } } @@ -8452,6 +8580,78 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) } /* + * Handle MAC-VLAN interface going down. + * L3VNI: When MAC-VLAN interface goes down, + * find its associated SVI and update type2/type-5 routes + * with SVI as RMAC + */ +void zebra_vxlan_macvlan_down(struct interface *ifp) +{ + zebra_l3vni_t *zl3vni = NULL; + struct zebra_if *zif, *link_zif; + struct interface *link_ifp, *link_if; + + zif = ifp->info; + assert(zif); + link_ifp = zif->link; + if (!link_ifp) { + if (IS_ZEBRA_DEBUG_VXLAN) { + struct interface *ifp; + + ifp = if_lookup_by_index_all_vrf(zif->link_ifindex); + zlog_debug("macvlan %s parent link is not found. Parent index %d ifp %s", + ifp->name, zif->link_ifindex, + ifp ? ifp->name : " "); + } + return; + } + link_zif = link_ifp->info; + assert(link_zif); + + link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + link_zif->link_ifindex); + + zl3vni = zl3vni_from_svi(link_ifp, link_if); + if (zl3vni) { + zl3vni->mac_vlan_if = NULL; + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } +} + +/* + * Handle MAC-VLAN interface going up. + * L3VNI: When MAC-VLAN interface comes up, + * find its associated SVI and update type-2 routes + * with MAC-VLAN's MAC as RMAC and for type-5 routes + * use SVI's MAC as RMAC. + */ +void zebra_vxlan_macvlan_up(struct interface *ifp) +{ + zebra_l3vni_t *zl3vni = NULL; + struct zebra_if *zif, *link_zif; + struct interface *link_ifp, *link_if; + + zif = ifp->info; + assert(zif); + link_ifp = zif->link; + link_zif = link_ifp->info; + assert(link_zif); + + link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + link_zif->link_ifindex); + zl3vni = zl3vni_from_svi(link_ifp, link_if); + if (zl3vni) { + /* associate with macvlan (VRR) interface */ + zl3vni->mac_vlan_if = ifp; + + /* process oper-up */ + if (is_l3vni_oper_up(zl3vni)) + zebra_vxlan_process_l3vni_oper_up(zl3vni); + } +} + +/* * Handle VxLAN interface down */ int zebra_vxlan_if_down(struct interface *ifp) @@ -8531,15 +8731,18 @@ int zebra_vxlan_if_up(struct interface *ifp) zl3vni = zl3vni_lookup(vni); if (zl3vni) { - - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Intf %s(%u) L3-VNI %u is UP", ifp->name, - ifp->ifindex, vni); - /* we need to associate with SVI, if any, we can associate with * svi-if only after association with vxlan-intf is complete */ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s" + , ifp->name, ifp->ifindex, vni, + zl3vni->svi_if ? zl3vni->svi_if->name : "NIL", + zl3vni->mac_vlan_if ? + zl3vni->mac_vlan_if->name : "NIL"); if (is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); @@ -8702,6 +8905,8 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->mac_vlan_if = + zl3vni_map_to_mac_vlan_if(zl3vni); zl3vni->local_vtep_ip = vxl->vtep_ip; if (is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up( @@ -8861,6 +9066,8 @@ int zebra_vxlan_if_add(struct interface *ifp) * after association with vxlan_if is complete */ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); + if (is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } else { @@ -8993,6 +9200,16 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, */ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); + zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: l3vni %u svi_if %s mac_vlan_if %s", + __PRETTY_FUNCTION__, vni, + zl3vni->svi_if ? + zl3vni->svi_if->name : "NIL", + zl3vni->mac_vlan_if ? + zl3vni->mac_vlan_if->name : "NIL"); + /* formulate l2vni list */ hash_iterate(zvrf_evpn->vni_table, zvni_add_to_l3vni_list, zl3vni); diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index bb80ae1c9a..b551ba8dff 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -141,7 +141,8 @@ extern void zebra_vxlan_print_neigh_vni_dad(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, bool use_json); extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni, bool use_json); + vni_t vni, bool use_json, + json_object *json_array); extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, bool use_json); extern void zebra_vxlan_print_vnis_detail(struct vty *vty, @@ -217,6 +218,8 @@ extern int zebra_vxlan_clear_dup_detect_vni(struct vty *vty, extern void zebra_vxlan_handle_result(struct zebra_dplane_ctx *ctx); extern void zebra_evpn_init(void); +extern void zebra_vxlan_macvlan_up(struct interface *ifp); +extern void zebra_vxlan_macvlan_down(struct interface *ifp); #ifdef __cplusplus } diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 8e78042646..989ea464e7 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -125,6 +125,8 @@ struct zebra_l3vni_t_ { /* SVI interface corresponding to the l3vni */ struct interface *svi_if; + struct interface *mac_vlan_if; + /* list of L2 VNIs associated with the L3 VNI */ struct list *l2vnis; @@ -167,6 +169,44 @@ static inline const char *zl3vni_rmac2str(zebra_l3vni_t *zl3vni, char *buf, ptr = buf; } + if (zl3vni->mac_vlan_if) + snprintf(ptr, (ETHER_ADDR_STRLEN), + "%02x:%02x:%02x:%02x:%02x:%02x", + (uint8_t)zl3vni->mac_vlan_if->hw_addr[0], + (uint8_t)zl3vni->mac_vlan_if->hw_addr[1], + (uint8_t)zl3vni->mac_vlan_if->hw_addr[2], + (uint8_t)zl3vni->mac_vlan_if->hw_addr[3], + (uint8_t)zl3vni->mac_vlan_if->hw_addr[4], + (uint8_t)zl3vni->mac_vlan_if->hw_addr[5]); + else if (zl3vni->svi_if) + snprintf(ptr, (ETHER_ADDR_STRLEN), + "%02x:%02x:%02x:%02x:%02x:%02x", + (uint8_t)zl3vni->svi_if->hw_addr[0], + (uint8_t)zl3vni->svi_if->hw_addr[1], + (uint8_t)zl3vni->svi_if->hw_addr[2], + (uint8_t)zl3vni->svi_if->hw_addr[3], + (uint8_t)zl3vni->svi_if->hw_addr[4], + (uint8_t)zl3vni->svi_if->hw_addr[5]); + else + snprintf(ptr, ETHER_ADDR_STRLEN, "None"); + + return ptr; +} + +/* get the sys mac string */ +static inline const char *zl3vni_sysmac2str(zebra_l3vni_t *zl3vni, char *buf, + int size) +{ + char *ptr; + + if (!buf) + ptr = (char *)XMALLOC(MTYPE_TMP, + ETHER_ADDR_STRLEN * sizeof(char)); + else { + assert(size >= ETHER_ADDR_STRLEN); + ptr = buf; + } + if (zl3vni->svi_if) snprintf(ptr, (ETHER_ADDR_STRLEN), "%02x:%02x:%02x:%02x:%02x:%02x", @@ -215,7 +255,8 @@ static inline vrf_id_t zl3vni_vrf_id(zebra_l3vni_t *zl3vni) return zl3vni->vrf_id; } -static inline void zl3vni_get_rmac(zebra_l3vni_t *zl3vni, struct ethaddr *rmac) +static inline void zl3vni_get_svi_rmac(zebra_l3vni_t *zl3vni, + struct ethaddr *rmac) { if (!zl3vni) return; @@ -363,6 +404,7 @@ struct zebra_neigh_t_ { #define ZEBRA_NEIGH_DEF_GW 0x08 #define ZEBRA_NEIGH_ROUTER_FLAG 0x10 #define ZEBRA_NEIGH_DUPLICATE 0x20 +#define ZEBRA_NEIGH_SVI_IP 0x40 enum zebra_neigh_state state; @@ -433,6 +475,7 @@ struct nh_walk_ctx { extern zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id); extern struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni); extern struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni); +extern struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni); DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, bool delete, const char *reason), (rmac, zl3vni, delete, reason)) diff --git a/zebra/zserv.c b/zebra/zserv.c index b0991e98f8..419f30e6d3 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -914,7 +914,7 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) zserv_command_string(last_write_cmd)); vty_out(vty, "\n"); - vty_out(vty, "Type Add Update Del \n"); + vty_out(vty, "Type Add Update Del \n"); vty_out(vty, "================================================== \n"); vty_out(vty, "IPv4 %-12d%-12d%-12d\n", client->v4_route_add_cnt, client->v4_route_upd8_cnt, client->v4_route_del_cnt); @@ -965,7 +965,7 @@ static void zebra_show_client_brief(struct vty *vty, struct zserv *client) last_write_time = (time_t)atomic_load_explicit(&client->last_write_time, memory_order_relaxed); - vty_out(vty, "%-8s%12s %12s%12s%8d/%-8d%8d/%-8d\n", + vty_out(vty, "%-10s%12s %12s%12s%8d/%-8d%8d/%-8d\n", zebra_route_string(client->proto), zserv_time_buf(&connect_time, cbuf, ZEBRA_TIME_BUF), zserv_time_buf(&last_read_time, rbuf, ZEBRA_TIME_BUF), @@ -1019,7 +1019,7 @@ DEFUN (show_zebra_client_summary, struct zserv *client; vty_out(vty, - "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes \n"); + "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes \n"); vty_out(vty, "--------------------------------------------------------------------------------\n"); diff --git a/zebra/zserv.h b/zebra/zserv.h index 708ff1e226..ccc8d92aa2 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -99,6 +99,13 @@ struct zserv { uint8_t proto; uint16_t instance; + /* + * Interested for MLAG Updates, and also stores the client + * interested message mask + */ + bool mlag_updates_interested; + uint32_t mlag_reg_mask1; + /* Statistics */ uint32_t redist_v4_add_cnt; uint32_t redist_v4_del_cnt; |
