diff options
286 files changed, 9809 insertions, 3419 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..6dc8e0d354 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 @@ -227,8 +228,6 @@ EXTRA_DIST += \ vrrpd/Makefile \ # end -noinst_HEADERS += defaults.h - clean-local: clean-python .PHONY: clean-python clean-python: 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 6e956aa929..920e3fdeea 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -1696,17 +1696,17 @@ static int bfd_vrf_enable(struct vrf *vrf) if (vrf->vrf_id == VRF_DEFAULT || vrf_get_backend() == VRF_BACKEND_NETNS) { if (!bvrf->bg_shop) - bvrf->bg_shop = bp_udp_shop(vrf->vrf_id); + bvrf->bg_shop = bp_udp_shop(vrf); if (!bvrf->bg_mhop) - bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id); + bvrf->bg_mhop = bp_udp_mhop(vrf); if (!bvrf->bg_shop6) - bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id); + bvrf->bg_shop6 = bp_udp6_shop(vrf); if (!bvrf->bg_mhop6) - bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id); + bvrf->bg_mhop6 = bp_udp6_mhop(vrf); if (!bvrf->bg_echo) - bvrf->bg_echo = bp_echo_socket(vrf->vrf_id); + bvrf->bg_echo = bp_echo_socket(vrf); if (!bvrf->bg_echov6) - bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id); + bvrf->bg_echov6 = bp_echov6_socket(vrf); /* Add descriptors to the event loop. */ if (!bvrf->bg_ev[0]) @@ -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 220dd6e0a8..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); @@ -461,14 +461,14 @@ int bp_set_tosv6(int sd, uint8_t value); int bp_set_tos(int sd, uint8_t value); int bp_bind_dev(int sd, const char *dev); -int bp_udp_shop(vrf_id_t vrf_id); -int bp_udp_mhop(vrf_id_t vrf_id); -int bp_udp6_shop(vrf_id_t vrf_id); -int bp_udp6_mhop(vrf_id_t vrf_id); +int bp_udp_shop(const struct vrf *vrf); +int bp_udp_mhop(const struct vrf *vrf); +int bp_udp6_shop(const struct vrf *vrf); +int bp_udp6_mhop(const struct vrf *vrf); int bp_peer_socket(const struct bfd_session *bs); int bp_peer_socketv6(const struct bfd_session *bs); -int bp_echo_socket(vrf_id_t vrf_id); -int bp_echov6_socket(vrf_id_t vrf_id); +int bp_echo_socket(const struct vrf *vrf); +int bp_echov6_socket(const struct vrf *vrf); void ptm_bfd_snd(struct bfd_session *bfd, int fbit); void ptm_bfd_echo_snd(struct bfd_session *bfd); @@ -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/bfd_packet.c b/bfdd/bfd_packet.c index 398719d18c..6da5e2cdf9 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -890,12 +890,13 @@ static void bp_bind_ip(int sd, uint16_t port) log_fatal("bind-ip: bind: %s", strerror(errno)); } -int bp_udp_shop(vrf_id_t vrf_id) +int bp_udp_shop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp-shop: socket: %s", strerror(errno)); @@ -905,12 +906,13 @@ int bp_udp_shop(vrf_id_t vrf_id) return sd; } -int bp_udp_mhop(vrf_id_t vrf_id) +int bp_udp_mhop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp-mhop: socket: %s", strerror(errno)); @@ -1117,12 +1119,13 @@ static void bp_bind_ipv6(int sd, uint16_t port) log_fatal("bind-ipv6: bind: %s", strerror(errno)); } -int bp_udp6_shop(vrf_id_t vrf_id) +int bp_udp6_shop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp6-shop: socket: %s", strerror(errno)); @@ -1133,12 +1136,13 @@ int bp_udp6_shop(vrf_id_t vrf_id) return sd; } -int bp_udp6_mhop(vrf_id_t vrf_id) +int bp_udp6_mhop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp6-mhop: socket: %s", strerror(errno)); @@ -1149,12 +1153,12 @@ int bp_udp6_mhop(vrf_id_t vrf_id) return sd; } -int bp_echo_socket(vrf_id_t vrf_id) +int bp_echo_socket(const struct vrf *vrf) { int s; frr_with_privs(&bglobal.bfdd_privs) { - s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL); + s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf->vrf_id, vrf->name); } if (s == -1) log_fatal("echo-socket: socket: %s", strerror(errno)); @@ -1165,12 +1169,12 @@ int bp_echo_socket(vrf_id_t vrf_id) return s; } -int bp_echov6_socket(vrf_id_t vrf_id) +int bp_echov6_socket(const struct vrf *vrf) { int s; frr_with_privs(&bglobal.bfdd_privs) { - s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf_id, NULL); + s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf->vrf_id, vrf->name); } if (s == -1) log_fatal("echov6-socket: socket: %s", strerror(errno)); 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 0ca4b613ee..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) @@ -321,6 +321,7 @@ void bgp_addpath_type_changed(struct bgp *bgp) for (type=0; type<BGP_ADDPATH_MAX; type++) { peer_count[afi][safi][type] = 0; } + bgp->tx_addpath.total_peercount[afi][safi] = 0; } for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { @@ -328,6 +329,7 @@ void bgp_addpath_type_changed(struct bgp *bgp) type = peer->addpath_type[afi][safi]; if (type != BGP_ADDPATH_NONE) { peer_count[afi][safi][type] += 1; + bgp->tx_addpath.total_peercount[afi][safi] += 1; } } } 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_attr.c b/bgpd/bgp_attr.c index bfa578085d..ab80aff81b 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -464,15 +464,6 @@ static void transit_finish(void) /* Attribute hash routines. */ static struct hash *attrhash; -/* Shallow copy of an attribute - * Though, not so shallow that it doesn't copy the contents - * of the attr_extra pointed to by 'extra' - */ -void bgp_attr_dup(struct attr *new, struct attr *orig) -{ - *new = *orig; -} - unsigned long int attr_count(void) { return attrhash->count; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 42002bd378..13ed3e1ee3 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -69,6 +69,10 @@ #define BGP_PREFIX_SID_IPV6_LENGTH 19 #define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6 +#define BGP_ATTR_NH_AFI(afi, attr) \ + ((afi != AFI_L2VPN) ? afi : \ + ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) ? AFI_IP : AFI_IP6)) + /* PMSI tunnel types (RFC 6514) */ struct bgp_attr_encap_subtlv { @@ -268,7 +272,6 @@ extern void bgp_attr_finish(void); extern bgp_attr_parse_ret_t bgp_attr_parse(struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); -extern void bgp_attr_dup(struct attr *, struct attr *); extern void bgp_attr_undup(struct attr *new, struct attr *old); extern struct attr *bgp_attr_intern(struct attr *attr); extern void bgp_attr_unintern_sub(struct attr *); 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 07d3f7b31e..b8798a7ced 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -49,6 +49,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_addpath.h" #include "bgpd/bgp_mac.h" +#include "bgpd/bgp_vty.h" /* * Definitions and external declarations. @@ -494,6 +495,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. @@ -1538,16 +1572,52 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, * present, else treat as locally originated. */ if (src_attr) - bgp_attr_dup(&attr, src_attr); + attr = *src_attr; else { 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 +1722,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 +1868,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 +1919,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 +2171,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 +2182,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 +2214,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 +2398,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; @@ -2532,7 +2662,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, * address for the rest of the code to flow through. In the case of IPv4, * make sure to set the flag for next hop attribute. */ - bgp_attr_dup(&attr, parent_pi->attr); + attr = *parent_pi->attr; if (afi == AFI_IP6) evpn_convert_nexthop_to_ipv6(&attr); else @@ -2583,6 +2713,8 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Process for route leaking. */ vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); + bgp_unlock_node(rn); + return ret; } @@ -2638,6 +2770,8 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Perform route selection and update zebra, if required. */ ret = evpn_route_select_install(bgp, vpn, rn); + bgp_unlock_node(rn); + return ret; } @@ -3523,8 +3657,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); @@ -4582,6 +4722,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 @@ -4596,8 +4739,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 */ @@ -5391,8 +5560,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]; @@ -5508,9 +5678,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 */ @@ -5537,9 +5710,10 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac, int ret = 0; - ret = bgp_get(&bgp_vrf, &as, vrf_id_to_name(vrf_id), - vrf_id == VRF_DEFAULT ? BGP_INSTANCE_TYPE_DEFAULT - : BGP_INSTANCE_TYPE_VRF); + ret = bgp_get_vty(&bgp_vrf, &as, vrf_id_to_name(vrf_id), + vrf_id == VRF_DEFAULT + ? BGP_INSTANCE_TYPE_DEFAULT + : BGP_INSTANCE_TYPE_VRF); switch (ret) { case BGP_ERR_AS_MISMATCH: flog_err(EC_BGP_EVPN_AS_MISMATCH, @@ -5557,10 +5731,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); @@ -5641,6 +5840,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)) { @@ -6000,6 +6203,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. */ @@ -6026,3 +6238,26 @@ int bgp_evpn_get_type5_prefixlen(struct prefix *pfx) return evp->prefix.prefix_addr.ip_prefix_length; } + +/* + * Should we register nexthop for this EVPN prefix for nexthop tracking? + */ +bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx) +{ + struct prefix_evpn *evp = (struct prefix_evpn *)pfx; + + /* + * EVPN RT-5 should not be marked as valid and imported to vrfs if the + * BGP nexthop is not reachable. To check for the nexthop reachability, + * Add nexthop for EVPN RT-5 for nexthop tracking. + * + * Ideally, a BGP route should be marked as valid only if the + * nexthop is reachable. Thus, other EVPN route types also should be + * added here after testing is performed for them. + */ + if (pfx && pfx->family == AF_EVPN && + evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) + return true; + + return false; +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 6d1e8cd31b..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, @@ -191,5 +192,7 @@ extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp); 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..9cb3957a86 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -27,7 +27,6 @@ #include "thread.h" #include <lib/version.h> #include "memory.h" -#include "memory_vty.h" #include "prefix.h" #include "log.h" #include "privs.h" @@ -360,7 +359,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_mpath.c b/bgpd/bgp_mpath.c index d37bf54734..77448ec15d 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -720,7 +720,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best, return; } - bgp_attr_dup(&attr, new_best->attr); + attr = *new_best->attr; if (new_best->peer && bgp_flag_check(new_best->peer->bgp, BGP_FLAG_MULTIPATH_RELAX_AS_SET)) { diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 1d15361416..59ed433e58 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -699,7 +699,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ return; } - bgp_attr_dup(&static_attr, path_vrf->attr); /* shallow copy */ + /* shallow copy */ + static_attr = *path_vrf->attr; /* * route map handling @@ -1082,7 +1083,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ buf_prefix, bgp_vrf->name_pretty); } - bgp_attr_dup(&static_attr, path_vpn->attr); /* shallow copy */ + /* shallow copy */ + static_attr = *path_vpn->attr; /* * Nexthop: stash and clear 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_nht.c b/bgpd/bgp_nht.c index 6be08efb21..0969c8e77e 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -43,6 +43,7 @@ #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_flowspec_util.h" +#include "bgpd/bgp_evpn.h" extern struct zclient *zclient; @@ -773,6 +774,16 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED); + if (safi == SAFI_EVPN && + bgp_evpn_is_prefix_nht_supported(&rn->p)) { + if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) + bgp_evpn_import_route(bgp_path, afi, safi, + &rn->p, path); + else + bgp_evpn_unimport_route(bgp_path, afi, safi, + &rn->p, path); + } + bgp_process(bgp_path, rn, afi, safi); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 261fe77800..3ef1ac39a5 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1244,7 +1244,7 @@ static int bgp_cluster_filter(struct peer *peer, struct attr *attr) static int bgp_input_modifier(struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name, mpls_label_t *label, - uint32_t num_labels) + uint32_t num_labels, struct bgp_node *rn) { struct bgp_filter *filter; struct bgp_path_info rmap_path = { 0 }; @@ -1279,6 +1279,8 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, rmap_path.peer = peer; rmap_path.attr = attr; rmap_path.extra = &extra; + rmap_path.net = rn; + extra.num_labels = num_labels; if (label && num_labels && num_labels <= BGP_MAX_LABELS) memcpy(extra.label, label, @@ -1693,7 +1695,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, } /* For modify attribute, copy it to temporary structure. */ - bgp_attr_dup(attr, piattr); + *attr = *piattr; /* If local-preference is not set. */ if ((peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) @@ -1795,6 +1797,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, memset(&rmap_path, 0, sizeof(struct bgp_path_info)); rmap_path.peer = peer; rmap_path.attr = attr; + rmap_path.net = rn; if (pi->extra) { memcpy(&dummy_rmap_path_extra, pi->extra, @@ -1812,7 +1815,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, if ((from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) && !bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { - bgp_attr_dup(&dummy_attr, attr); + dummy_attr = *attr; rmap_path.attr = &dummy_attr; } @@ -1851,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) { @@ -2967,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; @@ -2980,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; } @@ -2996,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: @@ -3006,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: @@ -3038,6 +3055,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, int connected = 0; 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 @@ -3144,7 +3165,20 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } - bgp_attr_dup(&new_attr, attr); + /* 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; + } + + new_attr = *attr; /* Apply incoming route-map. * NB: new_attr may now contain newly allocated values from route-map @@ -3153,7 +3187,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * intern * the attr (which takes over the memory references) */ if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL, - label, num_labels) == RMAP_DENY) { + label, num_labels, rn) == RMAP_DENY) { peer->stat_pfx_filter++; reason = "route-map;"; bgp_attr_flush(&new_attr); @@ -3183,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); @@ -3433,9 +3473,12 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, /* Nexthop reachability check - for unicast and * labeled-unicast.. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 + 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 (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( @@ -3449,8 +3492,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, if (pi->extra && pi->extra->bgp_orig) bgp_nexthop = pi->extra->bgp_orig; - if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, pi, - NULL, connected) + nh_afi = BGP_ATTR_NH_AFI(afi, pi->attr); + + if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, nh_afi, + pi, NULL, connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(rn, pi, BGP_PATH_VALID); else { @@ -3498,7 +3543,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * updating * the attributes for the route in the VNI(s). */ - if (safi == SAFI_EVPN && !same_attr) + if (safi == SAFI_EVPN && !same_attr && + CHECK_FLAG(pi->flags, BGP_PATH_VALID)) bgp_evpn_import_route(bgp, afi, safi, p, pi); /* Process change. */ @@ -3571,9 +3617,11 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, evpn == NULL ? NULL : &evpn->gw_ip); } /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { - if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 + 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 (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)) @@ -3581,7 +3629,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, else connected = 0; - if (bgp_find_or_add_nexthop(bgp, bgp, afi, new, NULL, connected) + nh_afi = BGP_ATTR_NH_AFI(afi, new->attr); + + if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, new, NULL, + connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(rn, new, BGP_PATH_VALID); else { @@ -3632,7 +3683,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, return -1; /* If this is an EVPN route, process for import. */ - if (safi == SAFI_EVPN) + if (safi == SAFI_EVPN && CHECK_FLAG(new->flags, BGP_PATH_VALID)) bgp_evpn_import_route(bgp, afi, safi, p, new); hook_call(bgp_process, bgp, afi, safi, rn, peer, false); @@ -4455,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)); @@ -6364,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) @@ -6466,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); @@ -6500,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) { @@ -6535,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 @@ -6570,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 @@ -6659,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) @@ -6756,7 +6829,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, struct attr attr_new; /* Copy attribute for modification. */ - bgp_attr_dup(&attr_new, &attr); + attr_new = attr; if (red->redist_metric_flag) attr_new.med = red->redist_metric; @@ -9145,7 +9218,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, struct attr dummy_attr; route_map_result_t ret; - bgp_attr_dup(&dummy_attr, pi->attr); + dummy_attr = *pi->attr; path.peer = pi->peer; path.attr = &dummy_attr; @@ -9343,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) { @@ -10572,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", @@ -10830,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", @@ -11111,7 +11185,7 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix, argv_find(argv, argc, "X:X::X:X", &idx)) network = argv[idx]->arg; else if (argv_find(argv, argc, "A.B.C.D/M", &idx) || - argv_find(argv, argc, "A.B.C.D/M", &idx)) { + argv_find(argv, argc, "X:X::X:X/M", &idx)) { network = argv[idx]->arg; prefix_check = 1; } else { @@ -11287,7 +11361,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, header2 = 0; } - bgp_attr_dup(&attr, ain->attr); + attr = *ain->attr; route_filtered = false; /* Filter prefix using distribute list, @@ -11299,7 +11373,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, /* Filter prefix using route-map */ ret = bgp_input_modifier(peer, &rn->p, &attr, - afi, safi, rmap_name, NULL, 0); + afi, safi, rmap_name, NULL, 0, + NULL); if (type == bgp_show_adj_route_filtered && !route_filtered && ret != RMAP_DENY) { @@ -11388,7 +11463,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, header2 = 0; } - bgp_attr_dup(&attr, adj->attr); + attr = *adj->attr; ret = bgp_output_modifier( peer, &rn->p, &attr, afi, safi, rmap_name); @@ -11928,6 +12003,32 @@ uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *pinfo, } } +/* If we enter `distance bgp (1-255) (1-255) (1-255)`, + * we should tell ZEBRA update the routes for a specific + * AFI/SAFI to reflect changes in RIB. + */ +static void bgp_announce_routes_distance_update(struct bgp *bgp, + afi_t update_afi, + safi_t update_safi) +{ + afi_t afi; + safi_t safi; + + FOREACH_AFI_SAFI (afi, safi) { + if (!bgp_fibupd_safi(safi)) + continue; + + if (afi != update_afi && safi != update_safi) + continue; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "%s: Announcing routes due to distance change afi/safi (%d/%d)", + __func__, afi, safi); + bgp_zebra_announce_table(bgp, afi, safi); + } +} + DEFUN (bgp_distance, bgp_distance_cmd, "distance bgp (1-255) (1-255) (1-255)", @@ -11941,15 +12042,23 @@ DEFUN (bgp_distance, int idx_number = 2; int idx_number_2 = 3; int idx_number_3 = 4; + int distance_ebgp = atoi(argv[idx_number]->arg); + int distance_ibgp = atoi(argv[idx_number_2]->arg); + int distance_local = atoi(argv[idx_number_3]->arg); afi_t afi; safi_t safi; afi = bgp_node_afi(vty); safi = bgp_node_safi(vty); - bgp->distance_ebgp[afi][safi] = atoi(argv[idx_number]->arg); - bgp->distance_ibgp[afi][safi] = atoi(argv[idx_number_2]->arg); - bgp->distance_local[afi][safi] = atoi(argv[idx_number_3]->arg); + if (bgp->distance_ebgp[afi][safi] != distance_ebgp + || bgp->distance_ibgp[afi][safi] != distance_ibgp + || bgp->distance_local[afi][safi] != distance_local) { + bgp->distance_ebgp[afi][safi] = distance_ebgp; + bgp->distance_ibgp[afi][safi] = distance_ibgp; + bgp->distance_local[afi][safi] = distance_local; + bgp_announce_routes_distance_update(bgp, afi, safi); + } return CMD_SUCCESS; } @@ -11970,9 +12079,14 @@ DEFUN (no_bgp_distance, afi = bgp_node_afi(vty); safi = bgp_node_safi(vty); - bgp->distance_ebgp[afi][safi] = 0; - bgp->distance_ibgp[afi][safi] = 0; - bgp->distance_local[afi][safi] = 0; + if (bgp->distance_ebgp[afi][safi] != 0 + || bgp->distance_ibgp[afi][safi] != 0 + || bgp->distance_local[afi][safi] != 0) { + bgp->distance_ebgp[afi][safi] = 0; + bgp->distance_ibgp[afi][safi] = 0; + bgp->distance_local[afi][safi] = 0; + bgp_announce_routes_distance_update(bgp, afi, safi); + } return CMD_SUCCESS; } @@ -12117,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 d0cea547ec..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,72 @@ 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' */ + +/* Match function should return 1 if match is success else return zero. */ +static enum route_map_cmd_result_t +route_match_rd(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_rd *prd_rule = NULL; + struct prefix_rd *prd_route = NULL; + struct bgp_path_info *path = NULL; + + if (type == RMAP_BGP) { + if (prefix->family != AF_EVPN) + return RMAP_NOMATCH; + + prd_rule = (struct prefix_rd *)rule; + path = (struct bgp_path_info *)object; + + if (path->net == NULL || path->net->prn == NULL) + return RMAP_NOMATCH; + + prd_route = (struct prefix_rd *)&path->net->prn->p; + if (memcmp(prd_route->val, prd_rule->val, ECOMMUNITY_SIZE) == 0) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +/* Route map `rd' match statement. */ +static void *route_match_rd_compile(const char *arg) +{ + struct prefix_rd *prd; + int ret; + + prd = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct prefix_rd)); + + ret = str2prefix_rd(arg, prd); + if (!ret) { + XFREE(MTYPE_ROUTE_MAP_COMPILED, prd); + return NULL; + } + + return prd; +} + +/* Free route map's compiled `rd' value. */ +static void route_match_rd_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for rd matching. */ +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 @@ -1011,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' */ @@ -1038,8 +1138,10 @@ route_match_local_pref(void *rule, const struct prefix *prefix, return RMAP_NOMATCH; } -/* Route map `match local-preference' match statement. - `arg' is local-pref value */ +/* + * Route map `match local-preference' match statement. + * `arg' is local-pref value + */ static void *route_match_local_pref_compile(const char *arg) { uint32_t *local_pref; @@ -1068,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' */ @@ -1091,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' */ @@ -1135,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 { @@ -1227,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 @@ -1298,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. */ @@ -1350,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'. */ @@ -1399,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 { */ @@ -1452,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 @@ -1496,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 +}; /* } */ @@ -1524,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, }; @@ -1635,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' */ @@ -1668,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, }; @@ -1696,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 */ @@ -1717,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, @@ -1750,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)' */ @@ -1775,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' */ @@ -1833,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' */ @@ -1866,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, }; @@ -1980,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, }; @@ -2098,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, }; @@ -2187,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, }; @@ -2277,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' */ @@ -2344,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' */ @@ -2364,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' */ @@ -2413,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, }; @@ -2448,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' */ @@ -2506,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 */ @@ -2531,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, }; @@ -2562,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, }; @@ -2598,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' */ @@ -2649,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' */ @@ -2673,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>' */ @@ -2720,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' */ @@ -2780,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 @@ -2830,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' */ @@ -2892,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' */ @@ -2974,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' */ @@ -3062,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' */ @@ -3117,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. */ @@ -3666,6 +3869,31 @@ DEFUN (no_match_evpn_default_route, RMAP_EVENT_MATCH_DELETED); } +DEFUN (match_evpn_rd, + match_evpn_rd_cmd, + "match evpn rd ASN:NN_OR_IP-ADDRESS:NN", + MATCH_STR + EVPN_HELP_STR + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + return bgp_route_match_add(vty, "evpn rd", argv[3]->arg, + RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_evpn_rd, + no_match_evpn_rd_cmd, + "no match evpn rd ASN:NN_OR_IP-ADDRESS:NN", + NO_STR + MATCH_STR + EVPN_HELP_STR + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + return bgp_route_match_delete(vty, "evpn rd", argv[4]->arg, + RMAP_EVENT_MATCH_DELETED); +} + DEFPY(match_vrl_source_vrf, match_vrl_source_vrf_cmd, "match source-vrf NAME$vrf_name", @@ -5216,6 +5444,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_mac_address_cmd); route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_match(&route_match_evpn_route_type_cmd); + route_map_install_match(&route_match_evpn_rd_cmd); route_map_install_match(&route_match_evpn_default_route_cmd); route_map_install_match(&route_match_vrl_source_vrf_cmd); @@ -5256,6 +5485,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_evpn_vni_cmd); install_element(RMAP_NODE, &match_evpn_route_type_cmd); install_element(RMAP_NODE, &no_match_evpn_route_type_cmd); + install_element(RMAP_NODE, &match_evpn_rd_cmd); + install_element(RMAP_NODE, &no_match_evpn_rd_cmd); install_element(RMAP_NODE, &match_evpn_default_route_cmd); install_element(RMAP_NODE, &no_match_evpn_default_route_cmd); install_element(RMAP_NODE, &match_vrl_source_vrf_cmd); 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_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 5c1483a768..49e87adc3c 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -764,7 +764,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) /* Provide dummy so the route-map can't modify * the attributes */ - bgp_attr_dup(&dummy_attr, ri->attr); + dummy_attr = *ri->attr; tmp_info.peer = ri->peer; tmp_info.attr = &dummy_attr; 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 17c93ffc38..0ff64c527b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -32,7 +32,7 @@ #include "thread.h" #include "log.h" #include "memory.h" -#include "memory_vty.h" +#include "lib_vty.h" #include "hash.h" #include "queue.h" #include "filter.h" @@ -64,8 +64,46 @@ #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_io.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_vty.h" #include "bgpd/bgp_addpath.h" #include "bgpd/bgp_mac.h" +#include "bgpd/bgp_flowspec.h" +#if ENABLE_BGP_VNC +#include "bgpd/rfapi/bgp_rfapi_cfg.h" +#endif + +FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK, + { .val_long = true, .match_profile = "datacenter", }, + { .val_long = false }, +) +FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME, + { .val_long = true, .match_profile = "datacenter", }, + { .val_long = false }, +) +FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES, + { .val_long = true, .match_profile = "datacenter", }, + { .val_long = false }, +) +FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED, + { .val_long = true, .match_profile = "datacenter", }, + { .val_long = false }, +) +FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY, + { .val_ulong = 10, .match_profile = "datacenter", }, + { .val_ulong = 120 }, +) +FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME, + { .val_ulong = 9, .match_profile = "datacenter", }, + { .val_ulong = 180 }, +) +FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE, + { .val_ulong = 3, .match_profile = "datacenter", }, + { .val_ulong = 60 }, +) + +DEFINE_HOOK(bgp_inst_config_write, + (struct bgp *bgp, struct vty *vty), + (bgp, vty)) static struct peer_group *listen_range_exists(struct bgp *bgp, struct prefix *range, int exact); @@ -347,6 +385,29 @@ int argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, return ret; } +int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, + enum bgp_instance_type inst_type) +{ + int ret = bgp_get(bgp, as, name, inst_type); + + if (ret == BGP_CREATED) { + bgp_timers_set(*bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME, + DFLT_BGP_CONNECT_RETRY); + + if (DFLT_BGP_IMPORT_CHECK) + bgp_flag_set(*bgp, BGP_FLAG_IMPORT_CHECK); + if (DFLT_BGP_SHOW_HOSTNAME) + bgp_flag_set(*bgp, BGP_FLAG_SHOW_HOSTNAME); + if (DFLT_BGP_LOG_NEIGHBOR_CHANGES) + bgp_flag_set(*bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); + if (DFLT_BGP_DETERMINISTIC_MED) + bgp_flag_set(*bgp, BGP_FLAG_DETERMINISTIC_MED); + + ret = BGP_SUCCESS; + } + return ret; +} + /* * bgp_vty_find_and_parse_afi_safi_bgp * @@ -1068,7 +1129,7 @@ DEFUN_NOSH (router_bgp, if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) is_new_bgp = (bgp_lookup(as, name) == NULL); - ret = bgp_get(&bgp, &as, name, inst_type); + ret = bgp_get_vty(&bgp, &as, name, inst_type); switch (ret) { case BGP_ERR_AS_MISMATCH: vty_out(vty, "BGP is already running; AS is %u\n", as); @@ -1777,8 +1838,8 @@ ALIAS_HIDDEN(no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_hidden_cmd, "Number of paths\n" "Match the cluster length\n") -void bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi) +static void bgp_config_write_maxpaths(struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi) { if (bgp->maxpaths[afi][safi].maxpaths_ebgp != MULTIPATH_NUM) { vty_out(vty, " maximum-paths %d\n", @@ -1821,7 +1882,7 @@ DEFUN (bgp_timers, return CMD_WARNING_CONFIG_FAILED; } - bgp_timers_set(bgp, keepalive, holdtime); + bgp_timers_set(bgp, keepalive, holdtime, DFLT_BGP_CONNECT_RETRY); return CMD_SUCCESS; } @@ -1836,7 +1897,8 @@ DEFUN (no_bgp_timers, "Holdtime\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); - bgp_timers_unset(bgp); + bgp_timers_set(bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME, + DFLT_BGP_CONNECT_RETRY); return CMD_SUCCESS; } @@ -1921,6 +1983,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, @@ -3146,14 +3258,16 @@ DEFUN (no_neighbor, * interface. */ if (peer->ifp) bgp_zebra_terminate_radv(peer->bgp, peer); + peer_notify_unconfig(peer); peer_delete(peer); return CMD_SUCCESS; } group = peer_group_lookup(bgp, argv[idx_peer]->arg); - if (group) + if (group) { + peer_group_notify_unconfig(group); peer_group_delete(group); - else { + } else { vty_out(vty, "%% Create the peer-group first\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -3167,9 +3281,12 @@ DEFUN (no_neighbor, } other = peer->doppelganger; + peer_notify_unconfig(peer); peer_delete(peer); - if (other && other->status != Deleted) + if (other && other->status != Deleted) { + peer_notify_unconfig(other); peer_delete(other); + } } } @@ -3201,6 +3318,7 @@ DEFUN (no_neighbor_interface_config, /* Request zebra to terminate IPv6 RAs on this interface. */ if (peer->ifp) bgp_zebra_terminate_radv(peer->bgp, peer); + peer_notify_unconfig(peer); peer_delete(peer); } else { vty_out(vty, "%% Create the bgp interface first\n"); @@ -3222,9 +3340,10 @@ DEFUN (no_neighbor_peer_group, struct peer_group *group; group = peer_group_lookup(bgp, argv[idx_word]->arg); - if (group) + if (group) { + peer_group_notify_unconfig(group); peer_group_delete(group); - else { + } else { vty_out(vty, "%% Create the peer-group first\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -3582,6 +3701,7 @@ DEFUN (no_neighbor_set_peer_group, return CMD_WARNING_CONFIG_FAILED; } + peer_notify_unconfig(peer); ret = peer_delete(peer); return bgp_vty_return(vty, ret); @@ -6898,8 +7018,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd, as_t as = bgp->as; /* Auto-create assuming the same AS */ - ret = bgp_get(&bgp_default, &as, NULL, - BGP_INSTANCE_TYPE_DEFAULT); + ret = bgp_get_vty(&bgp_default, &as, NULL, + BGP_INSTANCE_TYPE_DEFAULT); if (ret) { vty_out(vty, @@ -6984,8 +7104,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, bgp_default = bgp_get_default(); if (!bgp_default) { /* Auto-create assuming the same AS */ - ret = bgp_get(&bgp_default, &as, NULL, - BGP_INSTANCE_TYPE_DEFAULT); + ret = bgp_get_vty(&bgp_default, &as, NULL, + BGP_INSTANCE_TYPE_DEFAULT); if (ret) { vty_out(vty, @@ -7000,7 +7120,7 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, vrf_bgp = bgp_default; else /* Auto-create assuming the same AS */ - ret = bgp_get(&vrf_bgp, &as, import_name, bgp_type); + ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type); if (ret) { vty_out(vty, @@ -7320,7 +7440,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 @@ -7330,7 +7450,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" @@ -9667,9 +9787,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_neigh, "bgpTimerConfiguredKeepAliveIntervalMsecs", p->keepalive * 1000); - } else if ((bgp->default_holdtime != BGP_DEFAULT_HOLDTIME) - || (bgp->default_keepalive - != BGP_DEFAULT_KEEPALIVE)) { + } else if ((bgp->default_holdtime != SAVE_BGP_HOLDTIME) + || (bgp->default_keepalive != SAVE_BGP_KEEPALIVE)) { json_object_int_add(json_neigh, "bgpTimerConfiguredHoldTimeMsecs", bgp->default_holdtime); @@ -9731,9 +9850,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, p->holdtime); vty_out(vty, ", keepalive interval is %d seconds\n", p->keepalive); - } else if ((bgp->default_holdtime != BGP_DEFAULT_HOLDTIME) - || (bgp->default_keepalive - != BGP_DEFAULT_KEEPALIVE)) { + } else if ((bgp->default_holdtime != SAVE_BGP_HOLDTIME) + || (bgp->default_keepalive != SAVE_BGP_KEEPALIVE)) { vty_out(vty, " Configured hold time is %d", bgp->default_holdtime); vty_out(vty, ", keepalive interval is %d seconds\n", @@ -10888,7 +11006,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); @@ -10897,7 +11015,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); @@ -12751,8 +12869,8 @@ DEFUN (no_bgp_redistribute_ipv6, return bgp_redistribute_unset(bgp, AFI_IP6, type, 0); } -void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi) +static void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi) { int i; @@ -12789,8 +12907,86 @@ void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp, afi_t afi, } } +/* peer-group helpers for config-write */ + +static bool peergroup_flag_check(struct peer *peer, uint32_t flag) +{ + if (!peer_group_active(peer)) { + if (CHECK_FLAG(peer->flags_invert, flag)) + return !CHECK_FLAG(peer->flags, flag); + else + return !!CHECK_FLAG(peer->flags, flag); + } + + return !!CHECK_FLAG(peer->flags_override, flag); +} + +static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, + uint32_t flag) +{ + if (!peer_group_active(peer)) { + if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag)) + return !peer_af_flag_check(peer, afi, safi, flag); + else + return !!peer_af_flag_check(peer, afi, safi, flag); + } + + return !!CHECK_FLAG(peer->af_flags_override[afi][safi], flag); +} + +static bool peergroup_filter_check(struct peer *peer, afi_t afi, safi_t safi, + uint8_t type, int direct) +{ + struct bgp_filter *filter; + + if (peer_group_active(peer)) + return !!CHECK_FLAG(peer->filter_override[afi][safi][direct], + type); + + filter = &peer->filter[afi][safi]; + switch (type) { + case PEER_FT_DISTRIBUTE_LIST: + return !!(filter->dlist[direct].name); + case PEER_FT_FILTER_LIST: + return !!(filter->aslist[direct].name); + case PEER_FT_PREFIX_LIST: + return !!(filter->plist[direct].name); + case PEER_FT_ROUTE_MAP: + return !!(filter->map[direct].name); + case PEER_FT_UNSUPPRESS_MAP: + return !!(filter->usmap.name); + default: + return false; + } +} + +/* Return true if the addpath type is set for peer and different from + * peer-group. + */ +static int peergroup_af_addpath_check(struct peer *peer, afi_t afi, safi_t safi) +{ + enum bgp_addpath_strat type, g_type; + + type = peer->addpath_type[afi][safi]; + + if (type != BGP_ADDPATH_NONE) { + if (peer_group_active(peer)) { + g_type = peer->group->conf->addpath_type[afi][safi]; + + if (type != g_type) + return 1; + else + return 0; + } + + return 1; + } + + return 0; +} + /* This is part of the address-family block (unicast only) */ -void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp, +static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp, afi_t afi) { int indent = 2; @@ -12890,6 +13086,970 @@ void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp, } } +static void bgp_config_write_filter(struct vty *vty, struct peer *peer, + afi_t afi, safi_t safi) +{ + struct bgp_filter *filter; + char *addr; + + addr = peer->host; + filter = &peer->filter[afi][safi]; + + /* distribute-list. */ + if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST, + FILTER_IN)) + vty_out(vty, " neighbor %s distribute-list %s in\n", addr, + filter->dlist[FILTER_IN].name); + + if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST, + FILTER_OUT)) + vty_out(vty, " neighbor %s distribute-list %s out\n", addr, + filter->dlist[FILTER_OUT].name); + + /* prefix-list. */ + if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST, + FILTER_IN)) + vty_out(vty, " neighbor %s prefix-list %s in\n", addr, + filter->plist[FILTER_IN].name); + + if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST, + FILTER_OUT)) + vty_out(vty, " neighbor %s prefix-list %s out\n", addr, + filter->plist[FILTER_OUT].name); + + /* route-map. */ + if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP, RMAP_IN)) + vty_out(vty, " neighbor %s route-map %s in\n", addr, + filter->map[RMAP_IN].name); + + if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP, + RMAP_OUT)) + vty_out(vty, " neighbor %s route-map %s out\n", addr, + filter->map[RMAP_OUT].name); + + /* unsuppress-map */ + if (peergroup_filter_check(peer, afi, safi, PEER_FT_UNSUPPRESS_MAP, 0)) + vty_out(vty, " neighbor %s unsuppress-map %s\n", addr, + filter->usmap.name); + + /* filter-list. */ + if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST, + FILTER_IN)) + vty_out(vty, " neighbor %s filter-list %s in\n", addr, + filter->aslist[FILTER_IN].name); + + if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST, + FILTER_OUT)) + vty_out(vty, " neighbor %s filter-list %s out\n", addr, + filter->aslist[FILTER_OUT].name); +} + +/* BGP peer configuration display function. */ +static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, + struct peer *peer) +{ + struct peer *g_peer = NULL; + char buf[SU_ADDRSTRLEN]; + char *addr; + int if_pg_printed = false; + int if_ras_printed = false; + + /* Skip dynamic neighbors. */ + if (peer_dynamic_neighbor(peer)) + return; + + if (peer->conf_if) + addr = peer->conf_if; + else + addr = peer->host; + + /************************************ + ****** Global to the neighbor ****** + ************************************/ + if (peer->conf_if) { + if (CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) + vty_out(vty, " neighbor %s interface v6only", addr); + else + vty_out(vty, " neighbor %s interface", addr); + + if (peer_group_active(peer)) { + vty_out(vty, " peer-group %s", peer->group->name); + if_pg_printed = true; + } else if (peer->as_type == AS_SPECIFIED) { + vty_out(vty, " remote-as %u", peer->as); + if_ras_printed = true; + } else if (peer->as_type == AS_INTERNAL) { + vty_out(vty, " remote-as internal"); + if_ras_printed = true; + } else if (peer->as_type == AS_EXTERNAL) { + vty_out(vty, " remote-as external"); + if_ras_printed = true; + } + + vty_out(vty, "\n"); + } + + /* remote-as and peer-group */ + /* peer is a member of a peer-group */ + if (peer_group_active(peer)) { + g_peer = peer->group->conf; + + if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed) { + if (peer->as_type == AS_SPECIFIED) { + vty_out(vty, " neighbor %s remote-as %u\n", + addr, peer->as); + } else if (peer->as_type == AS_INTERNAL) { + vty_out(vty, + " neighbor %s remote-as internal\n", + addr); + } else if (peer->as_type == AS_EXTERNAL) { + vty_out(vty, + " neighbor %s remote-as external\n", + addr); + } + } + + /* For swpX peers we displayed the peer-group + * via 'neighbor swpX interface peer-group PGNAME' */ + if (!if_pg_printed) + vty_out(vty, " neighbor %s peer-group %s\n", addr, + peer->group->name); + } + + /* peer is NOT a member of a peer-group */ + else { + /* peer is a peer-group, declare the peer-group */ + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, " neighbor %s peer-group\n", addr); + } + + if (!if_ras_printed) { + if (peer->as_type == AS_SPECIFIED) { + vty_out(vty, " neighbor %s remote-as %u\n", + addr, peer->as); + } else if (peer->as_type == AS_INTERNAL) { + vty_out(vty, + " neighbor %s remote-as internal\n", + addr); + } else if (peer->as_type == AS_EXTERNAL) { + vty_out(vty, + " neighbor %s remote-as external\n", + addr); + } + } + } + + /* local-as */ + if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) { + vty_out(vty, " neighbor %s local-as %u", addr, + peer->change_local_as); + if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND)) + vty_out(vty, " no-prepend"); + if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS)) + vty_out(vty, " replace-as"); + vty_out(vty, "\n"); + } + + /* description */ + if (peer->desc) { + vty_out(vty, " neighbor %s description %s\n", addr, peer->desc); + } + + /* shutdown */ + if (peergroup_flag_check(peer, PEER_FLAG_SHUTDOWN)) { + if (peer->tx_shutdown_message) + vty_out(vty, " neighbor %s shutdown message %s\n", addr, + peer->tx_shutdown_message); + else + vty_out(vty, " neighbor %s shutdown\n", addr); + } + + /* bfd */ + if (peer->bfd_info) { + if (!peer_group_active(peer) || !g_peer->bfd_info) { + bgp_bfd_peer_config_write(vty, peer, addr); + } + } + + /* password */ + if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD)) + vty_out(vty, " neighbor %s password %s\n", addr, + peer->password); + + /* neighbor solo */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)) { + if (!peer_group_active(peer)) { + vty_out(vty, " neighbor %s solo\n", addr); + } + } + + /* BGP port */ + if (peer->port != BGP_PORT_DEFAULT) { + vty_out(vty, " neighbor %s port %d\n", addr, peer->port); + } + + /* Local interface name */ + if (peer->ifname) { + vty_out(vty, " neighbor %s interface %s\n", addr, peer->ifname); + } + + /* passive */ + if (peergroup_flag_check(peer, PEER_FLAG_PASSIVE)) + vty_out(vty, " neighbor %s passive\n", addr); + + /* ebgp-multihop */ + 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, + peer->ttl); + } + } + + /* ttl-security hops */ + if (peer->gtsm_hops != 0) { + if (!peer_group_active(peer) + || g_peer->gtsm_hops != peer->gtsm_hops) { + vty_out(vty, " neighbor %s ttl-security hops %d\n", + addr, peer->gtsm_hops); + } + } + + /* disable-connected-check */ + if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_CONNECTED_CHECK)) + vty_out(vty, " neighbor %s disable-connected-check\n", addr); + + /* enforce-first-as */ + if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) + vty_out(vty, " neighbor %s enforce-first-as\n", addr); + + /* update-source */ + if (peergroup_flag_check(peer, PEER_FLAG_UPDATE_SOURCE)) { + if (peer->update_source) + vty_out(vty, " neighbor %s update-source %s\n", addr, + sockunion2str(peer->update_source, buf, + SU_ADDRSTRLEN)); + else if (peer->update_if) + vty_out(vty, " neighbor %s update-source %s\n", addr, + peer->update_if); + } + + /* advertisement-interval */ + if (peergroup_flag_check(peer, PEER_FLAG_ROUTEADV)) + vty_out(vty, " neighbor %s advertisement-interval %u\n", addr, + peer->routeadv); + + /* timers */ + if (peergroup_flag_check(peer, PEER_FLAG_TIMER)) + vty_out(vty, " neighbor %s timers %u %u\n", addr, + peer->keepalive, peer->holdtime); + + /* timers connect */ + if (peergroup_flag_check(peer, PEER_FLAG_TIMER_CONNECT)) + vty_out(vty, " neighbor %s timers connect %u\n", addr, + peer->connect); + /* need special-case handling for changed default values due to + * config profile / version (because there is no "timers bgp connect" + * command, we need to save this per-peer :/) + */ + else if (!peer_group_active(peer) && !peer->connect && + peer->bgp->default_connect_retry != SAVE_BGP_CONNECT_RETRY) + vty_out(vty, " neighbor %s timers connect %u\n", addr, + peer->bgp->default_connect_retry); + + /* capability dynamic */ + if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) + vty_out(vty, " neighbor %s capability dynamic\n", addr); + + /* capability extended-nexthop */ + if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) { + if (!peer->conf_if) { + if (CHECK_FLAG(peer->flags_invert, + PEER_FLAG_CAPABILITY_ENHE)) + vty_out(vty, + " no neighbor %s capability extended-nexthop\n", + addr); + else + vty_out(vty, + " neighbor %s capability extended-nexthop\n", + addr); + } + } + + /* dont-capability-negotiation */ + if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY)) + vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr); + + /* override-capability */ + if (peergroup_flag_check(peer, PEER_FLAG_OVERRIDE_CAPABILITY)) + vty_out(vty, " neighbor %s override-capability\n", addr); + + /* strict-capability-match */ + if (peergroup_flag_check(peer, PEER_FLAG_STRICT_CAP_MATCH)) + vty_out(vty, " neighbor %s strict-capability-match\n", addr); + + /* Sender side AS path loop detection. */ + if (peer->as_path_loop_detection) + vty_out(vty, " neighbor %s sender-as-path-loop-detection\n", + addr); +} + +/* BGP peer configuration display function. */ +static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, + struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer *g_peer = NULL; + char *addr; + bool flag_scomm, flag_secomm, flag_slcomm; + + /* Skip dynamic neighbors. */ + if (peer_dynamic_neighbor(peer)) + return; + + if (peer->conf_if) + addr = peer->conf_if; + else + addr = peer->host; + + /************************************ + ****** Per AF to the neighbor ****** + ************************************/ + if (peer_group_active(peer)) { + g_peer = peer->group->conf; + + /* If the peer-group is active but peer is not, print a 'no + * activate' */ + if (g_peer->afc[afi][safi] && !peer->afc[afi][safi]) { + vty_out(vty, " no neighbor %s activate\n", addr); + } + + /* If the peer-group is not active but peer is, print an + 'activate' */ + else if (!g_peer->afc[afi][safi] && peer->afc[afi][safi]) { + vty_out(vty, " neighbor %s activate\n", addr); + } + } else { + if (peer->afc[afi][safi]) { + if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { + if (bgp_flag_check(bgp, + BGP_FLAG_NO_DEFAULT_IPV4)) { + vty_out(vty, " neighbor %s activate\n", + addr); + } + } else + vty_out(vty, " neighbor %s activate\n", addr); + } else { + if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { + if (!bgp_flag_check(bgp, + BGP_FLAG_NO_DEFAULT_IPV4)) { + vty_out(vty, + " no neighbor %s activate\n", + addr); + } + } + } + } + + /* addpath TX knobs */ + if (peergroup_af_addpath_check(peer, afi, safi)) { + switch (peer->addpath_type[afi][safi]) { + case BGP_ADDPATH_ALL: + vty_out(vty, " neighbor %s addpath-tx-all-paths\n", + addr); + break; + case BGP_ADDPATH_BEST_PER_AS: + vty_out(vty, + " neighbor %s addpath-tx-bestpath-per-AS\n", + addr); + break; + case BGP_ADDPATH_MAX: + case BGP_ADDPATH_NONE: + break; + } + } + + /* ORF capability. */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) + || peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_ORF_PREFIX_RM)) { + vty_out(vty, " neighbor %s capability orf prefix-list", addr); + + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_ORF_PREFIX_SM) + && peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_ORF_PREFIX_RM)) + vty_out(vty, " both"); + else if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_ORF_PREFIX_SM)) + vty_out(vty, " send"); + else + vty_out(vty, " receive"); + vty_out(vty, "\n"); + } + + /* BGP flag dampening. */ + if (CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_DAMPENING)) + bgp_config_write_damp(vty, afi, safi); + + /* Route reflector client. */ + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_REFLECTOR_CLIENT)) { + vty_out(vty, " neighbor %s route-reflector-client\n", addr); + } + + /* next-hop-self force */ + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_FORCE_NEXTHOP_SELF)) { + vty_out(vty, " neighbor %s next-hop-self force\n", addr); + } + + /* next-hop-self */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)) { + vty_out(vty, " neighbor %s next-hop-self\n", addr); + } + + /* remove-private-AS */ + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) { + vty_out(vty, " neighbor %s remove-private-AS all replace-AS\n", + addr); + } + + else if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) { + vty_out(vty, " neighbor %s remove-private-AS replace-AS\n", + addr); + } + + else if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_REMOVE_PRIVATE_AS_ALL)) { + vty_out(vty, " neighbor %s remove-private-AS all\n", addr); + } + + else if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_REMOVE_PRIVATE_AS)) { + vty_out(vty, " neighbor %s remove-private-AS\n", addr); + } + + /* as-override */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) { + vty_out(vty, " neighbor %s as-override\n", addr); + } + + /* send-community print. */ + flag_scomm = peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_SEND_COMMUNITY); + flag_secomm = peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY); + flag_slcomm = peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_SEND_LARGE_COMMUNITY); + + if (flag_scomm && flag_secomm && flag_slcomm) { + vty_out(vty, " no neighbor %s send-community all\n", addr); + } else { + if (flag_scomm) + vty_out(vty, " no neighbor %s send-community\n", addr); + if (flag_secomm) + vty_out(vty, + " no neighbor %s send-community extended\n", + addr); + + if (flag_slcomm) + vty_out(vty, " no neighbor %s send-community large\n", + addr); + } + + /* Default information */ + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_DEFAULT_ORIGINATE)) { + vty_out(vty, " neighbor %s default-originate", addr); + + if (peer->default_rmap[afi][safi].name) + vty_out(vty, " route-map %s", + peer->default_rmap[afi][safi].name); + + vty_out(vty, "\n"); + } + + /* Soft reconfiguration inbound. */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOFT_RECONFIG)) { + vty_out(vty, " neighbor %s soft-reconfiguration inbound\n", + addr); + } + + /* maximum-prefix. */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX)) { + vty_out(vty, " neighbor %s maximum-prefix %" PRIu32, addr, + peer->pmax[afi][safi]); + + if (peer->pmax_threshold[afi][safi] + != MAXIMUM_PREFIX_THRESHOLD_DEFAULT) + vty_out(vty, " %u", peer->pmax_threshold[afi][safi]); + if (peer_af_flag_check(peer, afi, safi, + PEER_FLAG_MAX_PREFIX_WARNING)) + vty_out(vty, " warning-only"); + if (peer->pmax_restart[afi][safi]) + vty_out(vty, " restart %u", + peer->pmax_restart[afi][safi]); + + vty_out(vty, "\n"); + } + + /* Route server client. */ + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_RSERVER_CLIENT)) { + vty_out(vty, " neighbor %s route-server-client\n", addr); + } + + /* Nexthop-local unchanged. */ + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) { + vty_out(vty, " neighbor %s nexthop-local unchanged\n", addr); + } + + /* allowas-in <1-10> */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) { + if (peer_af_flag_check(peer, afi, safi, + PEER_FLAG_ALLOWAS_IN_ORIGIN)) { + vty_out(vty, " neighbor %s allowas-in origin\n", addr); + } else if (peer->allowas_in[afi][safi] == 3) { + vty_out(vty, " neighbor %s allowas-in\n", addr); + } else { + vty_out(vty, " neighbor %s allowas-in %d\n", addr, + peer->allowas_in[afi][safi]); + } + } + + /* weight */ + if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT)) + vty_out(vty, " neighbor %s weight %lu\n", addr, + peer->weight[afi][safi]); + + /* Filter. */ + bgp_config_write_filter(vty, peer, afi, safi); + + /* atribute-unchanged. */ + if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) + || (safi != SAFI_EVPN + && peer_af_flag_check(peer, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED)) + || peer_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) { + + if (!peer_group_active(peer) + || peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED) + || peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED) + || peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_MED_UNCHANGED)) { + + vty_out(vty, + " neighbor %s attribute-unchanged%s%s%s\n", + addr, + peer_af_flag_check(peer, afi, safi, + PEER_FLAG_AS_PATH_UNCHANGED) + ? " as-path" + : "", + peer_af_flag_check(peer, afi, safi, + PEER_FLAG_NEXTHOP_UNCHANGED) + ? " next-hop" + : "", + peer_af_flag_check(peer, afi, safi, + PEER_FLAG_MED_UNCHANGED) + ? " med" + : ""); + } + } +} + +/* Address family based peer configuration display. */ +static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) +{ + struct peer *peer; + struct peer_group *group; + struct listnode *node, *nnode; + + + vty_frame(vty, " !\n address-family "); + if (afi == AFI_IP) { + if (safi == SAFI_UNICAST) + vty_frame(vty, "ipv4 unicast"); + else if (safi == SAFI_LABELED_UNICAST) + vty_frame(vty, "ipv4 labeled-unicast"); + else if (safi == SAFI_MULTICAST) + vty_frame(vty, "ipv4 multicast"); + else if (safi == SAFI_MPLS_VPN) + vty_frame(vty, "ipv4 vpn"); + else if (safi == SAFI_ENCAP) + vty_frame(vty, "ipv4 encap"); + else if (safi == SAFI_FLOWSPEC) + vty_frame(vty, "ipv4 flowspec"); + } else if (afi == AFI_IP6) { + if (safi == SAFI_UNICAST) + vty_frame(vty, "ipv6 unicast"); + else if (safi == SAFI_LABELED_UNICAST) + vty_frame(vty, "ipv6 labeled-unicast"); + else if (safi == SAFI_MULTICAST) + vty_frame(vty, "ipv6 multicast"); + else if (safi == SAFI_MPLS_VPN) + vty_frame(vty, "ipv6 vpn"); + else if (safi == SAFI_ENCAP) + vty_frame(vty, "ipv6 encap"); + else if (safi == SAFI_FLOWSPEC) + vty_frame(vty, "ipv6 flowspec"); + } else if (afi == AFI_L2VPN) { + if (safi == SAFI_EVPN) + vty_frame(vty, "l2vpn evpn"); + } + vty_frame(vty, "\n"); + + bgp_config_write_distance(vty, bgp, afi, safi); + + bgp_config_write_network(vty, bgp, afi, safi); + + bgp_config_write_redistribute(vty, bgp, afi, safi); + + for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) + bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi); + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + /* Skip dynamic neighbors. */ + if (peer_dynamic_neighbor(peer)) + continue; + + /* Do not display doppelganger peers */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + bgp_config_write_peer_af(vty, bgp, peer, afi, safi); + } + + bgp_config_write_maxpaths(vty, bgp, afi, safi); + bgp_config_write_table_map(vty, bgp, afi, safi); + + if (safi == SAFI_EVPN) + bgp_config_write_evpn_info(vty, bgp, afi, safi); + + if (safi == SAFI_FLOWSPEC) + bgp_fs_config_write_pbr(vty, bgp, afi, safi); + + if (safi == SAFI_UNICAST) { + bgp_vpn_policy_config_write_afi(vty, bgp, afi); + if (CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) { + + vty_out(vty, " export vpn\n"); + } + if (CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) { + + vty_out(vty, " import vpn\n"); + } + if (CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_VRF_TO_VRF_IMPORT)) { + char *name; + + for (ALL_LIST_ELEMENTS_RO( + bgp->vpn_policy[afi].import_vrf, node, + name)) + vty_out(vty, " import vrf %s\n", name); + } + } + + vty_endframe(vty, " exit-address-family\n"); +} + +int bgp_config_write(struct vty *vty) +{ + struct bgp *bgp; + struct peer_group *group; + struct peer *peer; + struct listnode *node, *nnode; + struct listnode *mnode, *mnnode; + + if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER) + vty_out(vty, "bgp route-map delay-timer %u\n", + bm->rmap_update_timer); + + /* BGP configuration. */ + for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { + + /* skip all auto created vrf as they dont have user config */ + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + + /* Router bgp ASN */ + vty_out(vty, "router bgp %u", bgp->as); + + if (bgp->name) + vty_out(vty, " %s %s", + (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) + ? "view" : "vrf", bgp->name); + vty_out(vty, "\n"); + + /* BGP fast-external-failover. */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) + vty_out(vty, " no bgp fast-external-failover\n"); + + /* BGP router ID. */ + if (bgp->router_id_static.s_addr != 0) + vty_out(vty, " bgp router-id %s\n", + inet_ntoa(bgp->router_id_static)); + + /* BGP log-neighbor-changes. */ + if (!!bgp_flag_check(bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES) + != SAVE_BGP_LOG_NEIGHBOR_CHANGES) + vty_out(vty, " %sbgp log-neighbor-changes\n", + bgp_flag_check(bgp, + BGP_FLAG_LOG_NEIGHBOR_CHANGES) + ? "" + : "no "); + + /* BGP configuration. */ + if (bgp_flag_check(bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) + vty_out(vty, " bgp always-compare-med\n"); + + /* RFC8212 default eBGP policy. */ + if (bgp->ebgp_requires_policy + == 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"); + + /* BGP default local-preference. */ + if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF) + vty_out(vty, " bgp default local-preference %u\n", + bgp->default_local_pref); + + /* BGP default show-hostname */ + if (!!bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME) + != SAVE_BGP_SHOW_HOSTNAME) + vty_out(vty, " %sbgp default show-hostname\n", + bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME) + ? "" + : "no "); + + /* BGP default subgroup-pkt-queue-max. */ + if (bgp->default_subgroup_pkt_queue_max + != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX) + vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n", + bgp->default_subgroup_pkt_queue_max); + + /* BGP client-to-client reflection. */ + if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) + vty_out(vty, " no bgp client-to-client reflection\n"); + + /* BGP cluster ID. */ + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID)) + vty_out(vty, " bgp cluster-id %s\n", + inet_ntoa(bgp->cluster_id)); + + /* Disable ebgp connected nexthop check */ + if (bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) + vty_out(vty, + " bgp disable-ebgp-connected-route-check\n"); + + /* Confederation identifier*/ + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) + vty_out(vty, " bgp confederation identifier %u\n", + bgp->confed_id); + + /* Confederation peer */ + if (bgp->confed_peers_cnt > 0) { + int i; + + vty_out(vty, " bgp confederation peers"); + + for (i = 0; i < bgp->confed_peers_cnt; i++) + vty_out(vty, " %u", bgp->confed_peers[i]); + + vty_out(vty, "\n"); + } + + /* BGP deterministic-med. */ + if (!!bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED) + != SAVE_BGP_DETERMINISTIC_MED) + vty_out(vty, " %sbgp deterministic-med\n", + bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED) + ? "" + : "no "); + + /* BGP update-delay. */ + bgp_config_write_update_delay(vty, bgp); + + if (bgp->v_maxmed_onstartup + != BGP_MAXMED_ONSTARTUP_UNCONFIGURED) { + vty_out(vty, " bgp max-med on-startup %u", + bgp->v_maxmed_onstartup); + if (bgp->maxmed_onstartup_value + != BGP_MAXMED_VALUE_DEFAULT) + vty_out(vty, " %u", + bgp->maxmed_onstartup_value); + vty_out(vty, "\n"); + } + if (bgp->v_maxmed_admin != BGP_MAXMED_ADMIN_UNCONFIGURED) { + vty_out(vty, " bgp max-med administrative"); + if (bgp->maxmed_admin_value != BGP_MAXMED_VALUE_DEFAULT) + vty_out(vty, " %u", bgp->maxmed_admin_value); + vty_out(vty, "\n"); + } + + /* write quanta */ + bgp_config_write_wpkt_quanta(vty, bgp); + /* read quanta */ + bgp_config_write_rpkt_quanta(vty, bgp); + + /* coalesce time */ + bgp_config_write_coalesce_time(vty, bgp); + + /* BGP graceful-restart. */ + if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, + " bgp graceful-restart stalepath-time %u\n", + bgp->stalepath_time); + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, " bgp graceful-restart restart-time %u\n", + bgp->restart_time); + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART)) + vty_out(vty, " bgp graceful-restart\n"); + + /* BGP graceful-shutdown */ + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) + vty_out(vty, " bgp graceful-shutdown\n"); + + /* BGP graceful-restart Preserve State F bit. */ + if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, + " bgp graceful-restart preserve-fw-state\n"); + + /* BGP bestpath method. */ + if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_IGNORE)) + vty_out(vty, " bgp bestpath as-path ignore\n"); + if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_CONFED)) + vty_out(vty, " bgp bestpath as-path confed\n"); + + if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { + if (bgp_flag_check(bgp, + BGP_FLAG_MULTIPATH_RELAX_AS_SET)) { + vty_out(vty, + " bgp bestpath as-path multipath-relax as-set\n"); + } else { + vty_out(vty, + " bgp bestpath as-path multipath-relax\n"); + } + } + + if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { + vty_out(vty, + " bgp route-reflector allow-outbound-policy\n"); + } + if (bgp_flag_check(bgp, BGP_FLAG_COMPARE_ROUTER_ID)) + vty_out(vty, " bgp bestpath compare-routerid\n"); + if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED) + || bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST)) { + vty_out(vty, " bgp bestpath med"); + if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED)) + vty_out(vty, " confed"); + if (bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST)) + vty_out(vty, " missing-as-worst"); + vty_out(vty, "\n"); + } + + /* BGP network import check. */ + if (!!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK) + != SAVE_BGP_IMPORT_CHECK) + vty_out(vty, " %sbgp network import-check\n", + bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK) + ? "" + : "no "); + + /* BGP timers configuration. */ + if (bgp->default_keepalive != SAVE_BGP_KEEPALIVE + && bgp->default_holdtime != SAVE_BGP_HOLDTIME) + vty_out(vty, " timers bgp %u %u\n", + bgp->default_keepalive, bgp->default_holdtime); + + /* peer-group */ + for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) { + bgp_config_write_peer_global(vty, bgp, group->conf); + } + + /* Normal neighbor configuration. */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + bgp_config_write_peer_global(vty, bgp, peer); + } + + /* listen range and limit for dynamic BGP neighbors */ + bgp_config_write_listen(vty, bgp); + + /* + * BGP default autoshutdown neighbors + * + * This must be placed after any peer and peer-group + * configuration, to avoid setting all peers to shutdown after + * a daemon restart, which is undesired behavior. (see #2286) + */ + if (bgp->autoshutdown) + vty_out(vty, " bgp default shutdown\n"); + + /* IPv4 unicast configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST); + + /* IPv4 multicast configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MULTICAST); + + /* IPv4 labeled-unicast configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_LABELED_UNICAST); + + /* IPv4 VPN configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MPLS_VPN); + + /* ENCAPv4 configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP); + + /* FLOWSPEC v4 configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_FLOWSPEC); + + /* IPv6 unicast configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_UNICAST); + + /* IPv6 multicast configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MULTICAST); + + /* IPv6 labeled-unicast configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP6, + SAFI_LABELED_UNICAST); + + /* IPv6 VPN configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MPLS_VPN); + + /* ENCAPv6 configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP); + + /* FLOWSPEC v6 configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_FLOWSPEC); + + /* EVPN configuration. */ + bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); + + hook_call(bgp_inst_config_write, bgp, vty); + +#if ENABLE_BGP_VNC + bgp_rfapi_cfg_write(vty, bgp); +#endif + + vty_out(vty, "!\n"); + } + return 0; +} + /* BGP node structure. */ static struct cmd_node bgp_node = { @@ -13128,6 +14288,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_vty.h b/bgpd/bgp_vty.h index 27b5ea47b2..5f3ce9cd8e 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -21,6 +21,8 @@ #ifndef _QUAGGA_BGP_VTY_H #define _QUAGGA_BGP_VTY_H +#include "bgpd/bgpd.h" + struct bgp; #define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n" @@ -46,6 +48,8 @@ struct bgp; extern void bgp_vty_init(void); extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json); +extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, + enum bgp_instance_type inst_type); extern void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp); extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp); extern void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp); @@ -72,6 +76,5 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, bool use_json); extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, safi_t safi, bool show_failed, bool use_json); -extern void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp, - afi_t afi); + #endif /* _QUAGGA_BGP_VTY_H */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d0a732b153..069c53d7df 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) @@ -1069,7 +1072,7 @@ static int update_ipv4nh_for_route_install(int nh_othervrf, */ if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - api_nh->onlink = true; + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; } else if (nh_othervrf && api_nh->gate.ipv4.s_addr == INADDR_ANY) { @@ -1095,7 +1098,7 @@ update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, if (is_evpn) { api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; - api_nh->onlink = true; + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; } else if (nh_othervrf) { if (IN6_IS_ADDR_UNSPECIFIED(nexthop)) { @@ -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)) @@ -1344,6 +1347,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, has_valid_label = 1; label = label_pton(&mpinfo->extra->label[0]); + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL); + api_nh->label_num = 1; api_nh->labels[0] = label; } @@ -1352,11 +1357,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, valid_nh_count++; } - - /* if this is a evpn route we don't have to include the label */ - if (has_valid_label && !(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))) - SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); - /* * When we create an aggregate route we must also * install a Null0 route in the RIB, so overwrite @@ -1690,7 +1690,7 @@ int bgp_redistribute_metric_set(struct bgp *bgp, struct bgp_redist *red, struct attr *old_attr; struct attr new_attr; - bgp_attr_dup(&new_attr, pi->attr); + new_attr = *pi->attr; new_attr.med = red->redist_metric; old_attr = pi->attr; pi->attr = bgp_attr_intern(&new_attr); @@ -2469,30 +2469,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/bgp_zebra.h b/bgpd/bgp_zebra.h index b912870b80..62c311cc1d 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -32,10 +32,6 @@ extern void bgp_zebra_destroy(void); extern int bgp_zebra_get_table_range(uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int bgp_if_update_all(void); -extern void bgp_config_write_maxpaths(struct vty *, struct bgp *, afi_t, - safi_t); -extern void bgp_config_write_redistribute(struct vty *, struct bgp *, afi_t, - safi_t); extern void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, struct bgp_path_info *path, struct bgp *bgp, afi_t afi, safi_t safi); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e6a742d9c4..9b0e81491a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -95,9 +95,6 @@ DEFINE_QOBJ_TYPE(bgp_master) DEFINE_QOBJ_TYPE(bgp) DEFINE_QOBJ_TYPE(peer) DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)) -DEFINE_HOOK(bgp_inst_config_write, - (struct bgp *bgp, struct vty *vty), - (bgp, vty)) /* BGP process wide configuration. */ static struct bgp_master bgp_master; @@ -407,19 +404,23 @@ time_t bgp_clock(void) } /* BGP timer configuration. */ -int bgp_timers_set(struct bgp *bgp, uint32_t keepalive, uint32_t holdtime) +int bgp_timers_set(struct bgp *bgp, uint32_t keepalive, uint32_t holdtime, + uint32_t connect_retry) { bgp->default_keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3); bgp->default_holdtime = holdtime; + bgp->default_connect_retry = connect_retry; return 0; } +/* mostly for completeness - CLI uses its own defaults */ int bgp_timers_unset(struct bgp *bgp) { bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; + bgp->default_connect_retry = BGP_DEFAULT_CONNECT_RETRY; return 0; } @@ -883,82 +884,6 @@ void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi, COND_FLAG(peer->af_flags[afi][safi], flag, group_val); } -static bool peergroup_flag_check(struct peer *peer, uint32_t flag) -{ - if (!peer_group_active(peer)) { - if (CHECK_FLAG(peer->flags_invert, flag)) - return !CHECK_FLAG(peer->flags, flag); - else - return !!CHECK_FLAG(peer->flags, flag); - } - - return !!CHECK_FLAG(peer->flags_override, flag); -} - -static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, - uint32_t flag) -{ - if (!peer_group_active(peer)) { - if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag)) - return !peer_af_flag_check(peer, afi, safi, flag); - else - return !!peer_af_flag_check(peer, afi, safi, flag); - } - - return !!CHECK_FLAG(peer->af_flags_override[afi][safi], flag); -} - -static bool peergroup_filter_check(struct peer *peer, afi_t afi, safi_t safi, - uint8_t type, int direct) -{ - struct bgp_filter *filter; - - if (peer_group_active(peer)) - return !!CHECK_FLAG(peer->filter_override[afi][safi][direct], - type); - - filter = &peer->filter[afi][safi]; - switch (type) { - case PEER_FT_DISTRIBUTE_LIST: - return !!(filter->dlist[direct].name); - case PEER_FT_FILTER_LIST: - return !!(filter->aslist[direct].name); - case PEER_FT_PREFIX_LIST: - return !!(filter->plist[direct].name); - case PEER_FT_ROUTE_MAP: - return !!(filter->map[direct].name); - case PEER_FT_UNSUPPRESS_MAP: - return !!(filter->usmap.name); - default: - return false; - } -} - -/* Return true if the addpath type is set for peer and different from - * peer-group. - */ -static int peergroup_af_addpath_check(struct peer *peer, afi_t afi, safi_t safi) -{ - enum bgp_addpath_strat type, g_type; - - type = peer->addpath_type[afi][safi]; - - if (type != BGP_ADDPATH_NONE) { - if (peer_group_active(peer)) { - g_type = peer->group->conf->addpath_type[afi][safi]; - - if (type != g_type) - return 1; - else - return 0; - } - - return 1; - } - - return 0; -} - /* Check peer's AS number and determines if this peer is IBGP or EBGP */ static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer) { @@ -1197,7 +1122,7 @@ struct peer *peer_new(struct bgp *bgp) /* Set default value. */ peer->fd = -1; peer->v_start = BGP_INIT_START_TIMER; - peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + peer->v_connect = bgp->default_connect_retry; peer->status = Idle; peer->ostatus = Idle; peer->cur_event = peer->last_event = peer->last_major_event = 0; @@ -2496,7 +2421,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, if (CHECK_FLAG(conf->flags, PEER_FLAG_TIMER_CONNECT)) peer->v_connect = conf->connect; else - peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + peer->v_connect = peer->bgp->default_connect_retry; } /* advertisement-interval apply */ @@ -2562,6 +2487,30 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, return 0; } +int peer_notify_unconfig(struct peer *peer) +{ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_PEER_UNCONFIG); + return 0; +} + +int peer_group_notify_unconfig(struct peer_group *group) +{ + struct peer *peer, *other; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + other = peer->doppelganger; + if (other && other->status != Deleted) { + other->group = NULL; + peer_notify_unconfig(other); + } else + peer_notify_unconfig(peer); + } + return 0; +} + int peer_group_delete(struct peer_group *group) { struct bgp *bgp; @@ -2959,25 +2908,13 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX; - bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; - bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; + bgp_timers_unset(bgp); bgp->restart_time = BGP_DEFAULT_RESTART_TIME; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; bgp->dynamic_neighbors_count = 0; bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED; -#if DFLT_BGP_IMPORT_CHECK - bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK); -#endif -#if DFLT_BGP_SHOW_HOSTNAME - bgp_flag_set(bgp, BGP_FLAG_SHOW_HOSTNAME); -#endif -#if DFLT_BGP_LOG_NEIGHBOR_CHANGES - bgp_flag_set(bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); -#endif -#if DFLT_BGP_DETERMINISTIC_MED - bgp_flag_set(bgp, BGP_FLAG_DETERMINISTIC_MED); -#endif + bgp->reject_as_sets = BGP_REJECT_AS_SETS_DISABLED; bgp_addpath_init_bgp_data(&bgp->tx_addpath); bgp->as = *as; @@ -3230,7 +3167,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, bgp_zebra_instance_register(bgp); } - return BGP_SUCCESS; + return BGP_CREATED; } /* @@ -5034,7 +4971,7 @@ int peer_timers_connect_unset(struct peer *peer) if (peer->connect) peer->v_connect = peer->connect; else - peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + peer->v_connect = peer->bgp->default_connect_retry; /* Skip peer-group mechanics for regular peers. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) @@ -5052,7 +4989,7 @@ int peer_timers_connect_unset(struct peer *peer) /* Remove flag and configuration on peer-group member. */ UNSET_FLAG(member->flags, PEER_FLAG_TIMER_CONNECT); member->connect = 0; - member->v_connect = BGP_DEFAULT_CONNECT_RETRY; + member->v_connect = peer->bgp->default_connect_retry; } return 0; @@ -6533,16 +6470,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; @@ -6873,958 +6811,6 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, return buf; } -static void bgp_config_write_filter(struct vty *vty, struct peer *peer, - afi_t afi, safi_t safi) -{ - struct bgp_filter *filter; - char *addr; - - addr = peer->host; - filter = &peer->filter[afi][safi]; - - /* distribute-list. */ - if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST, - FILTER_IN)) - vty_out(vty, " neighbor %s distribute-list %s in\n", addr, - filter->dlist[FILTER_IN].name); - - if (peergroup_filter_check(peer, afi, safi, PEER_FT_DISTRIBUTE_LIST, - FILTER_OUT)) - vty_out(vty, " neighbor %s distribute-list %s out\n", addr, - filter->dlist[FILTER_OUT].name); - - /* prefix-list. */ - if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST, - FILTER_IN)) - vty_out(vty, " neighbor %s prefix-list %s in\n", addr, - filter->plist[FILTER_IN].name); - - if (peergroup_filter_check(peer, afi, safi, PEER_FT_PREFIX_LIST, - FILTER_OUT)) - vty_out(vty, " neighbor %s prefix-list %s out\n", addr, - filter->plist[FILTER_OUT].name); - - /* route-map. */ - if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP, RMAP_IN)) - vty_out(vty, " neighbor %s route-map %s in\n", addr, - filter->map[RMAP_IN].name); - - if (peergroup_filter_check(peer, afi, safi, PEER_FT_ROUTE_MAP, - RMAP_OUT)) - vty_out(vty, " neighbor %s route-map %s out\n", addr, - filter->map[RMAP_OUT].name); - - /* unsuppress-map */ - if (peergroup_filter_check(peer, afi, safi, PEER_FT_UNSUPPRESS_MAP, 0)) - vty_out(vty, " neighbor %s unsuppress-map %s\n", addr, - filter->usmap.name); - - /* filter-list. */ - if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST, - FILTER_IN)) - vty_out(vty, " neighbor %s filter-list %s in\n", addr, - filter->aslist[FILTER_IN].name); - - if (peergroup_filter_check(peer, afi, safi, PEER_FT_FILTER_LIST, - FILTER_OUT)) - vty_out(vty, " neighbor %s filter-list %s out\n", addr, - filter->aslist[FILTER_OUT].name); -} - -/* BGP peer configuration display function. */ -static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, - struct peer *peer) -{ - struct peer *g_peer = NULL; - char buf[SU_ADDRSTRLEN]; - char *addr; - int if_pg_printed = false; - int if_ras_printed = false; - - /* Skip dynamic neighbors. */ - if (peer_dynamic_neighbor(peer)) - return; - - if (peer->conf_if) - addr = peer->conf_if; - else - addr = peer->host; - - /************************************ - ****** Global to the neighbor ****** - ************************************/ - if (peer->conf_if) { - if (CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) - vty_out(vty, " neighbor %s interface v6only", addr); - else - vty_out(vty, " neighbor %s interface", addr); - - if (peer_group_active(peer)) { - vty_out(vty, " peer-group %s", peer->group->name); - if_pg_printed = true; - } else if (peer->as_type == AS_SPECIFIED) { - vty_out(vty, " remote-as %u", peer->as); - if_ras_printed = true; - } else if (peer->as_type == AS_INTERNAL) { - vty_out(vty, " remote-as internal"); - if_ras_printed = true; - } else if (peer->as_type == AS_EXTERNAL) { - vty_out(vty, " remote-as external"); - if_ras_printed = true; - } - - vty_out(vty, "\n"); - } - - /* remote-as and peer-group */ - /* peer is a member of a peer-group */ - if (peer_group_active(peer)) { - g_peer = peer->group->conf; - - if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed) { - if (peer->as_type == AS_SPECIFIED) { - vty_out(vty, " neighbor %s remote-as %u\n", - addr, peer->as); - } else if (peer->as_type == AS_INTERNAL) { - vty_out(vty, - " neighbor %s remote-as internal\n", - addr); - } else if (peer->as_type == AS_EXTERNAL) { - vty_out(vty, - " neighbor %s remote-as external\n", - addr); - } - } - - /* For swpX peers we displayed the peer-group - * via 'neighbor swpX interface peer-group PGNAME' */ - if (!if_pg_printed) - vty_out(vty, " neighbor %s peer-group %s\n", addr, - peer->group->name); - } - - /* peer is NOT a member of a peer-group */ - else { - /* peer is a peer-group, declare the peer-group */ - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - vty_out(vty, " neighbor %s peer-group\n", addr); - } - - if (!if_ras_printed) { - if (peer->as_type == AS_SPECIFIED) { - vty_out(vty, " neighbor %s remote-as %u\n", - addr, peer->as); - } else if (peer->as_type == AS_INTERNAL) { - vty_out(vty, - " neighbor %s remote-as internal\n", - addr); - } else if (peer->as_type == AS_EXTERNAL) { - vty_out(vty, - " neighbor %s remote-as external\n", - addr); - } - } - } - - /* local-as */ - if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS)) { - vty_out(vty, " neighbor %s local-as %u", addr, - peer->change_local_as); - if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND)) - vty_out(vty, " no-prepend"); - if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS)) - vty_out(vty, " replace-as"); - vty_out(vty, "\n"); - } - - /* description */ - if (peer->desc) { - vty_out(vty, " neighbor %s description %s\n", addr, peer->desc); - } - - /* shutdown */ - if (peergroup_flag_check(peer, PEER_FLAG_SHUTDOWN)) { - if (peer->tx_shutdown_message) - vty_out(vty, " neighbor %s shutdown message %s\n", addr, - peer->tx_shutdown_message); - else - vty_out(vty, " neighbor %s shutdown\n", addr); - } - - /* bfd */ - if (peer->bfd_info) { - if (!peer_group_active(peer) || !g_peer->bfd_info) { - bgp_bfd_peer_config_write(vty, peer, addr); - } - } - - /* password */ - if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD)) - vty_out(vty, " neighbor %s password %s\n", addr, - peer->password); - - /* neighbor solo */ - if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)) { - if (!peer_group_active(peer)) { - vty_out(vty, " neighbor %s solo\n", addr); - } - } - - /* BGP port */ - if (peer->port != BGP_PORT_DEFAULT) { - vty_out(vty, " neighbor %s port %d\n", addr, peer->port); - } - - /* Local interface name */ - if (peer->ifname) { - vty_out(vty, " neighbor %s interface %s\n", addr, peer->ifname); - } - - /* passive */ - if (peergroup_flag_check(peer, PEER_FLAG_PASSIVE)) - vty_out(vty, " neighbor %s passive\n", addr); - - /* ebgp-multihop */ - if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 - && !(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, - peer->ttl); - } - } - - /* ttl-security hops */ - if (peer->gtsm_hops != 0) { - if (!peer_group_active(peer) - || g_peer->gtsm_hops != peer->gtsm_hops) { - vty_out(vty, " neighbor %s ttl-security hops %d\n", - addr, peer->gtsm_hops); - } - } - - /* disable-connected-check */ - if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_CONNECTED_CHECK)) - vty_out(vty, " neighbor %s disable-connected-check\n", addr); - - /* enforce-first-as */ - if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) - vty_out(vty, " neighbor %s enforce-first-as\n", addr); - - /* update-source */ - if (peergroup_flag_check(peer, PEER_FLAG_UPDATE_SOURCE)) { - if (peer->update_source) - vty_out(vty, " neighbor %s update-source %s\n", addr, - sockunion2str(peer->update_source, buf, - SU_ADDRSTRLEN)); - else if (peer->update_if) - vty_out(vty, " neighbor %s update-source %s\n", addr, - peer->update_if); - } - - /* advertisement-interval */ - if (peergroup_flag_check(peer, PEER_FLAG_ROUTEADV)) - vty_out(vty, " neighbor %s advertisement-interval %u\n", addr, - peer->routeadv); - - /* timers */ - if (peergroup_flag_check(peer, PEER_FLAG_TIMER)) - vty_out(vty, " neighbor %s timers %u %u\n", addr, - peer->keepalive, peer->holdtime); - - /* timers connect */ - if (peergroup_flag_check(peer, PEER_FLAG_TIMER_CONNECT)) - vty_out(vty, " neighbor %s timers connect %u\n", addr, - peer->connect); - - /* capability dynamic */ - if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) - vty_out(vty, " neighbor %s capability dynamic\n", addr); - - /* capability extended-nexthop */ - if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) { - if (!peer->conf_if) { - if (CHECK_FLAG(peer->flags_invert, - PEER_FLAG_CAPABILITY_ENHE)) - vty_out(vty, - " no neighbor %s capability extended-nexthop\n", - addr); - else - vty_out(vty, - " neighbor %s capability extended-nexthop\n", - addr); - } - } - - /* dont-capability-negotiation */ - if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY)) - vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr); - - /* override-capability */ - if (peergroup_flag_check(peer, PEER_FLAG_OVERRIDE_CAPABILITY)) - vty_out(vty, " neighbor %s override-capability\n", addr); - - /* strict-capability-match */ - if (peergroup_flag_check(peer, PEER_FLAG_STRICT_CAP_MATCH)) - vty_out(vty, " neighbor %s strict-capability-match\n", addr); - - /* Sender side AS path loop detection. */ - if (peer->as_path_loop_detection) - vty_out(vty, " neighbor %s sender-as-path-loop-detection\n", - addr); -} - -/* BGP peer configuration display function. */ -static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, - struct peer *peer, afi_t afi, safi_t safi) -{ - struct peer *g_peer = NULL; - char *addr; - bool flag_scomm, flag_secomm, flag_slcomm; - - /* Skip dynamic neighbors. */ - if (peer_dynamic_neighbor(peer)) - return; - - if (peer->conf_if) - addr = peer->conf_if; - else - addr = peer->host; - - /************************************ - ****** Per AF to the neighbor ****** - ************************************/ - if (peer_group_active(peer)) { - g_peer = peer->group->conf; - - /* If the peer-group is active but peer is not, print a 'no - * activate' */ - if (g_peer->afc[afi][safi] && !peer->afc[afi][safi]) { - vty_out(vty, " no neighbor %s activate\n", addr); - } - - /* If the peer-group is not active but peer is, print an - 'activate' */ - else if (!g_peer->afc[afi][safi] && peer->afc[afi][safi]) { - vty_out(vty, " neighbor %s activate\n", addr); - } - } else { - if (peer->afc[afi][safi]) { - if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { - if (bgp_flag_check(bgp, - BGP_FLAG_NO_DEFAULT_IPV4)) { - vty_out(vty, " neighbor %s activate\n", - addr); - } - } else - vty_out(vty, " neighbor %s activate\n", addr); - } else { - if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { - if (!bgp_flag_check(bgp, - BGP_FLAG_NO_DEFAULT_IPV4)) { - vty_out(vty, - " no neighbor %s activate\n", - addr); - } - } - } - } - - /* addpath TX knobs */ - if (peergroup_af_addpath_check(peer, afi, safi)) { - switch (peer->addpath_type[afi][safi]) { - case BGP_ADDPATH_ALL: - vty_out(vty, " neighbor %s addpath-tx-all-paths\n", - addr); - break; - case BGP_ADDPATH_BEST_PER_AS: - vty_out(vty, - " neighbor %s addpath-tx-bestpath-per-AS\n", - addr); - break; - case BGP_ADDPATH_MAX: - case BGP_ADDPATH_NONE: - break; - } - } - - /* ORF capability. */ - if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) - || peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_ORF_PREFIX_RM)) { - vty_out(vty, " neighbor %s capability orf prefix-list", addr); - - if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_ORF_PREFIX_SM) - && peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_ORF_PREFIX_RM)) - vty_out(vty, " both"); - else if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_ORF_PREFIX_SM)) - vty_out(vty, " send"); - else - vty_out(vty, " receive"); - vty_out(vty, "\n"); - } - - /* BGP flag dampening. */ - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_DAMPENING)) - bgp_config_write_damp(vty, afi, safi); - - /* Route reflector client. */ - if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_REFLECTOR_CLIENT)) { - vty_out(vty, " neighbor %s route-reflector-client\n", addr); - } - - /* next-hop-self force */ - if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_FORCE_NEXTHOP_SELF)) { - vty_out(vty, " neighbor %s next-hop-self force\n", addr); - } - - /* next-hop-self */ - if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)) { - vty_out(vty, " neighbor %s next-hop-self\n", addr); - } - - /* remove-private-AS */ - if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) { - vty_out(vty, " neighbor %s remove-private-AS all replace-AS\n", - addr); - } - - else if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) { - vty_out(vty, " neighbor %s remove-private-AS replace-AS\n", - addr); - } - - else if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_REMOVE_PRIVATE_AS_ALL)) { - vty_out(vty, " neighbor %s remove-private-AS all\n", addr); - } - - else if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_REMOVE_PRIVATE_AS)) { - vty_out(vty, " neighbor %s remove-private-AS\n", addr); - } - - /* as-override */ - if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) { - vty_out(vty, " neighbor %s as-override\n", addr); - } - - /* send-community print. */ - flag_scomm = peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_SEND_COMMUNITY); - flag_secomm = peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_SEND_EXT_COMMUNITY); - flag_slcomm = peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_SEND_LARGE_COMMUNITY); - - if (flag_scomm && flag_secomm && flag_slcomm) { - vty_out(vty, " no neighbor %s send-community all\n", addr); - } else { - if (flag_scomm) - vty_out(vty, " no neighbor %s send-community\n", addr); - if (flag_secomm) - vty_out(vty, - " no neighbor %s send-community extended\n", - addr); - - if (flag_slcomm) - vty_out(vty, " no neighbor %s send-community large\n", - addr); - } - - /* Default information */ - if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_DEFAULT_ORIGINATE)) { - vty_out(vty, " neighbor %s default-originate", addr); - - if (peer->default_rmap[afi][safi].name) - vty_out(vty, " route-map %s", - peer->default_rmap[afi][safi].name); - - vty_out(vty, "\n"); - } - - /* Soft reconfiguration inbound. */ - if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOFT_RECONFIG)) { - vty_out(vty, " neighbor %s soft-reconfiguration inbound\n", - addr); - } - - /* maximum-prefix. */ - if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX)) { - vty_out(vty, " neighbor %s maximum-prefix %" PRIu32, addr, - peer->pmax[afi][safi]); - - if (peer->pmax_threshold[afi][safi] - != MAXIMUM_PREFIX_THRESHOLD_DEFAULT) - vty_out(vty, " %u", peer->pmax_threshold[afi][safi]); - if (peer_af_flag_check(peer, afi, safi, - PEER_FLAG_MAX_PREFIX_WARNING)) - vty_out(vty, " warning-only"); - if (peer->pmax_restart[afi][safi]) - vty_out(vty, " restart %u", - peer->pmax_restart[afi][safi]); - - vty_out(vty, "\n"); - } - - /* Route server client. */ - if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_RSERVER_CLIENT)) { - vty_out(vty, " neighbor %s route-server-client\n", addr); - } - - /* Nexthop-local unchanged. */ - if (peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) { - vty_out(vty, " neighbor %s nexthop-local unchanged\n", addr); - } - - /* allowas-in <1-10> */ - if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) { - if (peer_af_flag_check(peer, afi, safi, - PEER_FLAG_ALLOWAS_IN_ORIGIN)) { - vty_out(vty, " neighbor %s allowas-in origin\n", addr); - } else if (peer->allowas_in[afi][safi] == 3) { - vty_out(vty, " neighbor %s allowas-in\n", addr); - } else { - vty_out(vty, " neighbor %s allowas-in %d\n", addr, - peer->allowas_in[afi][safi]); - } - } - - /* weight */ - if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT)) - vty_out(vty, " neighbor %s weight %lu\n", addr, - peer->weight[afi][safi]); - - /* Filter. */ - bgp_config_write_filter(vty, peer, afi, safi); - - /* atribute-unchanged. */ - if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) - || (safi != SAFI_EVPN - && peer_af_flag_check(peer, afi, safi, - PEER_FLAG_NEXTHOP_UNCHANGED)) - || peer_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) { - - if (!peer_group_active(peer) - || peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_AS_PATH_UNCHANGED) - || peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_NEXTHOP_UNCHANGED) - || peergroup_af_flag_check(peer, afi, safi, - PEER_FLAG_MED_UNCHANGED)) { - - vty_out(vty, - " neighbor %s attribute-unchanged%s%s%s\n", - addr, - peer_af_flag_check(peer, afi, safi, - PEER_FLAG_AS_PATH_UNCHANGED) - ? " as-path" - : "", - peer_af_flag_check(peer, afi, safi, - PEER_FLAG_NEXTHOP_UNCHANGED) - ? " next-hop" - : "", - peer_af_flag_check(peer, afi, safi, - PEER_FLAG_MED_UNCHANGED) - ? " med" - : ""); - } - } -} - -/* Address family based peer configuration display. */ -static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, - safi_t safi) -{ - struct peer *peer; - struct peer_group *group; - struct listnode *node, *nnode; - - - vty_frame(vty, " !\n address-family "); - if (afi == AFI_IP) { - if (safi == SAFI_UNICAST) - vty_frame(vty, "ipv4 unicast"); - else if (safi == SAFI_LABELED_UNICAST) - vty_frame(vty, "ipv4 labeled-unicast"); - else if (safi == SAFI_MULTICAST) - vty_frame(vty, "ipv4 multicast"); - else if (safi == SAFI_MPLS_VPN) - vty_frame(vty, "ipv4 vpn"); - else if (safi == SAFI_ENCAP) - vty_frame(vty, "ipv4 encap"); - else if (safi == SAFI_FLOWSPEC) - vty_frame(vty, "ipv4 flowspec"); - } else if (afi == AFI_IP6) { - if (safi == SAFI_UNICAST) - vty_frame(vty, "ipv6 unicast"); - else if (safi == SAFI_LABELED_UNICAST) - vty_frame(vty, "ipv6 labeled-unicast"); - else if (safi == SAFI_MULTICAST) - vty_frame(vty, "ipv6 multicast"); - else if (safi == SAFI_MPLS_VPN) - vty_frame(vty, "ipv6 vpn"); - else if (safi == SAFI_ENCAP) - vty_frame(vty, "ipv6 encap"); - else if (safi == SAFI_FLOWSPEC) - vty_frame(vty, "ipv6 flowspec"); - } else if (afi == AFI_L2VPN) { - if (safi == SAFI_EVPN) - vty_frame(vty, "l2vpn evpn"); - } - vty_frame(vty, "\n"); - - bgp_config_write_distance(vty, bgp, afi, safi); - - bgp_config_write_network(vty, bgp, afi, safi); - - bgp_config_write_redistribute(vty, bgp, afi, safi); - - for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) - bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi); - - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - /* Skip dynamic neighbors. */ - if (peer_dynamic_neighbor(peer)) - continue; - - /* Do not display doppelganger peers */ - if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) - bgp_config_write_peer_af(vty, bgp, peer, afi, safi); - } - - bgp_config_write_maxpaths(vty, bgp, afi, safi); - bgp_config_write_table_map(vty, bgp, afi, safi); - - if (safi == SAFI_EVPN) - bgp_config_write_evpn_info(vty, bgp, afi, safi); - - if (safi == SAFI_FLOWSPEC) - bgp_fs_config_write_pbr(vty, bgp, afi, safi); - - if (safi == SAFI_UNICAST) { - bgp_vpn_policy_config_write_afi(vty, bgp, afi); - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)) { - - vty_out(vty, " export vpn\n"); - } - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)) { - - vty_out(vty, " import vpn\n"); - } - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_VRF_TO_VRF_IMPORT)) { - char *name; - - for (ALL_LIST_ELEMENTS_RO( - bgp->vpn_policy[afi].import_vrf, node, - name)) - vty_out(vty, " import vrf %s\n", name); - } - } - - vty_endframe(vty, " exit-address-family\n"); -} - -int bgp_config_write(struct vty *vty) -{ - struct bgp *bgp; - struct peer_group *group; - struct peer *peer; - struct listnode *node, *nnode; - struct listnode *mnode, *mnnode; - - if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER) - vty_out(vty, "bgp route-map delay-timer %u\n", - bm->rmap_update_timer); - - /* BGP configuration. */ - for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { - - /* skip all auto created vrf as they dont have user config */ - if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) - continue; - - /* Router bgp ASN */ - vty_out(vty, "router bgp %u", bgp->as); - - if (bgp->name) - vty_out(vty, " %s %s", - (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) - ? "view" : "vrf", bgp->name); - vty_out(vty, "\n"); - - /* BGP fast-external-failover. */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) - vty_out(vty, " no bgp fast-external-failover\n"); - - /* BGP router ID. */ - if (bgp->router_id_static.s_addr != 0) - vty_out(vty, " bgp router-id %s\n", - inet_ntoa(bgp->router_id_static)); - - /* BGP log-neighbor-changes. */ - if (!!bgp_flag_check(bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES) - != DFLT_BGP_LOG_NEIGHBOR_CHANGES) - vty_out(vty, " %sbgp log-neighbor-changes\n", - bgp_flag_check(bgp, - BGP_FLAG_LOG_NEIGHBOR_CHANGES) - ? "" - : "no "); - - /* BGP configuration. */ - if (bgp_flag_check(bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) - vty_out(vty, " bgp always-compare-med\n"); - - /* RFC8212 default eBGP policy. */ - if (bgp->ebgp_requires_policy - == DEFAULT_EBGP_POLICY_ENABLED) - vty_out(vty, " bgp ebgp-requires-policy\n"); - - /* BGP default ipv4-unicast. */ - if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)) - vty_out(vty, " no bgp default ipv4-unicast\n"); - - /* BGP default local-preference. */ - if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF) - vty_out(vty, " bgp default local-preference %u\n", - bgp->default_local_pref); - - /* BGP default show-hostname */ - if (!!bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME) - != DFLT_BGP_SHOW_HOSTNAME) - vty_out(vty, " %sbgp default show-hostname\n", - bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME) - ? "" - : "no "); - - /* BGP default subgroup-pkt-queue-max. */ - if (bgp->default_subgroup_pkt_queue_max - != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX) - vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n", - bgp->default_subgroup_pkt_queue_max); - - /* BGP client-to-client reflection. */ - if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) - vty_out(vty, " no bgp client-to-client reflection\n"); - - /* BGP cluster ID. */ - if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID)) - vty_out(vty, " bgp cluster-id %s\n", - inet_ntoa(bgp->cluster_id)); - - /* Disable ebgp connected nexthop check */ - if (bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - vty_out(vty, - " bgp disable-ebgp-connected-route-check\n"); - - /* Confederation identifier*/ - if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) - vty_out(vty, " bgp confederation identifier %u\n", - bgp->confed_id); - - /* Confederation peer */ - if (bgp->confed_peers_cnt > 0) { - int i; - - vty_out(vty, " bgp confederation peers"); - - for (i = 0; i < bgp->confed_peers_cnt; i++) - vty_out(vty, " %u", bgp->confed_peers[i]); - - vty_out(vty, "\n"); - } - - /* BGP deterministic-med. */ - if (!!bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED) - != DFLT_BGP_DETERMINISTIC_MED) - vty_out(vty, " %sbgp deterministic-med\n", - bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED) - ? "" - : "no "); - - /* BGP update-delay. */ - bgp_config_write_update_delay(vty, bgp); - - if (bgp->v_maxmed_onstartup - != BGP_MAXMED_ONSTARTUP_UNCONFIGURED) { - vty_out(vty, " bgp max-med on-startup %u", - bgp->v_maxmed_onstartup); - if (bgp->maxmed_onstartup_value - != BGP_MAXMED_VALUE_DEFAULT) - vty_out(vty, " %u", - bgp->maxmed_onstartup_value); - vty_out(vty, "\n"); - } - if (bgp->v_maxmed_admin != BGP_MAXMED_ADMIN_UNCONFIGURED) { - vty_out(vty, " bgp max-med administrative"); - if (bgp->maxmed_admin_value != BGP_MAXMED_VALUE_DEFAULT) - vty_out(vty, " %u", bgp->maxmed_admin_value); - vty_out(vty, "\n"); - } - - /* write quanta */ - bgp_config_write_wpkt_quanta(vty, bgp); - /* read quanta */ - bgp_config_write_rpkt_quanta(vty, bgp); - - /* coalesce time */ - bgp_config_write_coalesce_time(vty, bgp); - - /* BGP graceful-restart. */ - if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) - vty_out(vty, - " bgp graceful-restart stalepath-time %u\n", - bgp->stalepath_time); - if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) - vty_out(vty, " bgp graceful-restart restart-time %u\n", - bgp->restart_time); - if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART)) - vty_out(vty, " bgp graceful-restart\n"); - - /* BGP graceful-shutdown */ - if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) - vty_out(vty, " bgp graceful-shutdown\n"); - - /* BGP graceful-restart Preserve State F bit. */ - if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD)) - vty_out(vty, - " bgp graceful-restart preserve-fw-state\n"); - - /* BGP bestpath method. */ - if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_IGNORE)) - vty_out(vty, " bgp bestpath as-path ignore\n"); - if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_CONFED)) - vty_out(vty, " bgp bestpath as-path confed\n"); - - if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { - if (bgp_flag_check(bgp, - BGP_FLAG_MULTIPATH_RELAX_AS_SET)) { - vty_out(vty, - " bgp bestpath as-path multipath-relax as-set\n"); - } else { - vty_out(vty, - " bgp bestpath as-path multipath-relax\n"); - } - } - - if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) { - vty_out(vty, - " bgp route-reflector allow-outbound-policy\n"); - } - if (bgp_flag_check(bgp, BGP_FLAG_COMPARE_ROUTER_ID)) - vty_out(vty, " bgp bestpath compare-routerid\n"); - if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED) - || bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST)) { - vty_out(vty, " bgp bestpath med"); - if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED)) - vty_out(vty, " confed"); - if (bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST)) - vty_out(vty, " missing-as-worst"); - vty_out(vty, "\n"); - } - - /* BGP network import check. */ - if (!!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK) - != DFLT_BGP_IMPORT_CHECK) - vty_out(vty, " %sbgp network import-check\n", - bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK) - ? "" - : "no "); - - /* BGP timers configuration. */ - if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE - && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME) - vty_out(vty, " timers bgp %u %u\n", - bgp->default_keepalive, bgp->default_holdtime); - - /* peer-group */ - for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) { - bgp_config_write_peer_global(vty, bgp, group->conf); - } - - /* Normal neighbor configuration. */ - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) - bgp_config_write_peer_global(vty, bgp, peer); - } - - /* listen range and limit for dynamic BGP neighbors */ - bgp_config_write_listen(vty, bgp); - - /* - * BGP default autoshutdown neighbors - * - * This must be placed after any peer and peer-group - * configuration, to avoid setting all peers to shutdown after - * a daemon restart, which is undesired behavior. (see #2286) - */ - if (bgp->autoshutdown) - vty_out(vty, " bgp default shutdown\n"); - - /* IPv4 unicast configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST); - - /* IPv4 multicast configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MULTICAST); - - /* IPv4 labeled-unicast configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP, SAFI_LABELED_UNICAST); - - /* IPv4 VPN configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP, SAFI_MPLS_VPN); - - /* ENCAPv4 configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP); - - /* FLOWSPEC v4 configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP, SAFI_FLOWSPEC); - - /* IPv6 unicast configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_UNICAST); - - /* IPv6 multicast configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MULTICAST); - - /* IPv6 labeled-unicast configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP6, - SAFI_LABELED_UNICAST); - - /* IPv6 VPN configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_MPLS_VPN); - - /* ENCAPv6 configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP); - - /* FLOWSPEC v6 configuration. */ - bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_FLOWSPEC); - - /* EVPN configuration. */ - bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); - - hook_call(bgp_inst_config_write, bgp, vty); - -#if ENABLE_BGP_VNC - bgp_rfapi_cfg_write(vty, bgp); -#endif - - vty_out(vty, "!\n"); - } - return 0; -} - void bgp_master_init(struct thread_master *master, const int buffer_size) { qobj_init(); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 317f200b85..7d81579009 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -457,6 +457,7 @@ struct bgp { /* BGP default timer. */ uint32_t default_holdtime; uint32_t default_keepalive; + uint32_t default_connect_retry; /* BGP graceful restart */ uint32_t restart_time; @@ -504,6 +505,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 +1211,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]; @@ -1421,13 +1430,17 @@ struct bgp_nlri { #define BGP_EVENTS_MAX 15 /* BGP timers default value. */ -/* note: the DFLT_ ones depend on compile-time "defaults" selection */ #define BGP_INIT_START_TIMER 1 -#define BGP_DEFAULT_HOLDTIME DFLT_BGP_HOLDTIME -#define BGP_DEFAULT_KEEPALIVE DFLT_BGP_KEEPALIVE +/* The following 3 are RFC defaults that are overridden in bgp_vty.c with + * version-/profile-specific values. The values here do not matter, they only + * exist to provide a clear layering separation between core and CLI. + */ +#define BGP_DEFAULT_HOLDTIME 180 +#define BGP_DEFAULT_KEEPALIVE 60 +#define BGP_DEFAULT_CONNECT_RETRY 120 + #define BGP_DEFAULT_EBGP_ROUTEADV 0 #define BGP_DEFAULT_IBGP_ROUTEADV 0 -#define BGP_DEFAULT_CONNECT_RETRY DFLT_BGP_TIMERS_CONNECT /* BGP default local preference. */ #define BGP_DEFAULT_LOCAL_PREF 100 @@ -1472,6 +1485,7 @@ enum bgp_clear_type { /* BGP error codes. */ #define BGP_SUCCESS 0 +#define BGP_CREATED 1 #define BGP_ERR_INVALID_VALUE -1 #define BGP_ERR_INVALID_FLAG -2 #define BGP_ERR_INVALID_AS -3 @@ -1618,7 +1632,8 @@ extern int bgp_confederation_peers_check(struct bgp *, as_t); extern int bgp_confederation_peers_add(struct bgp *, as_t); extern int bgp_confederation_peers_remove(struct bgp *, as_t); -extern int bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime); +extern int bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime, + uint32_t connect_retry); extern int bgp_timers_unset(struct bgp *); extern int bgp_default_local_preference_set(struct bgp *, uint32_t); @@ -1638,9 +1653,11 @@ extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *, int, afi_t, safi_t); extern int peer_group_remote_as(struct bgp *, const char *, as_t *, int); extern int peer_delete(struct peer *peer); +extern int peer_notify_unconfig(struct peer *peer); extern int peer_group_delete(struct peer_group *); extern int peer_group_remote_as_delete(struct peer_group *); extern int peer_group_listen_range_add(struct peer_group *, struct prefix *); +extern int peer_group_notify_unconfig(struct peer_group *group); extern int peer_activate(struct peer *, afi_t, safi_t); extern int peer_deactivate(struct peer *, afi_t, safi_t); 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/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index b97c8c3030..352f5e8328 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -78,7 +78,7 @@ static void encap_attr_export_ce(struct attr *new, struct attr *orig, * Make "new" a ghost attr copy of "orig" */ memset(new, 0, sizeof(struct attr)); - bgp_attr_dup(new, orig); + *new = *orig; /* * Set nexthop @@ -616,7 +616,7 @@ encap_attr_export(struct attr *new, struct attr *orig, * Make "new" a ghost attr copy of "orig" */ memset(new, 0, sizeof(struct attr)); - bgp_attr_dup(new, orig); + *new = *orig; /* * Set nexthop diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index 6e8969ad18..ba6ef14257 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -356,7 +356,8 @@ static int process_unicast_route(struct bgp *bgp, /* in */ * all of the possible returns above. */ memset(&hattr, 0, sizeof(struct attr)); - bgp_attr_dup(&hattr, attr); /* hattr becomes a ghost attr */ + /* hattr becomes a ghost attr */ + hattr = *attr; if (rmap) { struct bgp_path_info info; @@ -798,7 +799,8 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp, * all of the possible returns above. */ memset(&hattr, 0, sizeof(struct attr)); - bgp_attr_dup(&hattr, attr); /* hattr becomes a ghost attr */ + /* hattr becomes a ghost attr */ + hattr = *attr; if (rmap) { struct bgp_path_info info; @@ -1000,7 +1002,8 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix, * all of the possible returns above. */ memset(&hattr, 0, sizeof(struct attr)); - bgp_attr_dup(&hattr, attr); /* hattr becomes a ghost attr */ + /* hattr becomes a ghost attr */ + hattr = *attr; if (rmap) { struct bgp_path_info path; @@ -1779,7 +1782,7 @@ static void vnc_import_bgp_exterior_add_route_it( /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); - bgp_attr_dup(&new_attr, bpi_interior->attr); + new_attr = *bpi_interior->attr; if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { new_attr.local_pref = @@ -2104,7 +2107,7 @@ void vnc_import_bgp_exterior_add_route_interior( /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); - bgp_attr_dup(&new_attr, bpi_interior->attr); + new_attr = *bpi_interior->attr; if (bpi_exterior && (bpi_exterior->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) { @@ -2240,7 +2243,7 @@ void vnc_import_bgp_exterior_add_route_interior( /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); - bgp_attr_dup(&new_attr, bpi_interior->attr); + new_attr = *bpi_interior->attr; if (bpi_exterior && (bpi_exterior->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) { @@ -2360,7 +2363,7 @@ void vnc_import_bgp_exterior_add_route_interior( /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); - bgp_attr_dup(&new_attr, bpi_interior->attr); + new_attr = *bpi_interior->attr; if (bpi_exterior && (bpi_exterior->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) { @@ -2550,7 +2553,7 @@ void vnc_import_bgp_exterior_del_route_interior( /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); - bgp_attr_dup(&new_attr, bpi->attr); + new_attr = *bpi->attr; if (bpi_exterior && (bpi_exterior->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) { diff --git a/configure.ac b/configure.ac index 6147ebf0d8..124312b1e8 100755 --- a/configure.ac +++ b/configure.ac @@ -643,6 +643,7 @@ fi if test "${enable_datacenter}" = "yes" ; then AC_DEFINE([HAVE_DATACENTER], [1], [Compile extensions for a DataCenter]) + AC_MSG_WARN([The --enable-datacenter compile time option is deprecated. Please modify the init script to pass -F datacenter to the daemons instead.]) DFLT_NAME="datacenter" else DFLT_NAME="traditional" diff --git a/defaults.h b/defaults.h deleted file mode 100644 index fd38aaed70..0000000000 --- a/defaults.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * FRR switchable defaults. - * Copyright (C) 2017 David Lamparter for NetDEF, Inc. - * - * This file is part of FRRouting (FRR). - * - * 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 _FRR_DEFAULTS_H -#define _FRR_DEFAULTS_H - -#include "config.h" - -#ifdef HAVE_DATACENTER - -#define DFLT_BGP_IMPORT_CHECK 1 -#define DFLT_BGP_TIMERS_CONNECT 10 -#define DFLT_BGP_HOLDTIME 9 -#define DFLT_BGP_KEEPALIVE 3 -#define DFLT_BGP_LOG_NEIGHBOR_CHANGES 1 -#define DFLT_BGP_SHOW_HOSTNAME 1 -#define DFLT_BGP_DETERMINISTIC_MED 1 - -#define DFLT_OSPF_LOG_ADJACENCY_CHANGES 1 -#define DFLT_OSPF6_LOG_ADJACENCY_CHANGES 1 - -#else /* !HAVE_DATACENTER */ - -#define DFLT_BGP_IMPORT_CHECK 0 -#define DFLT_BGP_TIMERS_CONNECT 120 -#define DFLT_BGP_HOLDTIME 180 -#define DFLT_BGP_KEEPALIVE 60 -#define DFLT_BGP_LOG_NEIGHBOR_CHANGES 0 -#define DFLT_BGP_SHOW_HOSTNAME 0 -#define DFLT_BGP_DETERMINISTIC_MED 0 - -#define DFLT_OSPF_LOG_ADJACENCY_CHANGES 0 -#define DFLT_OSPF6_LOG_ADJACENCY_CHANGES 0 - -#endif /* !HAVE_DATACENTER */ - -#endif /* _FRR_DEFAULTS_H */ diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 6eef7532b3..40378f0219 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -293,6 +293,11 @@ Code submitted to FRR must be signed off. We have the same requirements for using the signed-off-by process as the Linux kernel. In short, you must include a ``Signed-off-by`` tag in every patch. +An easy way to do this is to use ``git commit -s`` where ``-s`` will automatically +append a signed-off line to the end of your commit message. Also, if you commit +and forgot to add the line you can use ``git commit --amend -s`` to add the +signed-off line to the last commit. + ``Signed-off-by`` is a developer's certification that they have the right to submit the patch for inclusion into the project. It is an agreement to the :ref:`Developer's Certificate of Origin <developers-certificate-of-origin>`. diff --git a/doc/user/basic.rst b/doc/user/basic.rst index f946c37a73..edcfce45ad 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -286,6 +286,9 @@ Below is a sample configuration file for the zebra daemon. ! ! Zebra configuration file ! + frr version 6.0 + frr defaults traditional + ! hostname Router password zebra enable password zebra @@ -307,6 +310,137 @@ If a comment character is not the first character of the word, it's a normal character. So in the above example ``!`` will not be regarded as a comment and the password is set to ``zebra!password``. + +Configuration versioning, profiles and upgrade behavior +------------------------------------------------------- + +All |PACKAGE_NAME| daemons share a mechanism to specify a configuration profile +and version for loading and saving configuration. Specific configuration +settings take different default values depending on the selected profile and +version. + +While the profile can be selected by user configuration and will remain over +upgrades, |PACKAGE_NAME| will always write configurations using its current +version. This means that, after upgrading, a ``write file`` may write out a +slightly different configuration than what was read in. + +Since the previous configuration is loaded with its version's defaults, but +the new configuration is written with the new defaults, any default that +changed between versions will result in an appropriate configuration entry +being written out. **FRRouting configuration is sticky, staying consistent +over upgrades.** Changed defaults will only affect new configuration. + +Note that the loaded version persists into interactive configuration +sessions. Commands executed in an interactive configuration session are +no different from configuration loaded at startup. This means that when, +say, you configure a new BGP peer, the defaults used for configuration +are the ones selected by the last ``frr version`` command. + +.. warning:: + + Saving the configuration does not bump the daemons forward to use the new + version for their defaults, but restarting them will, since they will then + apply the new ``frr version`` command that was written out. Manually + execute the ``frr version`` command in ``show running-config`` to avoid + this intermediate state. + +This is visible in ``show running-config``: + +.. code-block:: frr + + Current configuration: + ! + ! loaded from 6.0 + frr version 6.1-dev + frr defaults traditional + ! + +If you save and then restart with this configuration, the old defaults will +no longer apply. Similarly, you could execute ``frr version 6.1-dev``, causing +the new defaults to apply and the ``loaded from 6.0`` comment to disappear. + + +Profiles +^^^^^^^^ + +|PACKAGE_NAME| provides configuration profiles to adapt its default settings +to various usage scenarios. Currently, the following profiles are +implemented: + +* ``traditional`` - reflects defaults adhering mostly to IETF standards or + common practices in wide-area internet routing. +* ``datacenter`` - reflects a single administrative domain with intradomain + links using aggressive timers. + +Your distribution/installation may pre-set a profile through the ``-F`` command +line option on all daemons. All daemons must be configured for the same +profile. The value specified on the command line is only a pre-set and any +``frr defaults`` statement in the configuration will take precedence. + +.. note:: + + The profile must be the same across all daemons. Mismatches may result + in undefined behavior. + +You can freely switch between profiles without causing any interruption or +configuration changes. All settings remain at their previous values, and +``show running-configuration`` output will have new output listing the previous +default values as explicit configuration. New configuration, e.g. adding a +BGP peer, will use the new defaults. To apply the new defaults for existing +configuration, the previously-invisible old defaults that are now shown must +be removed from the configuration. + + +Upgrade practices for interactive configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you configure |PACKAGE_NAME| interactively and use the configuration +writing functionality to make changes persistent, the following +recommendations apply in regards to upgrades: + +1. Skipping major versions should generally work but is still inadvisable. + To avoid unneeded issue, upgrade one major version at a time and write + out the configuration after each update. + +2. After installing a new |PACKAGE_NAME| version, check the configuration + for differences against your old configuration. If any defaults changed + that affect your setup, lines may appear or disappear. If a new line + appears, it was previously the default (or not supported) and is now + neccessary to retain previous behavior. If a line disappears, it + previously wasn't the default, but now is, so it is no longer necessary. + +3. Check the log files for deprecation warnings by using ``grep -i deprecat``. + +4. After completing each upgrade, save the configuration and either restart + |PACKAGE_NAME| or execute ``frr version <CURRENT>`` to ensure defaults of + the new version are fully applied. + + +Upgrade practices for autogenerated configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When using |PACKAGE_NAME| with generated configurations (e.g. Ansible, +Puppet, etc.), upgrade considerations differ somewhat: + +1. Always write out a ``frr version`` statement in the configurations you + generate. This ensures that defaults are applied consistently. + +2. Try to not run more distinct versions of |PACKAGE_NAME| than necessary. + Each version may need to be checked individually. If running a mix of + older and newer installations, use the oldest version for the + ``frr version`` statement. + +3. When rolling out upgrades, generate a configuration as usual with the old + version identifier and load it. Check for any differences or deprecation + warnings. If there are differences in the configuration, propagate these + back to the configuration generator to minimize relying on actual default + values. + +4. After the last installation of an old version is removed, change the + configuration generation to a newer ``frr version`` as appropriate. Perform + the same checks as when rolling out upgrades. + + .. _terminal-mode-commands: Terminal Mode Commands diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 525a31d486..b3fc7f15a6 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -94,6 +94,10 @@ BFDd Commands Show status for a specific BFD peer. +.. index:: show bfd [vrf NAME] peers brief [json] +.. clicmd:: show bfd [vrf NAME] peers brief [json] + + Show all configured BFD peers information and current status in brief. .. _bfd-peer-config: @@ -340,11 +344,14 @@ You can inspect the current BFD peer status with the following commands: Uptime: 1 minute(s), 51 second(s) Diagnostics: ok Remote diagnostics: ok + Peer Type: dynamic Local timers: + Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms Echo transmission interval: disabled Remote timers: + Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms Echo transmission interval: 50ms @@ -357,11 +364,14 @@ You can inspect the current BFD peer status with the following commands: Uptime: 1 minute(s), 53 second(s) Diagnostics: ok Remote diagnostics: ok + Peer Type: configured Local timers: + Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms Echo transmission interval: disabled Remote timers: + Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms Echo transmission interval: 50ms @@ -376,17 +386,31 @@ You can inspect the current BFD peer status with the following commands: Uptime: 3 minute(s), 4 second(s) Diagnostics: ok Remote diagnostics: ok + Peer Type: dynamic Local timers: + Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms Echo transmission interval: disabled Remote timers: + Detect-multiplier: 3 Receive interval: 300ms Transmission interval: 300ms Echo transmission interval: 50ms frr# show bfd peer 192.168.0.1 json - {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-interval":50,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-interval":50} + {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-interval":50,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"} + + +You can inspect the current BFD peer status in brief with the following commands: + +:: + + frr# show bfd peers brief + Session count: 1 + SessionId LocalAddress PeerAddress Status + ========= ============ =========== ====== + 1 192.168.0.1 192.168.0.2 up You can also inspect peer session counters with the following commands: @@ -425,3 +449,30 @@ You can also inspect peer session counters with the following commands: frr# show bfd peer 192.168.0.1 counters json {"multihop":false,"peer":"192.168.0.1","control-packet-input":348,"control-packet-output":685,"echo-packet-input":6815,"echo-packet-output":6816,"session-up":1,"session-down":0,"zebra-notifications":4} + +You can also clear packet counters per session with the following commands, only the packet counters will be reset: + +:: + + frr# clear bfd peers counters + + frr# show bfd peers counters + BFD Peers: + peer 192.168.2.1 interface r2-eth2 + Control packet input: 0 packets + Control packet output: 0 packets + Echo packet input: 0 packets + Echo packet output: 0 packets + Session up events: 1 + Session down events: 0 + Zebra notifications: 2 + + peer 192.168.0.1 + Control packet input: 0 packets + Control packet output: 0 packets + Echo packet input: 0 packets + Echo packet output: 0 packets + Session up events: 1 + Session down events: 0 + Zebra notifications: 4 + diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 4b3113cf3b..97ce036f52 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/nhrpd.rst b/doc/user/nhrpd.rst index 33cdbd9591..ec6bc56e76 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -124,9 +124,9 @@ nhrpd connects to strongSwan using VICI protocol based on UNIX socket (hardcoded now as /var/run/charon.vici). strongSwan currently needs few patches applied. Please check out the -`http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras-release,release <http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras-release,release>`_ +https://git.alpinelinux.org/user/tteras/strongswan/log/?h=tteras-release and -`http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras,working tree <http://git.alpinelinux.org/cgit/user/tteras/strongswan/log/?h=tteras,working tree>`_ +https://git.alpinelinux.org/user/tteras/strongswan/log/?h=tteras git repositories for the patches. .. _nhrp-events: diff --git a/doc/user/overview.rst b/doc/user/overview.rst index 24d9ece93b..03d7299bf7 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -64,6 +64,21 @@ The ultimate goal of the FRR project is making a production-grade, high quality, featureful and free IP routing software suite. +How to get FRR +============== + +The official FRR website is located at |PACKAGE_URL| and contains further +information, as well as links to additional resources. + +Several distributions provide packages for FRR. Check your distribution's +repositories to find out if a suitable version is available. + +Up-to-date Debian packages are available at https://deb.frrouting.org/. + +For instructions on installing from source, refer to the +`developer documentation <http://docs.frrouting.org/projects/dev-guide/en/latest/>`_. + + System Architecture =================== @@ -242,13 +257,15 @@ The indicators have the following semantics: * :mark:`N` - daemon/feature not supported by operating system -Known Kernel Issues: -==================== +Known Kernel Issues +------------------- + +- Linux < 4.11 -- Linux - v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 route deletion when you - have ecmp routes installed into the kernel. This especially becomes apparent if the route is being - transformed from one ecmp path to another. + v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 + route deletion when you have ECMP routes installed into the kernel. This + especially becomes apparent if the route is being transformed from one ECMP + path to another. .. _supported-rfcs: @@ -348,15 +365,6 @@ FRR implements the following RFCs: - :rfc:`2741` :t:`Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.` -How to get FRR -============== - -The official FRR website is located at |PACKAGE_URL| and contains further -information, as well as links to additional resources. - -Several distributions provide packages for FRR. Check your distribution's -repositories to find out if a suitable version is available. - Mailing Lists ============= diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index fab4343f50..d3c7ee09e6 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -39,7 +39,7 @@ listing of ECMP nexthops used to forward packets for when a pbr-map is matched. sub-mode where you can specify individual nexthops. To exit this mode type exit or end as per normal conventions for leaving a sub-mode. -.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME] +.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME] [label LABELS] Create a v4 or v6 nexthop. All normal rules for creating nexthops that you are used to are allowed here. The syntax was intentionally kept the same as @@ -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_interface.c b/eigrpd/eigrp_interface.c index 6294c0dd0f..ece0b4b0c4 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -99,6 +99,9 @@ struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, ei->params.auth_type = EIGRP_AUTH_TYPE_NONE; ei->params.auth_keychain = NULL; + ei->curr_bandwidth = ifp->bandwidth; + ei->curr_mtu = ifp->mtu; + return ei; } @@ -139,45 +142,40 @@ static int eigrp_ifp_create(struct interface *ifp) static int eigrp_ifp_up(struct interface *ifp) { - /* Interface is already up. */ - if (if_is_operative(ifp)) { - /* Temporarily keep ifp values. */ - struct interface if_tmp; - memcpy(&if_tmp, ifp, sizeof(struct interface)); + struct eigrp_interface *ei = ifp->info; - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: Interface[%s] state update.", - ifp->name); + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug("Zebra: Interface[%s] state change to up.", + ifp->name); - if (if_tmp.bandwidth != ifp->bandwidth) { - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: Interface[%s] bandwidth change %d -> %d.", - ifp->name, if_tmp.bandwidth, - ifp->bandwidth); + if (!ei) + return 0; - // eigrp_if_recalculate_output_cost (ifp); - } + if (ei->curr_bandwidth != ifp->bandwidth) { + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: Interface[%s] bandwidth change %d -> %d.", + ifp->name, ei->curr_bandwidth, + ifp->bandwidth); - if (if_tmp.mtu != ifp->mtu) { - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: Interface[%s] MTU change %u -> %u.", - ifp->name, if_tmp.mtu, ifp->mtu); + ei->curr_bandwidth = ifp->bandwidth; + // eigrp_if_recalculate_output_cost (ifp); + } - /* Must reset the interface (simulate down/up) when MTU - * changes. */ - eigrp_if_reset(ifp); - } + if (ei->curr_mtu != ifp->mtu) { + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug( + "Zebra: Interface[%s] MTU change %u -> %u.", + ifp->name, ei->curr_mtu, ifp->mtu); + + ei->curr_mtu = ifp->mtu; + /* Must reset the interface (simulate down/up) when MTU + * changes. */ + eigrp_if_reset(ifp); return 0; } - if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: Interface[%s] state change to up.", - ifp->name); - - if (ifp->info) - eigrp_if_up(ifp->info); + eigrp_if_up(ifp->info); return 0; } 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/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index e50858f071..82bddaaae3 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -176,6 +176,8 @@ struct eigrp_interface { /* To which multicast groups do we currently belong? */ + uint32_t curr_bandwidth; + uint32_t curr_mtu; uint8_t multicast_memberships; 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..364441f79d 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -29,7 +29,6 @@ #include "command.h" #include "vty.h" #include "memory.h" -#include "memory_vty.h" #include "stream.h" #include "if.h" #include "privs.h" @@ -162,7 +161,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/isisd/isis_zebra.c b/isisd/isis_zebra.c index b4c699ccbb..630264768f 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -184,7 +184,7 @@ void isis_zebra_route_add_route(struct prefix *prefix, break; api_nh = &api.nexthops[count]; if (fabricd) - api_nh->onlink = true; + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); api_nh->vrf_id = VRF_DEFAULT; switch (nexthop->family) { diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 5e1b422a41..a656626356 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -723,6 +723,14 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, /* Prefix Length */ map->fec.prefix.prefixlen = buf[off]; off += sizeof(uint8_t); + if ((map->fec.prefix.af == AF_IPV4 + && map->fec.prefix.prefixlen > IPV4_MAX_PREFIXLEN) + || (map->fec.prefix.af == AF_IPV6 + && map->fec.prefix.prefixlen > IPV6_MAX_PREFIXLEN)) { + session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, + msg->type); + return (-1); + } if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type); 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..d2145d9f5a 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 = @@ -1575,18 +1575,6 @@ DEFUN (show_version, return CMD_SUCCESS; } -/* "Set" version ... ignore version tags */ -DEFUN (frr_version_defaults, - frr_version_defaults_cmd, - "frr <version|defaults> LINE...", - "FRRouting global parameters\n" - "version configuration was written by\n" - "set of configuration defaults used\n" - "version string\n") -{ - return CMD_SUCCESS; -} - /* Help display function for all node. */ DEFUN (config_help, config_help_cmd, @@ -1660,7 +1648,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)) @@ -1721,8 +1709,10 @@ static int vty_write_config(struct vty *vty) vty_out(vty, "!\n"); } + if (strcmp(frr_defaults_version(), FRR_VER_SHORT)) + vty_out(vty, "! loaded from %s\n", frr_defaults_version()); vty_out(vty, "frr version %s\n", FRR_VER_SHORT); - vty_out(vty, "frr defaults %s\n", DFLT_NAME); + vty_out(vty, "frr defaults %s\n", frr_defaults_profile()); vty_out(vty, "!\n"); for (i = 0; i < vector_active(cmdvec); i++) @@ -2941,7 +2931,6 @@ void cmd_init(int terminal) install_element(CONFIG_NODE, &no_hostname_cmd); install_element(CONFIG_NODE, &domainname_cmd); install_element(CONFIG_NODE, &no_domainname_cmd); - install_element(CONFIG_NODE, &frr_version_defaults_cmd); if (terminal > 0) { install_element(CONFIG_NODE, &debug_memstats_cmd); diff --git a/lib/command.h b/lib/command.h index 73c15469e7..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, \ @@ -414,18 +414,18 @@ struct cmd_node { /* Daemons lists */ #define DAEMONS_STR \ - "For the zebra daemon\nFor the rip daemon\nFor the ripng daemon\nFor the ospf daemon\nFor the ospfv6 daemon\nFor the bgp daemon\nFor the isis daemon\nFor the pbr daemon\nFor the fabricd daemon\nFor the pim daemon\nFor the static daemon\nFor the sharpd daemon\nFor the vrrpd daemon\n" + "For the zebra daemon\nFor the rip daemon\nFor the ripng daemon\nFor the ospf daemon\nFor the ospfv6 daemon\nFor the bgp daemon\nFor the isis daemon\nFor the pbr daemon\nFor the fabricd daemon\nFor the pim daemon\nFor the static daemon\nFor the sharpd daemon\nFor the vrrpd daemon\nFor the ldpd daemon\n" #define DAEMONS_LIST \ - "<zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd|pimd|staticd|sharpd|vrrpd>" + "<zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd|pimd|staticd|sharpd|vrrpd|ldpd>" /* 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/defaults.c b/lib/defaults.c new file mode 100644 index 0000000000..71ccc73cc6 --- /dev/null +++ b/lib/defaults.c @@ -0,0 +1,229 @@ +/* + * FRR switchable defaults. + * Copyright (c) 2017-2019 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. + */ + +#include <zebra.h> + +#include "defaults.h" +#include "version.h" + +static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME; +static struct frr_default *dflt_first = NULL, **dflt_next = &dflt_first; + +/* these are global for all FRR daemons. they have to be, since we write an + * integrated config with the same value for all daemons. + */ +const char *frr_defaults_profiles[] = { + "traditional", + "datacenter", + NULL, +}; + +static int version_value(int ch) +{ + /* non-ASCII shouldn't happen */ + if (ch < 0 || ch >= 128) + return 2; + + /* ~foo sorts older than nothing */ + if (ch == '~') + return 0; + if (ch == '\0') + return 1; + if (isalpha(ch)) + return 0x100 + tolower(ch); + + /* punctuation and digits (and everything else) */ + return 0x200 + ch; +} + +int frr_version_cmp(const char *aa, const char *bb) +{ + const char *apos = aa, *bpos = bb; + + /* || is correct, we won't scan past the end of a string since that + * doesn't compare equal to anything else */ + while (apos[0] || bpos[0]) { + if (isdigit((unsigned char)apos[0]) && + isdigit((unsigned char)bpos[0])) { + unsigned long av, bv; + char *aend = NULL, *bend = NULL; + + av = strtoul(apos, &aend, 10); + bv = strtoul(bpos, &bend, 10); + if (av < bv) + return -1; + if (av > bv) + return 1; + + apos = aend; + bpos = bend; + continue; + } + + int a = version_value(*apos++); + int b = version_value(*bpos++); + + if (a < b) + return -1; + if (a > b) + return 1; + } + return 0; +} + +static void frr_default_apply_one(struct frr_default *dflt, bool check); + +void frr_default_add(struct frr_default *dflt) +{ + dflt->next = NULL; + *dflt_next = dflt; + dflt_next = &dflt->next; + + frr_default_apply_one(dflt, true); +} + +static bool frr_match_version(const char *name, const char *vspec, + const char *version, bool check) +{ + int cmp; + static struct spec { + const char *str; + bool dir, eq; + } *s, specs[] = { + {"<=", -1, 1}, + {">=", 1, 1}, + {"==", 0, 1}, + {"<", -1, 0}, + {">", 1, 0}, + {"=", 0, 1}, + {NULL, 0, 0}, + }; + + if (!vspec) + /* NULL = all versions */ + return true; + + for (s = specs; s->str; s++) + if (!strncmp(s->str, vspec, strlen(s->str))) + break; + if (!s->str) { + if (check) + fprintf(stderr, "invalid version specifier for %s: %s", + name, vspec); + /* invalid version spec, never matches */ + return false; + } + + vspec += strlen(s->str); + while (isspace((unsigned char)*vspec)) + vspec++; + + cmp = frr_version_cmp(version, vspec); + if (cmp == s->dir || (s->eq && cmp == 0)) + return true; + + return false; +} + +static void frr_default_apply_one(struct frr_default *dflt, bool check) +{ + struct frr_default_entry *entry = dflt->entries; + struct frr_default_entry *dfltentry = NULL, *saveentry = NULL; + + for (; entry->match_version || entry->match_profile; entry++) { + if (entry->match_profile + && strcmp(entry->match_profile, df_profile)) + continue; + + if (!dfltentry && frr_match_version(dflt->name, + entry->match_version, df_version, check)) + dfltentry = entry; + if (!saveentry && frr_match_version(dflt->name, + entry->match_version, FRR_VER_SHORT, check)) + saveentry = entry; + + if (dfltentry && saveentry && !check) + break; + } + /* found default or arrived at last entry that has NULL,NULL spec */ + + if (!dfltentry) + dfltentry = entry; + if (!saveentry) + saveentry = entry; + + if (dflt->dflt_bool) + *dflt->dflt_bool = dfltentry->val_bool; + if (dflt->dflt_str) + *dflt->dflt_str = dfltentry->val_str; + if (dflt->dflt_long) + *dflt->dflt_long = dfltentry->val_long; + if (dflt->dflt_ulong) + *dflt->dflt_ulong = dfltentry->val_ulong; + if (dflt->dflt_float) + *dflt->dflt_float = dfltentry->val_float; + if (dflt->save_bool) + *dflt->save_bool = saveentry->val_bool; + if (dflt->save_str) + *dflt->save_str = saveentry->val_str; + if (dflt->save_long) + *dflt->save_long = saveentry->val_long; + if (dflt->save_ulong) + *dflt->save_ulong = saveentry->val_ulong; + if (dflt->save_float) + *dflt->save_float = saveentry->val_float; +} + +void frr_defaults_apply(void) +{ + struct frr_default *dflt; + + for (dflt = dflt_first; dflt; dflt = dflt->next) + frr_default_apply_one(dflt, false); +} + +bool frr_defaults_profile_valid(const char *profile) +{ + const char **p; + + for (p = frr_defaults_profiles; *p; p++) + if (!strcmp(profile, *p)) + return true; + return false; +} + +const char *frr_defaults_version(void) +{ + return df_version; +} + +const char *frr_defaults_profile(void) +{ + return df_profile; +} + +void frr_defaults_version_set(const char *version) +{ + strlcpy(df_version, version, sizeof(df_version)); + frr_defaults_apply(); +} + +void frr_defaults_profile_set(const char *profile) +{ + strlcpy(df_profile, profile, sizeof(df_profile)); + frr_defaults_apply(); +} diff --git a/lib/defaults.h b/lib/defaults.h new file mode 100644 index 0000000000..7cdd18120e --- /dev/null +++ b/lib/defaults.h @@ -0,0 +1,138 @@ +/* + * FRR switchable defaults. + * Copyright (C) 2017-2019 David Lamparter for NetDEF, Inc. + * + * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. + */ + +#ifndef _FRR_DEFAULTS_H +#define _FRR_DEFAULTS_H + +#include <stdbool.h> + +#include "compiler.h" + +/* frr_default wraps information about a default that has different + * values depending on FRR version or default-set + * + * frr_default_entry describes one match rule and the resulting value; + * entries are evaluated in order and the first matching is used. + * + * If both match_version and match_profile are specified, they must both + * match. A NULL value matches everything. + */ +struct frr_default_entry { + /* syntax: "(<|<=|==|>=|>) [whitespace] version", e.g. + * ">= 6.1-dev" "<6.0" + */ + const char *match_version; + /* exact profile string to compare against */ + const char *match_profile; + + /* value to use */ + bool val_bool; + const char *val_str; + long val_long; + unsigned long val_ulong; + float val_float; +}; + +/* one struct frr_default exists for each malleable default value */ +struct frr_default { + struct frr_default *next; + + /* for UI/debug use */ + const char *name; + + /* the following two sets of variables differ because the written + * config always targets the *current* FRR version + * + * e.g. if you load a config that has "frr version 5.0" on 6.0 + * *dflt_long => set to the default value in 5.0 + * *save_long => set to the default value in 6.0 + * config save will write "frr version 6.0" with 6.0 defaults + */ + + /* variable holding the default value for reading/use */ + bool *dflt_bool; + const char **dflt_str; + long *dflt_long; + unsigned long *dflt_ulong; + float *dflt_float; + + /* variable to use when comparing for config save */ + bool *save_bool; + const char **save_str; + long *save_long; + unsigned long *save_ulong; + float *save_float; + + struct frr_default_entry entries[]; +}; + +#define _FRR_CFG_DEFAULT(type, typname, varname, ...) \ + static type DFLT_##varname; \ + static type SAVE_##varname; \ + static struct frr_default _dflt_##varname = { \ + .name = #varname, \ + .dflt_##typname = &DFLT_##varname, \ + .save_##typname = &SAVE_##varname, \ + .entries = { __VA_ARGS__ }, \ + }; \ + static void _dfltinit_##varname(void) \ + __attribute__((_CONSTRUCTOR(1000))); \ + static void _dfltinit_##varname(void) \ + { \ + frr_default_add(&_dflt_##varname); \ + } + +/* use: + * FRR_CFG_DEFAULT_LONG(SHARP_BLUNTNESS, + * { .val_long = 2, .match_version = ">= 10.0" }, + * { .val_long = 1, .match_profile = "datacenter" }, + * { .val_long = 0 }, + * ) + * + * This will create DFLT_SHARP_BLUNTNESS and SAVE_SHARP_BLUNTNESS variables. + * + * Note: preprocessor defines cannot be used as variable names because they + * will be expanded and blow up with a compile error. Use an enum or add an + * extra _ at the beginning (e.g. _SHARP_BLUNTNESS => DFLT__SHARP_BLUNTNESS) + */ +#define FRR_CFG_DEFAULT_BOOL(varname, ...) \ + _FRR_CFG_DEFAULT(bool, bool, varname, ## __VA_ARGS__) +#define FRR_CFG_DEFAULT_LONG(varname, ...) \ + _FRR_CFG_DEFAULT(long, long, varname, ## __VA_ARGS__) +#define FRR_CFG_DEFAULT_ULONG(varname, ...) \ + _FRR_CFG_DEFAULT(unsigned long, ulong, varname, ## __VA_ARGS__) +#define FRR_CFG_DEFAULT_FLOAT(varname, ...) \ + _FRR_CFG_DEFAULT(float, float, varname, ## __VA_ARGS__) +#define FRR_CFG_DEFAULT_STR(varname, ...) \ + _FRR_CFG_DEFAULT(const char *, str, varname, ## __VA_ARGS__) + + +/* daemons don't need to call any of these, libfrr handles that */ +extern void frr_default_add(struct frr_default *dflt); +extern void frr_defaults_version_set(const char *version); +extern void frr_defaults_profile_set(const char *profile); +extern const char *frr_defaults_version(void); +extern const char *frr_defaults_profile(void); +extern void frr_defaults_apply(void); + +extern const char *frr_defaults_profiles[]; +extern bool frr_defaults_profile_valid(const char *profile); + +/* like strcmp(), but with version ordering */ +extern int frr_version_cmp(const char *aa, const char *bb); + +#endif /* _FRR_DEFAULTS_H */ diff --git a/lib/filter.c b/lib/filter.c index 8c210bd7ad..ed3ffe9c67 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -2147,7 +2147,7 @@ DEFUN (no_access_list_any, "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") { - int idx_word = 1; + int idx_word = 2; int idx = 0; char *seq = NULL; char *permit_deny = NULL; @@ -2352,7 +2352,7 @@ DEFUN (no_ipv6_access_list_exact, { int idx = 0; int exact = 0; - int idx_word = 2; + int idx_word = 3; char *seq = NULL; char *permit_deny = NULL; char *prefix = NULL; @@ -2394,7 +2394,7 @@ DEFUN (no_ipv6_access_list_any, "Specify packets to forward\n" "Any prefixi to match\n") { - int idx_word = 2; + int idx_word = 3; int idx = 0; char *seq = NULL; char *permit_deny = NULL; 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); /* diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index c6fd3c04ad..a23874a517 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -28,7 +28,6 @@ #endif #include "command.h" -#include "memory_vty.h" #include "graph.h" #include "linklist.h" #include "command_match.h" diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index 6d28a667b3..4bd8f5138a 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -28,7 +28,7 @@ #endif #include "command.h" -#include "memory_vty.h" +#include "lib_vty.h" static void vty_do_exit(int isexit) { @@ -57,7 +57,7 @@ int main(int argc, char **argv) host.domainname = strdup("testdomainname"); vty_init(master, true); - memory_init(); + lib_cmd_init(); yang_init(); nb_init(master, NULL, 0); @@ -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/memory_vty.c b/lib/lib_vty.c index 1adc0d7b74..787da08e28 100644 --- a/lib/memory_vty.c +++ b/lib/lib_vty.c @@ -1,5 +1,5 @@ /* - * Memory and dynamic module VTY routine + * Assorted library VTY commands * * Copyright (C) 1998 Kunihiro Ishiguro * Copyright (C) 2016-2017 David Lamparter for NetDEF, Inc. @@ -35,7 +35,8 @@ #include "log.h" #include "memory.h" #include "module.h" -#include "memory_vty.h" +#include "defaults.h" +#include "lib_vty.h" /* Looking up memory status from vty interface. */ #include "vector.h" @@ -120,11 +121,11 @@ static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt) } -DEFUN (show_memory, - show_memory_cmd, - "show memory", - "Show running system information\n" - "Memory statistics\n") +DEFUN_NOSH (show_memory, + show_memory_cmd, + "show memory", + "Show running system information\n" + "Memory statistics\n") { #ifdef HAVE_MALLINFO show_memory_mallinfo(vty); @@ -134,11 +135,11 @@ DEFUN (show_memory, return CMD_SUCCESS; } -DEFUN (show_modules, - show_modules_cmd, - "show modules", - "Show running system information\n" - "Loaded modules\n") +DEFUN_NOSH (show_modules, + show_modules_cmd, + "show modules", + "Show running system information\n" + "Loaded modules\n") { struct frrmod_runtime *plug = frrmod_list; @@ -177,8 +178,60 @@ DEFUN (show_modules, return CMD_SUCCESS; } -void memory_init(void) +DEFUN (frr_defaults, + frr_defaults_cmd, + "frr defaults PROFILE...", + "FRRouting global parameters\n" + "set of configuration defaults used\n" + "profile string\n") { + char *profile = argv_concat(argv, argc, 2); + int rv = CMD_SUCCESS; + + if (!frr_defaults_profile_valid(profile)) { + vty_out(vty, "%% WARNING: profile %s is not known in this version\n", + profile); + rv = CMD_WARNING; + } + frr_defaults_profile_set(profile); + XFREE(MTYPE_TMP, profile); + return rv; +} + +DEFUN (frr_version, + frr_version_cmd, + "frr version VERSION...", + "FRRouting global parameters\n" + "version configuration was written by\n" + "version string\n") +{ + char *version = argv_concat(argv, argc, 2); + + frr_defaults_version_set(version); + XFREE(MTYPE_TMP, version); + return CMD_SUCCESS; +} + +static void defaults_autocomplete(vector comps, struct cmd_token *token) +{ + const char **p; + + for (p = frr_defaults_profiles; *p; p++) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, *p)); +} + +static const struct cmd_variable_handler default_var_handlers[] = { + {.tokenname = "PROFILE", .completions = defaults_autocomplete}, + {.completions = NULL}, +}; + +void lib_cmd_init(void) +{ + cmd_variable_handler_register(default_var_handlers); + + install_element(CONFIG_NODE, &frr_defaults_cmd); + install_element(CONFIG_NODE, &frr_version_cmd); + install_element(VIEW_NODE, &show_memory_cmd); install_element(VIEW_NODE, &show_modules_cmd); } diff --git a/lib/memory_vty.h b/lib/lib_vty.h index 941255be1d..48e409ec52 100644 --- a/lib/memory_vty.h +++ b/lib/lib_vty.h @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _ZEBRA_MEMORY_VTY_H -#define _ZEBRA_MEMORY_VTY_H +#ifndef _ZEBRA_LIB_VTY_H +#define _ZEBRA_LIB_VTY_H #include "memory.h" @@ -27,7 +27,7 @@ extern "C" { #endif -extern void memory_init(void); +extern void lib_cmd_init(void); /* Human friendly string for given byte count */ #define MTYPE_MEMSTR_LEN 20 @@ -37,4 +37,4 @@ extern const char *mtype_memstr(char *, size_t, unsigned long); } #endif -#endif /* _ZEBRA_MEMORY_VTY_H */ +#endif /* _ZEBRA_LIB_VTY_H */ diff --git a/lib/libfrr.c b/lib/libfrr.c index 8ef32eaa8a..4fb43edff2 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -30,7 +30,7 @@ #include "vty.h" #include "command.h" #include "version.h" -#include "memory_vty.h" +#include "lib_vty.h" #include "log_vty.h" #include "zclient.h" #include "log_int.h" @@ -43,6 +43,7 @@ #include "debug.h" #include "frrcu.h" #include "frr_pthread.h" +#include "defaults.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) DEFINE_KOOH(frr_early_fini, (), ()) @@ -104,6 +105,7 @@ static const struct option lo_always[] = { {"version", no_argument, NULL, 'v'}, {"daemon", no_argument, NULL, 'd'}, {"module", no_argument, NULL, 'M'}, + {"profile", required_argument, NULL, 'F'}, {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, {"log", required_argument, NULL, OPTION_LOG}, @@ -112,11 +114,12 @@ static const struct option lo_always[] = { {"command-log-always", no_argument, NULL, OPTION_LOGGING}, {NULL}}; static const struct optspec os_always = { - "hvdM:", + "hvdM:F:", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" " -M, --module Load specified module\n" + " -F, --profile Use specified configuration profile\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --log Set Logging to stdout, syslog, or file:<name>\n" @@ -175,7 +178,6 @@ static const struct optspec os_user = {"u:g:", " -g, --group Group to run as\n", lo_user}; - bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, const char *path) { @@ -390,6 +392,32 @@ static int frr_opt(int opt) *modnext = oc; modnext = &oc->next; break; + case 'F': + if (!frr_defaults_profile_valid(optarg)) { + const char **p; + FILE *ofd = stderr; + + if (!strcmp(optarg, "help")) + ofd = stdout; + else + fprintf(stderr, + "The \"%s\" configuration profile is not valid for this FRR version.\n", + optarg); + + fprintf(ofd, "Available profiles are:\n"); + for (p = frr_defaults_profiles; *p; p++) + fprintf(ofd, "%s%s\n", + strcmp(*p, DFLT_NAME) ? " " : " * ", + *p); + + if (ofd == stdout) + exit(0); + fprintf(ofd, "\n"); + errors++; + break; + } + frr_defaults_profile_set(optarg); + break; case 'i': if (di->flags & FRR_NO_CFG_PID_DRY) return 1; @@ -608,6 +636,7 @@ struct thread_master *frr_init(void) dir = di->module_path ? di->module_path : frr_moduledir; srandom(time(NULL)); + frr_defaults_apply(); if (di->instance) { snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]", @@ -679,7 +708,7 @@ struct thread_master *frr_init(void) cmd_init(1); vty_init(master, di->log_always); - memory_init(); + lib_cmd_init(); log_filter_cmd_init(); frr_pthread_init(); @@ -1077,7 +1106,6 @@ void frr_fini(void) hook_call(frr_fini); - /* memory_init -> nothing needed */ vty_terminate(); cmd_terminate(); nb_terminate(); 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 73c2de0cd8..f314fea697 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -33,6 +33,7 @@ #include "mpls.h" #include "jhash.h" #include "printfrr.h" +#include "vrf.h" DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop") DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label") @@ -200,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", @@ -281,6 +282,93 @@ bool nexthop_same_no_labels(const struct nexthop *nh1, return true; } +/* + * Allocate a new nexthop object and initialize it from various args. + */ +struct nexthop *nexthop_from_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->type = NEXTHOP_TYPE_IFINDEX; + nexthop->ifindex = ifindex; + nexthop->vrf_id = vrf_id; + + return nexthop; +} + +struct nexthop *nexthop_from_ipv4(const struct in_addr *ipv4, + const struct in_addr *src, + vrf_id_t vrf_id) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->type = NEXTHOP_TYPE_IPV4; + nexthop->vrf_id = vrf_id; + nexthop->gate.ipv4 = *ipv4; + if (src) + nexthop->src.ipv4 = *src; + + return nexthop; +} + +struct nexthop *nexthop_from_ipv4_ifindex(const struct in_addr *ipv4, + const struct in_addr *src, + ifindex_t ifindex, vrf_id_t vrf_id) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + nexthop->vrf_id = vrf_id; + nexthop->gate.ipv4 = *ipv4; + if (src) + nexthop->src.ipv4 = *src; + nexthop->ifindex = ifindex; + + return nexthop; +} + +struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6, + vrf_id_t vrf_id) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->vrf_id = vrf_id; + nexthop->type = NEXTHOP_TYPE_IPV6; + nexthop->gate.ipv6 = *ipv6; + + return nexthop; +} + +struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6, + ifindex_t ifindex, vrf_id_t vrf_id) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->vrf_id = vrf_id; + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + nexthop->gate.ipv6 = *ipv6; + nexthop->ifindex = ifindex; + + return nexthop; +} + +struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type) +{ + struct nexthop *nexthop; + + nexthop = nexthop_new(); + nexthop->vrf_id = VRF_DEFAULT; + nexthop->type = NEXTHOP_TYPE_BLACKHOLE; + nexthop->bh_type = bh_type; + + return nexthop; +} + /* Update nexthop with label information. */ void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type, uint8_t num_labels, mpls_label_t *label) diff --git a/lib/nexthop.h b/lib/nexthop.h index fe029f1867..72a4acedb2 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -122,6 +122,22 @@ void nexthop_add_labels(struct nexthop *, enum lsp_types_t, uint8_t, void nexthop_del_labels(struct nexthop *); /* + * Allocate a new nexthop object and initialize it from various args. + */ +struct nexthop *nexthop_from_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); +struct nexthop *nexthop_from_ipv4(const struct in_addr *ipv4, + const struct in_addr *src, + vrf_id_t vrf_id); +struct nexthop *nexthop_from_ipv4_ifindex(const struct in_addr *ipv4, + const struct in_addr *src, + ifindex_t ifindex, vrf_id_t vrf_id); +struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6, + vrf_id_t vrf_id); +struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6, + ifindex_t ifindex, vrf_id_t vrf_id); +struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type); + +/* * Hash a nexthop. Suitable for use with hash tables. * * This function uses the following values when computing the hash: diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 9552f89568..b810d13a5a 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -34,6 +34,16 @@ DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group") +/* + * Internal struct used to hold nhg config strings + */ +struct nexthop_hold { + char *nhvrf_name; + union sockunion *addr; + char *intf; + char *labels; +}; + struct nexthop_group_hooks { void (*new)(const char *name); void (*add_nexthop)(const struct nexthop_group_cmd *nhg, @@ -233,8 +243,8 @@ void _nexthop_add(struct nexthop **target, struct nexthop *nexthop) nexthop->prev = last; } -void _nexthop_group_add_sorted(struct nexthop_group *nhg, - struct nexthop *nexthop) +void nexthop_group_add_sorted(struct nexthop_group *nhg, + struct nexthop *nexthop) { struct nexthop *position, *prev, *tail; @@ -425,7 +435,11 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2) if (ret) return ret; - return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name); + ret = nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name); + if (ret) + return ret; + + return nhgc_cmp_helper(nh1->labels, nh2->labels); } static void nhgl_delete(struct nexthop_hold *nh) @@ -437,6 +451,8 @@ static void nhgl_delete(struct nexthop_hold *nh) if (nh->addr) sockunion_free(nh->addr); + XFREE(MTYPE_TMP, nh->labels); + XFREE(MTYPE_TMP, nh); } @@ -510,7 +526,8 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME", static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, const char *nhvrf_name, const union sockunion *addr, - const char *intf) + const char *intf, + const char *labels) { struct nexthop_hold *nh; @@ -522,6 +539,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, nh->intf = XSTRDUP(MTYPE_TMP, intf); if (addr) nh->addr = sockunion_dup(addr); + if (labels) + nh->labels = XSTRDUP(MTYPE_TMP, labels); listnode_add_sort(nhgc->nhg_list, nh); } @@ -529,7 +548,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, const char *nhvrf_name, const union sockunion *addr, - const char *intf) + const char *intf, + const char *labels) { struct nexthop_hold *nh; struct listnode *node; @@ -537,7 +557,8 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) { if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 && nhgc_addr_cmp_helper(addr, nh->addr) == 0 && - nhgc_cmp_helper(intf, nh->intf) == 0) + nhgc_cmp_helper(intf, nh->intf) == 0 && + nhgc_cmp_helper(labels, nh->labels) == 0) break; } @@ -551,10 +572,19 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc, nhgl_delete(nh); } +/* + * Parse the config strings we support for a single nexthop. This gets used + * in a couple of different ways, and we distinguish between transient + * failures - such as a still-unprocessed interface - and fatal errors + * from label-string parsing. + */ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, const union sockunion *addr, - const char *intf, const char *name) + const char *intf, const char *name, + const char *labels, + int *lbl_ret) { + int ret = 0; struct vrf *vrf; memset(nhop, 0, sizeof(*nhop)); @@ -592,16 +622,49 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, } else nhop->type = NEXTHOP_TYPE_IFINDEX; + if (labels) { + uint8_t num = 0; + mpls_label_t larray[MPLS_MAX_LABELS]; + + ret = mpls_str2label(labels, &num, larray); + + /* Return label parse result */ + if (lbl_ret) + *lbl_ret = ret; + + if (ret < 0) + return false; + else if (num > 0) + nexthop_add_labels(nhop, ZEBRA_LSP_NONE, + num, larray); + } + return true; } +/* + * Wrapper to parse the strings in a 'nexthop_hold' + */ +static bool nexthop_group_parse_nhh(struct nexthop *nhop, + const struct nexthop_hold *nhh) +{ + return (nexthop_group_parse_nexthop(nhop, nhh->addr, + nhh->intf, + nhh->nhvrf_name, + nhh->labels, + NULL)); +} + DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, "[no] nexthop\ <\ <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ |INTERFACE$intf\ >\ - [nexthop-vrf NAME$vrf_name]", + [{ \ + nexthop-vrf NAME$vrf_name \ + |label WORD \ + }]", NO_STR "Specify one of the nexthops in this ECMP group\n" "v4 Address\n" @@ -609,14 +672,18 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, "Interface to use\n" "Interface to use\n" "If the nexthop is in a different vrf tell us\n" - "The nexthop-vrf Name\n") + "The nexthop-vrf Name\n" + "Specify label(s) for this nexthop\n" + "One or more labels in the range (16-1048575) separated by '/'\n") { VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); struct nexthop nhop; struct nexthop *nh; + int lbl_ret = 0; bool legal; - legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name); + legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, + label, &lbl_ret); if (nhop.type == NEXTHOP_TYPE_IPV6 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { @@ -625,10 +692,31 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, return CMD_WARNING_CONFIG_FAILED; } + /* Handle label-string errors */ + if (!legal && lbl_ret < 0) { + switch (lbl_ret) { + case -1: + vty_out(vty, "%% Malformed label(s)\n"); + break; + case -2: + vty_out(vty, + "%% Cannot use reserved label(s) (%d-%d)\n", + MPLS_LABEL_RESERVED_MIN, + MPLS_LABEL_RESERVED_MAX); + break; + case -3: + vty_out(vty, + "%% Too many labels. Enter %d or fewer\n", + MPLS_MAX_LABELS); + break; + } + return CMD_WARNING_CONFIG_FAILED; + } + nh = nexthop_exists(&nhgc->nhg, &nhop); if (no) { - nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf); + nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label); if (nh) { _nexthop_del(&nhgc->nhg, nh); @@ -646,7 +734,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, _nexthop_add(&nhgc->nhg.nexthop, nh); } - nexthop_group_save_nhop(nhgc, vrf_name, addr, intf); + nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label); if (legal && nhg_hooks.add_nexthop) nhg_hooks.add_nexthop(nhgc, nh); @@ -696,6 +784,16 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh) vrf = vrf_lookup_by_id(nh->vrf_id); vty_out(vty, " nexthop-vrf %s", vrf->name); } + + if (nh->nh_label && nh->nh_label->num_labels > 0) { + char buf[200]; + + mpls_label2str(nh->nh_label->num_labels, + nh->nh_label->label, + buf, sizeof(buf), 0); + vty_out(vty, " label %s", buf); + } + vty_out(vty, "\n"); } @@ -715,6 +813,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty, if (nh->nhvrf_name) vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name); + if (nh->labels) + vty_out(vty, " label %s", nh->labels); + vty_out(vty, "\n"); } @@ -751,9 +852,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf) struct nexthop nhop; struct nexthop *nh; - if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, - nhh->intf, - nhh->nhvrf_name)) + if (!nexthop_group_parse_nhh(&nhop, nhh)) continue; nh = nexthop_exists(&nhgc->nhg, &nhop); @@ -787,9 +886,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf) struct nexthop nhop; struct nexthop *nh; - if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, - nhh->intf, - nhh->nhvrf_name)) + if (!nexthop_group_parse_nhh(&nhop, nhh)) continue; nh = nexthop_exists(&nhgc->nhg, &nhop); @@ -824,9 +921,7 @@ void nexthop_group_interface_state_change(struct interface *ifp, for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) { struct nexthop nhop; - if (!nexthop_group_parse_nexthop( - &nhop, nhh->addr, nhh->intf, - nhh->nhvrf_name)) + if (!nexthop_group_parse_nhh(&nhop, nhh)) continue; switch (nhop.type) { diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 391775c69c..c90b21737a 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -50,6 +50,8 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg); uint32_t nexthop_group_hash(const struct nexthop_group *nhg); void nexthop_group_mark_duplicates(struct nexthop_group *nhg); +void nexthop_group_add_sorted(struct nexthop_group *nhg, + struct nexthop *nexthop); /* The following for loop allows to iterate over the nexthop * structure of routes. @@ -70,12 +72,6 @@ void nexthop_group_mark_duplicates(struct nexthop_group *nhg); (nhop) = nexthop_next(nhop) -struct nexthop_hold { - char *nhvrf_name; - union sockunion *addr; - char *intf; -}; - struct nexthop_group_cmd { RB_ENTRY(nexthop_group_cmd) nhgc_entry; diff --git a/lib/nexthop_group_private.h b/lib/nexthop_group_private.h index cdd0df0ab3..4abda624ae 100644 --- a/lib/nexthop_group_private.h +++ b/lib/nexthop_group_private.h @@ -35,8 +35,6 @@ extern "C" { void _nexthop_add(struct nexthop **target, struct nexthop *nexthop); void _nexthop_del(struct nexthop_group *nhg, struct nexthop *nexthop); -void _nexthop_group_add_sorted(struct nexthop_group *nhg, - struct nexthop *nexthop); #ifdef __cplusplus } 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..17dc256281 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -21,6 +21,7 @@ #include "libfrr.h" #include "version.h" +#include "defaults.h" #include "log.h" #include "lib_errors.h" #include "command.h" @@ -432,12 +433,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); @@ -486,7 +487,7 @@ static void nb_cli_show_config_cmds(struct vty *vty, struct nb_config *config, vty_out(vty, "Configuration:\n"); vty_out(vty, "!\n"); vty_out(vty, "frr version %s\n", FRR_VER_SHORT); - vty_out(vty, "frr defaults %s\n", DFLT_NAME); + vty_out(vty, "frr defaults %s\n", frr_defaults_profile()); LY_TREE_FOR (config->dnode, root) nb_cli_show_dnode_cmds(vty, root, with_defaults); diff --git a/lib/plist.c b/lib/plist.c index 64571a05b7..a0976cd6bd 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -1891,6 +1891,8 @@ int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp, if (!plist) return CMD_WARNING_CONFIG_FAILED; + apply_mask(&orfp->p); + if (set) { pentry = prefix_list_entry_make( &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY), 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/stream.c b/lib/stream.c index 2e1a0193a2..dd4d5bd96d 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -812,7 +812,7 @@ int stream_put_ipv4(struct stream *s, uint32_t l) } /* Put long word to the stream. */ -int stream_put_in_addr(struct stream *s, struct in_addr *addr) +int stream_put_in_addr(struct stream *s, const struct in_addr *addr) { STREAM_VERIFY_SANE(s); @@ -828,7 +828,8 @@ int stream_put_in_addr(struct stream *s, struct in_addr *addr) } /* Put in_addr at location in the stream. */ -int stream_put_in_addr_at(struct stream *s, size_t putp, struct in_addr *addr) +int stream_put_in_addr_at(struct stream *s, size_t putp, + const struct in_addr *addr) { STREAM_VERIFY_SANE(s); @@ -842,7 +843,8 @@ int stream_put_in_addr_at(struct stream *s, size_t putp, struct in_addr *addr) } /* Put in6_addr at location in the stream. */ -int stream_put_in6_addr_at(struct stream *s, size_t putp, struct in6_addr *addr) +int stream_put_in6_addr_at(struct stream *s, size_t putp, + const struct in6_addr *addr) { STREAM_VERIFY_SANE(s); @@ -856,7 +858,7 @@ int stream_put_in6_addr_at(struct stream *s, size_t putp, struct in6_addr *addr) } /* Put prefix by nlri type format. */ -int stream_put_prefix_addpath(struct stream *s, struct prefix *p, +int stream_put_prefix_addpath(struct stream *s, const struct prefix *p, int addpath_encode, uint32_t addpath_tx_id) { size_t psize; @@ -890,7 +892,7 @@ int stream_put_prefix_addpath(struct stream *s, struct prefix *p, return psize; } -int stream_put_prefix(struct stream *s, struct prefix *p) +int stream_put_prefix(struct stream *s, const struct prefix *p) { return stream_put_prefix_addpath(s, p, 0, 0); } diff --git a/lib/stream.h b/lib/stream.h index 1144e43ef0..c0d25e0579 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -186,13 +186,16 @@ extern int stream_putl_at(struct stream *, size_t, uint32_t); extern int stream_putq(struct stream *, uint64_t); extern int stream_putq_at(struct stream *, size_t, uint64_t); extern int stream_put_ipv4(struct stream *, uint32_t); -extern int stream_put_in_addr(struct stream *, struct in_addr *); -extern int stream_put_in_addr_at(struct stream *, size_t, struct in_addr *); -extern int stream_put_in6_addr_at(struct stream *, size_t, struct in6_addr *); -extern int stream_put_prefix_addpath(struct stream *, struct prefix *, +extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr); +extern int stream_put_in_addr_at(struct stream *s, size_t putp, + const struct in_addr *addr); +extern int stream_put_in6_addr_at(struct stream *s, size_t putp, + const struct in6_addr *addr); +extern int stream_put_prefix_addpath(struct stream *s, + const struct prefix *p, int addpath_encode, uint32_t addpath_tx_id); -extern int stream_put_prefix(struct stream *, struct prefix *); +extern int stream_put_prefix(struct stream *s, const struct prefix *p); extern int stream_put_labeled_prefix(struct stream *, struct prefix *, mpls_label_t *, int addpath_encode, uint32_t addpath_tx_id); diff --git a/lib/subdir.am b/lib/subdir.am index 23b1950384..cb6fa7a3b8 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -18,6 +18,7 @@ lib_libfrr_la_SOURCES = \ lib/command_parse.y \ lib/csv.c \ lib/debug.c \ + lib/defaults.c \ lib/distribute.c \ lib/ferr.c \ lib/filter.c \ @@ -40,13 +41,13 @@ lib_libfrr_la_SOURCES = \ lib/json.c \ lib/keychain.c \ lib/lib_errors.c \ + lib/lib_vty.c \ lib/libfrr.c \ lib/linklist.c \ lib/log.c \ lib/log_vty.c \ lib/md5.c \ lib/memory.c \ - lib/memory_vty.c \ lib/mlag.c \ lib/module.c \ lib/mpls.c \ @@ -114,6 +115,7 @@ vtysh_scan += \ $(top_srcdir)/lib/if.c \ $(top_srcdir)/lib/if_rmap.c \ $(top_srcdir)/lib/keychain.c \ + $(top_srcdir)/lib/lib_vty.c \ $(top_srcdir)/lib/nexthop_group.c \ $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/routemap.c \ @@ -156,6 +158,7 @@ pkginclude_HEADERS += \ lib/csv.h \ lib/db.h \ lib/debug.h \ + lib/defaults.h \ lib/distribute.h \ lib/ferr.h \ lib/filter.h \ @@ -179,6 +182,7 @@ pkginclude_HEADERS += \ lib/json.h \ lib/keychain.h \ lib/lib_errors.h \ + lib/lib_vty.h \ lib/libfrr.h \ lib/libospf.h \ lib/linklist.h \ @@ -186,7 +190,6 @@ pkginclude_HEADERS += \ lib/log_vty.h \ lib/md5.h \ lib/memory.h \ - lib/memory_vty.h \ lib/module.h \ lib/monotime.h \ lib/mpls.h \ 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..5ce1150b05 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -859,6 +859,76 @@ static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp, &zapi_nexthop_cmp); } +/* + * Encode a single zapi nexthop + */ +int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, + uint32_t api_flags) +{ + int ret = 0; + int nh_flags = api_nh->flags; + + stream_putl(s, api_nh->vrf_id); + stream_putc(s, api_nh->type); + + /* If needed, set 'labelled nexthop' flag */ + if (api_nh->label_num > 0) { + SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_LABEL); + + /* Validate label count */ + if (api_nh->label_num > MPLS_MAX_LABELS) { + ret = -1; + goto done; + } + } + + /* Note that we're only encoding a single octet */ + stream_putc(s, nh_flags); + + switch (api_nh->type) { + case NEXTHOP_TYPE_BLACKHOLE: + stream_putc(s, api_nh->bh_type); + break; + case NEXTHOP_TYPE_IPV4: + stream_put_in_addr(s, &api_nh->gate.ipv4); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + stream_put_in_addr(s, &api_nh->gate.ipv4); + stream_putl(s, api_nh->ifindex); + break; + case NEXTHOP_TYPE_IFINDEX: + stream_putl(s, api_nh->ifindex); + break; + case NEXTHOP_TYPE_IPV6: + stream_write(s, (uint8_t *)&api_nh->gate.ipv6, + 16); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + stream_write(s, (uint8_t *)&api_nh->gate.ipv6, + 16); + stream_putl(s, api_nh->ifindex); + break; + } + + /* We only encode labels if we have >0 - we use + * the per-nexthop flag above to signal that the count + * is present in the payload. + */ + if (api_nh->label_num > 0) { + stream_putc(s, api_nh->label_num); + stream_put(s, &api_nh->labels[0], + api_nh->label_num * sizeof(mpls_label_t)); + } + + /* Router MAC for EVPN routes. */ + if (CHECK_FLAG(api_flags, ZEBRA_FLAG_EVPN_ROUTE)) + stream_put(s, &(api_nh->rmac), + sizeof(struct ethaddr)); + +done: + return ret; +} + int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) { struct zapi_nexthop *api_nh; @@ -921,59 +991,22 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) for (i = 0; i < api->nexthop_num; i++) { api_nh = &api->nexthops[i]; - stream_putl(s, api_nh->vrf_id); - stream_putc(s, api_nh->type); - stream_putc(s, api_nh->onlink); - switch (api_nh->type) { - case NEXTHOP_TYPE_BLACKHOLE: - stream_putc(s, api_nh->bh_type); - break; - case NEXTHOP_TYPE_IPV4: - stream_put_in_addr(s, &api_nh->gate.ipv4); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: - stream_put_in_addr(s, &api_nh->gate.ipv4); - stream_putl(s, api_nh->ifindex); - break; - case NEXTHOP_TYPE_IFINDEX: - stream_putl(s, api_nh->ifindex); - break; - case NEXTHOP_TYPE_IPV6: - stream_write(s, (uint8_t *)&api_nh->gate.ipv6, - 16); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - stream_write(s, (uint8_t *)&api_nh->gate.ipv6, - 16); - stream_putl(s, api_nh->ifindex); - break; - } - /* MPLS labels for BGP-LU or Segment Routing */ - if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)) { - if (api_nh->label_num > MPLS_MAX_LABELS) { - char buf[PREFIX2STR_BUFFER]; - prefix2str(&api->prefix, buf, - sizeof(buf)); - flog_err(EC_LIB_ZAPI_ENCODE, - "%s: prefix %s: can't encode " - "%u labels (maximum is %u)", - __func__, buf, - api_nh->label_num, - MPLS_MAX_LABELS); - return -1; - } - - stream_putc(s, api_nh->label_num); - stream_put(s, &api_nh->labels[0], - api_nh->label_num - * sizeof(mpls_label_t)); + if (api_nh->label_num > MPLS_MAX_LABELS) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&api->prefix, buf, sizeof(buf)); + + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: prefix %s: can't encode %u labels (maximum is %u)", + __func__, buf, + api_nh->label_num, + MPLS_MAX_LABELS); + return -1; } - /* Router MAC for EVPN routes. */ - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) - stream_put(s, &(api_nh->rmac), - sizeof(struct ethaddr)); + if (zapi_nexthop_encode(s, api_nh, api->flags) != 0) + return -1; } } @@ -995,6 +1028,73 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) return 0; } +/* + * Decode a single zapi nexthop object + */ +static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, + uint32_t api_flags) +{ + int ret = -1; + + STREAM_GETL(s, api_nh->vrf_id); + STREAM_GETC(s, api_nh->type); + + /* Note that we're only using a single octet of flags */ + STREAM_GETC(s, api_nh->flags); + + switch (api_nh->type) { + case NEXTHOP_TYPE_BLACKHOLE: + STREAM_GETC(s, api_nh->bh_type); + break; + case NEXTHOP_TYPE_IPV4: + STREAM_GET(&api_nh->gate.ipv4.s_addr, s, + IPV4_MAX_BYTELEN); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + STREAM_GET(&api_nh->gate.ipv4.s_addr, s, + IPV4_MAX_BYTELEN); + STREAM_GETL(s, api_nh->ifindex); + break; + case NEXTHOP_TYPE_IFINDEX: + STREAM_GETL(s, api_nh->ifindex); + break; + case NEXTHOP_TYPE_IPV6: + STREAM_GET(&api_nh->gate.ipv6, s, 16); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + STREAM_GET(&api_nh->gate.ipv6, s, 16); + STREAM_GETL(s, api_nh->ifindex); + break; + } + + /* MPLS labels for BGP-LU or Segment Routing */ + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)) { + STREAM_GETC(s, api_nh->label_num); + if (api_nh->label_num > MPLS_MAX_LABELS) { + flog_err( + EC_LIB_ZAPI_ENCODE, + "%s: invalid number of MPLS labels (%u)", + __func__, api_nh->label_num); + return -1; + } + + STREAM_GET(&api_nh->labels[0], s, + api_nh->label_num * sizeof(mpls_label_t)); + } + + /* Router MAC for EVPN routes. */ + if (CHECK_FLAG(api_flags, ZEBRA_FLAG_EVPN_ROUTE)) + STREAM_GET(&(api_nh->rmac), s, + sizeof(struct ethaddr)); + + /* Success */ + ret = 0; + +stream_failure: + + return ret; +} + int zapi_route_decode(struct stream *s, struct zapi_route *api) { struct zapi_nexthop *api_nh; @@ -1088,55 +1188,8 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) for (i = 0; i < api->nexthop_num; i++) { api_nh = &api->nexthops[i]; - STREAM_GETL(s, api_nh->vrf_id); - STREAM_GETC(s, api_nh->type); - STREAM_GETC(s, api_nh->onlink); - switch (api_nh->type) { - case NEXTHOP_TYPE_BLACKHOLE: - STREAM_GETC(s, api_nh->bh_type); - break; - case NEXTHOP_TYPE_IPV4: - STREAM_GET(&api_nh->gate.ipv4.s_addr, s, - IPV4_MAX_BYTELEN); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: - STREAM_GET(&api_nh->gate.ipv4.s_addr, s, - IPV4_MAX_BYTELEN); - STREAM_GETL(s, api_nh->ifindex); - break; - case NEXTHOP_TYPE_IFINDEX: - STREAM_GETL(s, api_nh->ifindex); - break; - case NEXTHOP_TYPE_IPV6: - STREAM_GET(&api_nh->gate.ipv6, s, 16); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - STREAM_GET(&api_nh->gate.ipv6, s, 16); - STREAM_GETL(s, api_nh->ifindex); - break; - } - - /* MPLS labels for BGP-LU or Segment Routing */ - if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)) { - STREAM_GETC(s, api_nh->label_num); - - if (api_nh->label_num > MPLS_MAX_LABELS) { - flog_err( - EC_LIB_ZAPI_ENCODE, - "%s: invalid number of MPLS labels (%u)", - __func__, api_nh->label_num); - return -1; - } - - STREAM_GET(&api_nh->labels[0], s, - api_nh->label_num - * sizeof(mpls_label_t)); - } - - /* Router MAC for EVPN routes. */ - if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) - stream_get(&(api_nh->rmac), s, - sizeof(struct ethaddr)); + if (zapi_nexthop_decode(s, api_nh, api->flags) != 0) + return -1; } } @@ -1335,6 +1388,35 @@ struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh) return n; } +/* + * Convert nexthop to zapi nexthop + */ +int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, + const struct nexthop *nh) +{ + int i; + + memset(znh, 0, sizeof(*znh)); + + znh->type = nh->type; + znh->vrf_id = nh->vrf_id; + znh->ifindex = nh->ifindex; + znh->gate = nh->gate; + + if (nh->nh_label && (nh->nh_label->num_labels > 0)) { + for (i = 0; i < nh->nh_label->num_labels; i++) + znh->labels[i] = nh->nh_label->label[i]; + + znh->label_num = i; + SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL); + } + + return 0; +} + +/* + * Decode the nexthop-tracking update message + */ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) { uint32_t i; @@ -1361,38 +1443,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) STREAM_GETC(s, nhr->nexthop_num); for (i = 0; i < nhr->nexthop_num; i++) { - STREAM_GETL(s, nhr->nexthops[i].vrf_id); - STREAM_GETC(s, nhr->nexthops[i].type); - switch (nhr->nexthops[i].type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - STREAM_GET(&nhr->nexthops[i].gate.ipv4.s_addr, s, - IPV4_MAX_BYTELEN); - STREAM_GETL(s, nhr->nexthops[i].ifindex); - break; - case NEXTHOP_TYPE_IFINDEX: - STREAM_GETL(s, nhr->nexthops[i].ifindex); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - STREAM_GET(&nhr->nexthops[i].gate.ipv6, s, - IPV6_MAX_BYTELEN); - STREAM_GETL(s, nhr->nexthops[i].ifindex); - break; - case NEXTHOP_TYPE_BLACKHOLE: - break; - } - STREAM_GETC(s, nhr->nexthops[i].label_num); - if (nhr->nexthops[i].label_num > MPLS_MAX_LABELS) { - flog_err(EC_LIB_ZAPI_ENCODE, - "%s: invalid number of MPLS labels (%u)", - __func__, nhr->nexthops[i].label_num); - return false; - } - if (nhr->nexthops[i].label_num) - STREAM_GET(&nhr->nexthops[i].labels[0], s, - nhr->nexthops[i].label_num - * sizeof(mpls_label_t)); + if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0) != 0) + return -1; } return true; @@ -2721,6 +2773,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 +3118,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..9c5c65ffc5 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. */ @@ -281,7 +289,6 @@ struct zclient { #define ZAPI_MESSAGE_TAG 0x08 #define ZAPI_MESSAGE_MTU 0x10 #define ZAPI_MESSAGE_SRCPFX 0x20 -#define ZAPI_MESSAGE_LABEL 0x40 /* * This should only be used by a DAEMON that needs to communicate * the table being used is not in the VRF. You must pass the @@ -305,7 +312,7 @@ struct zapi_nexthop { enum nexthop_types_t type; vrf_id_t vrf_id; ifindex_t ifindex; - bool onlink; + uint8_t flags; union { union g_addr gate; enum blackhole_type bh_type; @@ -319,6 +326,12 @@ struct zapi_nexthop { }; /* + * ZAPI nexthop flags values + */ +#define ZAPI_NEXTHOP_FLAG_ONLINK 0x01 +#define ZAPI_NEXTHOP_FLAG_LABEL 0x02 + +/* * Some of these data structures do not map easily to * a actual data structure size giving different compilers * and systems. For those data structures we need @@ -477,11 +490,35 @@ enum zapi_iptable_notify_owner { ZAPI_IPTABLE_FAIL_REMOVE, }; +static inline const char * +zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) +{ + const char *ret = "UNKNOWN"; + + switch (note) { + case ZAPI_RULE_FAIL_INSTALL: + ret = "ZAPI_RULE_FAIL_INSTALL"; + break; + case ZAPI_RULE_INSTALLED: + ret = "ZAPI_RULE_INSTALLED"; + break; + case ZAPI_RULE_FAIL_REMOVE: + ret = "ZAPI_RULE_FAIL_REMOVE"; + break; + case ZAPI_RULE_REMOVED: + ret = "ZAPI_RULE_REMOVED"; + break; + } + + return ret; +} + /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #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 }; @@ -657,6 +694,8 @@ extern int zclient_route_send(uint8_t, struct zclient *, struct zapi_route *); extern int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p, bool exact_match, vrf_id_t vrf_id); +int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, + uint32_t api_flags); extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *); extern int zapi_route_decode(struct stream *, struct zapi_route *); bool zapi_route_notify_decode(struct stream *s, struct prefix *p, @@ -681,6 +720,8 @@ bool zapi_iptable_notify_decode(struct stream *s, enum zapi_iptable_notify_owner *note); extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh); +int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, + const struct nexthop *nh); extern bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr); @@ -694,5 +735,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..b58fe776ab 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -21,7 +21,6 @@ #include "version.h" #include "log.h" #include "memory.h" -#include "memory_vty.h" #include "command.h" #include "libfrr.h" @@ -116,7 +115,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..0aaefeb3c2 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -28,7 +28,6 @@ #include "command.h" #include "vty.h" #include "memory.h" -#include "memory_vty.h" #include "if.h" #include "filter.h" #include "prefix.h" @@ -166,7 +165,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/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 95dafff84e..95537eb86e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -51,6 +51,11 @@ DEFINE_QOBJ_TYPE(ospf6) +FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES, + { .val_long = true, .match_profile = "datacenter", }, + { .val_long = false }, +) + /* global ospf6d variable */ struct ospf6 *ospf6; static struct ospf6_master ospf6_master; @@ -179,11 +184,6 @@ static struct ospf6 *ospf6_create(vrf_id_t vrf_id) o->distance_table = route_table_init(); -/* Enable "log-adjacency-changes" */ -#if DFLT_OSPF6_LOG_ADJACENCY_CHANGES - SET_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); -#endif - QOBJ_REG(o, ospf6); return o; @@ -327,6 +327,9 @@ DEFUN_NOSH (router_ospf6, { if (ospf6 == NULL) { ospf6 = ospf6_create(VRF_DEFAULT); + if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES) + SET_FLAG(ospf6->config_flags, + OSPF6_LOG_ADJACENCY_CHANGES); if (ospf6->router_id == 0) ospf6_router_id_update(); } @@ -1079,9 +1082,9 @@ static int config_write_ospf6(struct vty *vty) if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) vty_out(vty, " log-adjacency-changes detail\n"); - else if (!DFLT_OSPF6_LOG_ADJACENCY_CHANGES) + else if (!SAVE_OSPF6_LOG_ADJACENCY_CHANGES) vty_out(vty, " log-adjacency-changes\n"); - } else if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES) { + } else if (SAVE_OSPF6_LOG_ADJACENCY_CHANGES) { vty_out(vty, " no log-adjacency-changes\n"); } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index ba41fca65b..18c0697025 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -29,6 +29,12 @@ struct ospf6_master { uint32_t zebra_router_id; }; +/* ospf6->config_flags */ +enum { + OSPF6_LOG_ADJACENCY_CHANGES = (1 << 0), + OSPF6_LOG_ADJACENCY_DETAIL = (1 << 1), +}; + /* OSPFv3 top level data structure */ struct ospf6 { /* The relevant vrf_id */ @@ -68,10 +74,8 @@ struct ospf6 { uint8_t flag; - /* Configured flags */ + /* Configuration bitmask, refer to enum above */ uint8_t config_flags; -#define OSPF6_LOG_ADJACENCY_CHANGES (1 << 0) -#define OSPF6_LOG_ADJACENCY_DETAIL (1 << 1) /* LSA timer parameters */ unsigned int lsa_minarrival; /* LSA minimum arrival in milliseconds. */ diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index f06e45392e..1ace0977bc 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -246,13 +246,6 @@ void msg_print(struct msg *msg) return; } -#ifdef ORIGINAL_CODING - zlog_debug( - "msg=%p msgtype=%d msglen=%d msgseq=%d streamdata=%p streamsize=%lu\n", - msg, msg->hdr.msgtype, ntohs(msg->hdr.msglen), - ntohl(msg->hdr.msgseq), STREAM_DATA(msg->s), - STREAM_SIZE(msg->s)); -#else /* ORIGINAL_CODING */ /* API message common header part. */ zlog_debug("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%zd)", ospf_api_typename(msg->hdr.msgtype), msg->hdr.msgtype, @@ -260,16 +253,7 @@ void msg_print(struct msg *msg) (unsigned long)ntohl(msg->hdr.msgseq), STREAM_DATA(msg->s), STREAM_SIZE(msg->s)); -/* API message body part. */ -#ifdef ndef - /* Generic Hex/Ascii dump */ - DumpBuf(STREAM_DATA(msg->s), STREAM_SIZE(msg->s)); /* Sorry, deleted! */ -#else /* ndef */ -/* Message-type dependent dump function. */ -#endif /* ndef */ - return; -#endif /* ORIGINAL_CODING */ } void msg_free(struct msg *msg) diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index c99923e7b8..0fc683a5db 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -140,16 +140,10 @@ struct msg_unregister_opaque_type { * Power2[0] is not used. */ -#ifdef ORIGINAL_CODING -static const uint16_t Power2[] = {0x0, 0x1, 0x2, 0x4, 0x8, 0x10, - 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, - 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; -#else static const uint16_t Power2[] = { 0, (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15)}; -#endif /* ORIGINAL_CODING */ struct lsa_filter_type { uint16_t typemask; /* bitmask for selecting LSA types (1..16) */ diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index d6f1fba28b..49730063b9 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -2325,14 +2325,12 @@ void ospf_apiserver_clients_notify_ism_change(struct ospf_interface *oi) void ospf_apiserver_clients_notify_nsm_change(struct ospf_neighbor *nbr) { struct msg *msg; - struct in_addr ifaddr = {.s_addr = 0L}; + struct in_addr ifaddr; struct in_addr nbraddr; 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_asbr.c b/ospfd/ospf_asbr.c index ea919017d3..a60af36564 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -238,20 +238,23 @@ struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf, /* Update ASBR status. */ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status) { - zlog_info("ASBR[Status:%d]: Update", status); + zlog_info("ASBR[%s:Status:%d]: Update", + ospf_get_name(ospf), status); /* ASBR on. */ if (status) { /* Already ASBR. */ if (IS_OSPF_ASBR(ospf)) { - zlog_info("ASBR[Status:%d]: Already ASBR", status); + zlog_info("ASBR[%s:Status:%d]: Already ASBR", + ospf_get_name(ospf), status); return; } SET_FLAG(ospf->flags, OSPF_FLAG_ASBR); } else { /* Already non ASBR. */ if (!IS_OSPF_ASBR(ospf)) { - zlog_info("ASBR[Status:%d]: Already non ASBR", status); + zlog_info("ASBR[%s:Status:%d]: Already non ASBR", + ospf_get_name(ospf), status); return; } UNSET_FLAG(ospf->flags, OSPF_FLAG_ASBR); diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index f74d9733ee..dffcb930e4 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -501,23 +501,6 @@ static void ospf_packet_ls_ack_dump(struct stream *s, uint16_t length) stream_set_getp(s, sp); } -/* Expects header to be in host order */ -void ospf_ip_header_dump(struct ip *iph) -{ - /* IP Header dump. */ - zlog_debug("ip_v %d", iph->ip_v); - zlog_debug("ip_hl %d", iph->ip_hl); - zlog_debug("ip_tos %d", iph->ip_tos); - zlog_debug("ip_len %d", iph->ip_len); - zlog_debug("ip_id %u", (uint32_t)iph->ip_id); - zlog_debug("ip_off %u", (uint32_t)iph->ip_off); - zlog_debug("ip_ttl %d", iph->ip_ttl); - zlog_debug("ip_p %d", iph->ip_p); - zlog_debug("ip_sum 0x%x", (uint32_t)iph->ip_sum); - zlog_debug("ip_src %s", inet_ntoa(iph->ip_src)); - zlog_debug("ip_dst %s", inet_ntoa(iph->ip_dst)); -} - static void ospf_header_dump(struct ospf_header *ospfh) { char buf[9]; diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index 397f666f69..6b2ebb125a 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -108,11 +108,6 @@ (conf_debug_ospf_packet[a] & OSPF_DEBUG_##b) #define IS_CONF_DEBUG_OSPF(a, b) (conf_debug_ospf_##a & OSPF_DEBUG_##b) -#ifdef ORIGINAL_CODING -#else /* ORIGINAL_CODING */ -struct stream; -#endif /* ORIGINAL_CODING */ - #define AREA_NAME(A) ospf_area_name_string ((A)) #define IF_NAME(I) ospf_if_name_string ((I)) @@ -138,7 +133,6 @@ extern const char *ospf_if_name_string(struct ospf_interface *); extern void ospf_nbr_state_message(struct ospf_neighbor *, char *, size_t); extern const char *ospf_timer_dump(struct thread *, char *, size_t); extern const char *ospf_timeval_dump(struct timeval *, char *, size_t); -extern void ospf_ip_header_dump(struct ip *); extern void ospf_packet_dump(struct stream *); extern void ospf_debug_init(void); diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 1d85a04984..c29b464cab 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -157,9 +157,9 @@ static void ospf_process_self_originated_lsa(struct ospf *ospf, if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Type%d:%s]: Process self-originated LSA seq 0x%x", - new->data->type, inet_ntoa(new->data->id), - ntohl(new->data->ls_seqnum)); + "%s:LSA[Type%d:%s]: Process self-originated LSA seq 0x%x", + ospf_get_name(ospf), new->data->type, + inet_ntoa(new->data->id), ntohl(new->data->ls_seqnum)); /* If we're here, we installed a self-originated LSA that we received from a neighbor, i.e. it's more recent. We must see whether we want @@ -276,8 +276,8 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr, if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", - inet_ntoa(nbr->router_id), + "%s:LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", + ospf_get_name(ospf), inet_ntoa(nbr->router_id), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), (void *)current, dump_lsa_key(new)); @@ -295,15 +295,16 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr, == OSPF_INITIAL_SEQUENCE_NUMBER)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Flooding]: Got a self-originated LSA, " - "while local one is initial instance."); + "%s:LSA[Flooding]: Got a self-originated LSA, while local one is initial instance.", + ospf_get_name(ospf)); ; /* Accept this LSA for quick LSDB resynchronization. */ } else if (monotime_since(¤t->tv_recv, NULL) < ospf->min_ls_arrival * 1000LL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Flooding]: LSA is received recently."); + "%s:LSA[Flooding]: LSA is received recently.", + ospf_get_name(ospf)); return -1; } } @@ -327,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; } } @@ -344,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 @@ -376,9 +376,8 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ospf_flood_through_interface(): " - "considering int %s, INBR(%s), LSA[%s] AGE %u", - IF_NAME(oi), inbr ? inet_ntoa(inbr->router_id) : "NULL", + "%s:ospf_flood_through_interface(): considering int %s, INBR(%s), LSA[%s] AGE %u", + ospf_get_name(oi->ospf), IF_NAME(oi), inbr ? inet_ntoa(inbr->router_id) : "NULL", dump_lsa_key(lsa), ntohs(lsa->data->ls_age)); if (!ospf_if_is_enable(oi)) @@ -399,8 +398,9 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, onbr = rn->info; if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ospf_flood_through_interface(): considering nbr %s (%s)", + "ospf_flood_through_interface(): considering nbr %s(%s) (%s)", inet_ntoa(onbr->router_id), + ospf_get_name(oi->ospf), lookup_msg(ospf_nsm_state_msg, onbr->state, NULL)); @@ -454,13 +454,8 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, } } -/* If the new LSA was received from this neighbor, - examine the next neighbor. */ -#ifdef ORIGINAL_CODING - if (inbr) - if (IPV4_ADDR_SAME(&inbr->router_id, &onbr->router_id)) - continue; -#else /* ORIGINAL_CODING */ + /* If the new LSA was received from this neighbor, + examine the next neighbor. */ if (inbr) { /* * Triggered by LSUpd message parser "ospf_ls_upd ()". @@ -486,7 +481,6 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, continue; } } -#endif /* ORIGINAL_CODING */ /* Add the new LSA to the Link state retransmission list for the adjacency. The LSA will be retransmitted @@ -691,43 +685,14 @@ int ospf_flood_through(struct ospf *ospf, struct ospf_neighbor *inbr, { int lsa_ack_flag = 0; -/* Type-7 LSA's for NSSA are flooded throughout the AS here, and - upon return are updated in the LSDB for Type-7's. Later, - re-fresh will re-send them (and also, if ABR, packet code will - translate to Type-5's) + /* Type-7 LSA's for NSSA are flooded throughout the AS here, and + upon return are updated in the LSDB for Type-7's. Later, + re-fresh will re-send them (and also, if ABR, packet code will + translate to Type-5's) - As usual, Type-5 LSA's (if not DISCARDED because we are STUB or - NSSA) are flooded throughout the AS, and are updated in the - global table. */ -#ifdef ORIGINAL_CODING - switch (lsa->data->type) { - case OSPF_ROUTER_LSA: - case OSPF_NETWORK_LSA: - case OSPF_SUMMARY_LSA: - case OSPF_ASBR_SUMMARY_LSA: - case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ - case OSPF_OPAQUE_AREA_LSA: - lsa_ack_flag = - ospf_flood_through_area(inbr->oi->area, inbr, lsa); - break; - case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ - case OSPF_OPAQUE_AS_LSA: - lsa_ack_flag = ospf_flood_through_as(ospf, inbr, lsa); - break; - /* Type-7 Only received within NSSA, then flooded */ - case OSPF_AS_NSSA_LSA: - /* Any P-bit was installed with the Type-7. */ - lsa_ack_flag = - ospf_flood_through_area(inbr->oi->area, inbr, lsa); - - if (IS_DEBUG_OSPF_NSSA) - zlog_debug( - "ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); - break; - default: - break; - } -#else /* ORIGINAL_CODING */ + As usual, Type-5 LSA's (if not DISCARDED because we are STUB or + NSSA) are flooded throughout the AS, and are updated in the + global table. */ /* * At the common sub-sub-function "ospf_flood_through_interface()", * a parameter "inbr" will be used to distinguish the called context @@ -757,7 +722,6 @@ int ospf_flood_through(struct ospf *ospf, struct ospf_neighbor *inbr, lsa_ack_flag = ospf_flood_through_area(lsa->area, inbr, lsa); break; } -#endif /* ORIGINAL_CODING */ return (lsa_ack_flag); } @@ -773,9 +737,10 @@ void ospf_ls_request_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) * the common function "ospf_lsdb_add()" -- endo. */ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RqstL(%lu)++, NBR(%s), LSA[%s]", + zlog_debug("RqstL(%lu)++, NBR(%s(%s)), LSA[%s]", ospf_ls_request_count(nbr), - inet_ntoa(nbr->router_id), dump_lsa_key(lsa)); + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_add(&nbr->ls_req, lsa); } @@ -799,9 +764,10 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) } if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RqstL(%lu)--, NBR(%s), LSA[%s]", + zlog_debug("RqstL(%lu)--, NBR(%s(%s)), LSA[%s]", ospf_ls_request_count(nbr), - inet_ntoa(nbr->router_id), dump_lsa_key(lsa)); + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_delete(&nbr->ls_req, lsa); } @@ -859,6 +825,12 @@ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) if (ospf_lsa_more_recent(old, lsa) < 0) { if (old) { old->retransmit_counter--; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu)--, NBR(%s(%s)), LSA[%s]", + ospf_ls_retransmit_count(nbr), + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), + dump_lsa_key(old)); ospf_lsdb_delete(&nbr->ls_rxmt, old); } lsa->retransmit_counter++; @@ -871,9 +843,10 @@ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) * the common function "ospf_lsdb_add()" -- endo. */ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)++, NBR(%s), LSA[%s]", + zlog_debug("RXmtL(%lu)++, NBR(%s(%s)), LSA[%s]", ospf_ls_retransmit_count(nbr), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_add(&nbr->ls_rxmt, lsa); } @@ -885,9 +858,10 @@ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) if (ospf_ls_retransmit_lookup(nbr, lsa)) { lsa->retransmit_counter--; if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RXmtL(%lu)--, NBR(%s), LSA[%s]", + zlog_debug("RXmtL(%lu)--, NBR(%s(%s)), LSA[%s]", ospf_ls_retransmit_count(nbr), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_delete(&nbr->ls_rxmt, lsa); } diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 5459e3b87c..cfcffcdb3d 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -273,7 +273,7 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u created", __PRETTY_FUNCTION__, ifp->name, - ospf_vrf_id_to_name(ospf->vrf_id), ospf->vrf_id); + ospf_get_name(ospf), ospf->vrf_id); return oi; } @@ -636,9 +636,13 @@ void ospf_if_update_params(struct interface *ifp, struct in_addr addr) int ospf_if_new_hook(struct interface *ifp) { int rc = 0; + struct ospf_if_info *oii; ifp->info = XCALLOC(MTYPE_OSPF_IF_INFO, sizeof(struct ospf_if_info)); + oii = ifp->info; + oii->curr_mtu = ifp->mtu; + IF_OIFS(ifp) = route_table_init(); IF_OIFS_PARAMS(ifp) = route_table_init(); @@ -832,7 +836,7 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf, struct prefix_ipv4 *p; if (IS_DEBUG_OSPF_EVENT) - zlog_debug("ospf_vl_new(): Start"); + zlog_debug("ospf_vl_new()(%s): Start", ospf_get_name(ospf)); if (vlink_count == OSPF_VL_MAX_COUNT) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( @@ -1261,31 +1265,21 @@ static int ospf_ifp_up(struct interface *ifp) { struct ospf_interface *oi; struct route_node *rn; + struct ospf_if_info *oii = ifp->info; - /* Interface is already up. */ - if (if_is_operative(ifp)) { - /* Temporarily keep ifp values. */ - struct interface if_tmp; - memcpy(&if_tmp, ifp, sizeof(struct interface)); + ospf_if_recalculate_output_cost(ifp); + if (oii && oii->curr_mtu != ifp->mtu) { if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) zlog_debug( - "Zebra: Interface[%s] state update speed %u -> %u, bw %d -> %d", - ifp->name, if_tmp.speed, ifp->speed, - if_tmp.bandwidth, ifp->bandwidth); + "Zebra: Interface[%s] MTU change %u -> %u.", + ifp->name, oii->curr_mtu, ifp->mtu); - ospf_if_recalculate_output_cost(ifp); + oii->curr_mtu = ifp->mtu; + /* Must reset the interface (simulate down/up) when MTU + * changes. */ + ospf_if_reset(ifp); - if (if_tmp.mtu != ifp->mtu) { - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug( - "Zebra: Interface[%s] MTU change %u -> %u.", - ifp->name, if_tmp.mtu, ifp->mtu); - - /* Must reset the interface (simulate down/up) when MTU - * changes. */ - ospf_if_reset(ifp); - } return 0; } diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index cde52dbb9e..4b3dbcc5c2 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -117,6 +117,8 @@ struct ospf_if_info { struct route_table *oifs; unsigned int membership_counts[MEMBER_MAX]; /* multicast group refcnts */ + + uint32_t curr_mtu; }; struct ospf_interface; 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 5ab0927e71..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) { @@ -3202,45 +3202,6 @@ int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2) return 0; } -#ifdef ORIGINAL_CODING -void ospf_lsa_flush_self_originated(struct ospf_neighbor *nbr, - struct ospf_lsa *self, struct ospf_lsa *new) -{ - uint32_t seqnum; - - /* Adjust LS Sequence Number. */ - seqnum = ntohl(new->data->ls_seqnum) + 1; - self->data->ls_seqnum = htonl(seqnum); - - /* Recalculate LSA checksum. */ - ospf_lsa_checksum(self->data); - - /* Reflooding LSA. */ - /* RFC2328 Section 13.3 - On non-broadcast networks, separate Link State Update - packets must be sent, as unicasts, to each adjacent neighbor - (i.e., those in state Exchange or greater). The destination - IP addresses for these packets are the neighbors' IP - addresses. */ - if (nbr->oi->type == OSPF_IFTYPE_NBMA) { - struct route_node *rn; - struct ospf_neighbor *onbr; - - for (rn = route_top(nbr->oi->nbrs); rn; rn = route_next(rn)) - if ((onbr = rn->info) != NULL) - if (onbr != nbr->oi->nbr_self - && onbr->status >= NSM_Exchange) - ospf_ls_upd_send_lsa( - onbr, self, - OSPF_SEND_PACKET_DIRECT); - } else - ospf_ls_upd_send_lsa(nbr, self, OSPF_SEND_PACKET_INDIRECT); - - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug("LSA[Type%d:%s]: Flush self-originated LSA", - self->data->type, inet_ntoa(self->data->id)); -} -#else /* ORIGINAL_CODING */ int ospf_lsa_flush_schedule(struct ospf *ospf, struct ospf_lsa *lsa) { if (lsa == NULL || !IS_LSA_SELF(lsa)) @@ -3345,7 +3306,6 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf) return; } -#endif /* ORIGINAL_CODING */ /* If there is self-originated LSA, then return 1, otherwise return 0. */ /* An interface-independent version of ospf_lsa_is_self_originated */ diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index bee7bbb21d..d02ffe0448 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -35,7 +35,6 @@ #include "stream.h" #include "log.h" #include "memory.h" -#include "memory_vty.h" #include "privs.h" #include "sigevent.h" #include "zclient.h" @@ -72,9 +71,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 +124,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 00174b638e..0fc2cd60f9 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -65,8 +65,9 @@ static int ospf_inactivity_timer(struct thread *thread) nbr->t_inactivity = NULL; if (IS_DEBUG_OSPF(nsm, NSM_TIMERS)) - zlog_debug("NSM[%s:%s]: Timer (Inactivity timer expire)", - IF_NAME(nbr->oi), inet_ntoa(nbr->router_id)); + zlog_debug("NSM[%s:%s:%s]: Timer (Inactivity timer expire)", + IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf)); OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); @@ -81,8 +82,9 @@ static int ospf_db_desc_timer(struct thread *thread) nbr->t_db_desc = NULL; if (IS_DEBUG_OSPF(nsm, NSM_TIMERS)) - zlog_debug("NSM[%s:%s]: Timer (DD Retransmit timer expire)", - IF_NAME(nbr->oi), inet_ntoa(nbr->src)); + zlog_debug("NSM[%s:%s:%s]: Timer (DD Retransmit timer expire)", + IF_NAME(nbr->oi), inet_ntoa(nbr->src), + ospf_get_name(nbr->oi->ospf)); /* resent last send DD packet. */ assert(nbr->last_send); @@ -222,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: @@ -387,16 +389,17 @@ static int nsm_kill_nbr(struct ospf_neighbor *nbr) if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) zlog_debug( - "NSM[%s:%s]: Down (PollIntervalTimer scheduled)", + "NSM[%s:%s:%s]: Down (PollIntervalTimer scheduled)", IF_NAME(nbr->oi), - inet_ntoa(nbr->address.u.prefix4)); + inet_ntoa(nbr->address.u.prefix4), + ospf_get_name(nbr->oi->ospf)); } return 0; } /* Neighbor State Machine */ -struct { +const struct { int (*func)(struct ospf_neighbor *); int next_state; } NSM[OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = { @@ -572,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?", @@ -585,8 +588,9 @@ static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state, { /* Logging change of status. */ if (IS_DEBUG_OSPF(nsm, NSM_STATUS)) - zlog_debug("NSM[%s:%s]: State change %s -> %s (%s)", + zlog_debug("NSM[%s:%s:%s]: State change %s -> %s (%s)", IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), lookup_msg(ospf_nsm_state_msg, next_state, NULL), ospf_nsm_event_str[event]); @@ -595,8 +599,9 @@ static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state, if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) || (next_state == NSM_Full) || (next_state < nbr->state))) - zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)", - inet_ntoa(nbr->router_id), IF_NAME(nbr->oi), + zlog_notice("AdjChg: Nbr %s(%s) on %s: %s -> %s (%s)", + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), lookup_msg(ospf_nsm_state_msg, next_state, NULL), ospf_nsm_event_str[event]); @@ -677,9 +682,10 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) zlog_info( - "%s:(%s, %s -> %s): " + "%s:[%s:%s], %s -> %s): " "scheduling new router-LSA origination", __PRETTY_FUNCTION__, inet_ntoa(nbr->router_id), + ospf_get_name(oi->ospf), lookup_msg(ospf_nsm_state_msg, old_state, NULL), lookup_msg(ospf_nsm_state_msg, state, NULL)); @@ -753,8 +759,9 @@ int ospf_nsm_event(struct thread *thread) event = THREAD_VAL(thread); if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) - zlog_debug("NSM[%s:%s]: %s (%s)", IF_NAME(nbr->oi), + zlog_debug("NSM[%s:%s:%s]: %s (%s)", IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), ospf_nsm_event_str[event]); @@ -777,9 +784,10 @@ int ospf_nsm_event(struct thread *thread) */ flog_err( EC_OSPF_FSM_INVALID_STATE, - "NSM[%s:%s]: %s (%s): " + "NSM[%s:%s:%s]: %s (%s): " "Warning: action tried to change next_state to %s", IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), ospf_nsm_event_str[event], diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 453135cb4d..80ffc3f361 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -614,13 +614,6 @@ static void ospf_write_frags(int fd, struct ospf_packet *op, struct ip *iph, "ospf_write_frags: sent id %d, off %d, len %d to %s\n", iph->ip_id, iph->ip_off, iph->ip_len, inet_ntoa(iph->ip_dst)); - if (IS_DEBUG_OSPF_PACKET(type - 1, DETAIL)) { - zlog_debug( - "-----------------IP Header Dump----------------------"); - ospf_ip_header_dump(iph); - zlog_debug( - "-----------------------------------------------------"); - } } iph->ip_off += offset; @@ -824,7 +817,6 @@ static int ospf_write(struct thread *thread) if (IS_DEBUG_OSPF_PACKET(type - 1, DETAIL)) { zlog_debug( "-----------------------------------------------------"); - ospf_ip_header_dump(&iph); stream_set_getp(op->s, 0); ospf_packet_dump(op->s); } @@ -1505,10 +1497,6 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, /* Check DD Options. */ if (dd->options != nbr->options) { -#ifdef ORIGINAL_CODING - /* Save the new options for debugging */ - nbr->options = dd->options; -#endif /* ORIGINAL_CODING */ flog_warn(EC_OSPF_PACKET, "Packet[DD]: Neighbor %s options mismatch.", inet_ntoa(nbr->router_id)); @@ -2322,10 +2310,12 @@ static struct stream *ospf_recv_packet(struct ospf *ospf, int fd, msgh.msg_control = (caddr_t)buff; msgh.msg_controllen = sizeof(buff); - ret = stream_recvmsg(ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE + 1); + ret = stream_recvmsg(ibuf, fd, &msgh, MSG_DONTWAIT, + OSPF_MAX_PACKET_SIZE + 1); if (ret < 0) { - flog_warn(EC_OSPF_PACKET, "stream_recvmsg failed: %s", - safe_strerror(errno)); + if (errno != EAGAIN && errno != EWOULDBLOCK) + flog_warn(EC_OSPF_PACKET, "stream_recvmsg failed: %s", + safe_strerror(errno)); return NULL; } if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */ @@ -2385,6 +2375,10 @@ static struct stream *ospf_recv_packet(struct ospf *ospf, int fd, return NULL; } + if (IS_DEBUG_OSPF_PACKET(0, RECV)) + zlog_debug("%s: fd %d(%s) on interface %d(%s)", + __PRETTY_FUNCTION__, fd, ospf_get_name(ospf), + ifindex, *ifp ? (*ifp)->name : "Unknown"); return ibuf; } @@ -2943,56 +2937,60 @@ static int ospf_verify_header(struct stream *ibuf, struct ospf_interface *oi, return 0; } -/* Starting point of packet process function. */ -int ospf_read(struct thread *thread) +enum ospf_read_return_enum { + OSPF_READ_ERROR, + OSPF_READ_CONTINUE, +}; + +static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf) { int ret; struct stream *ibuf; - struct ospf *ospf; struct ospf_interface *oi; struct ip *iph; struct ospf_header *ospfh; uint16_t length; - struct interface *ifp = NULL; struct connected *c; - - /* first of all get interface pointer. */ - ospf = THREAD_ARG(thread); - - /* prepare for next packet. */ - ospf->t_read = NULL; - thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read); + struct interface *ifp = NULL; stream_reset(ospf->ibuf); ibuf = ospf_recv_packet(ospf, ospf->fd, &ifp, ospf->ibuf); if (ibuf == NULL) - return -1; - /* This raw packet is known to be at least as big as its IP header. */ + return OSPF_READ_ERROR; - /* Note that there should not be alignment problems with this assignment - because this is at the beginning of the stream data buffer. */ + /* + * This raw packet is known to be at least as big as its + * IP header. Note that there should not be alignment problems with + * this assignment because this is at the beginning of the + * stream data buffer. + */ iph = (struct ip *)STREAM_DATA(ibuf); - /* Note that sockopt_iphdrincl_swab_systoh was called in - * ospf_recv_packet. */ - + /* + * Note that sockopt_iphdrincl_swab_systoh was called in + * ospf_recv_packet. + */ if (ifp == NULL) { - /* Handle cases where the platform does not support retrieving - the ifindex, - and also platforms (such as Solaris 8) that claim to support - ifindex - retrieval but do not. */ + /* + * Handle cases where the platform does not support + * retrieving the ifindex, and also platforms (such as + * Solaris 8) that claim to support ifindex retrieval but do + * not. + */ c = if_lookup_address((void *)&iph->ip_src, AF_INET, ospf->vrf_id); if (c) ifp = c->ifp; - if (ifp == NULL) - return 0; + if (ifp == NULL) { + if (IS_DEBUG_OSPF_PACKET(0, RECV)) + zlog_debug( + "%s: Unable to determine incoming interface from: %s(%s)", + __PRETTY_FUNCTION__, + inet_ntoa(iph->ip_src), + ospf_get_name(ospf)); + return OSPF_READ_CONTINUE; + } } - /* IP Header dump. */ - if (IS_DEBUG_OSPF_PACKET(0, RECV)) - ospf_ip_header_dump(iph); - /* Self-originated packet should be discarded silently. */ if (ospf_if_lookup_by_local_addr(ospf, NULL, iph->ip_src)) { if (IS_DEBUG_OSPF_PACKET(0, RECV)) { @@ -3000,30 +2998,32 @@ int ospf_read(struct thread *thread) "ospf_read[%s]: Dropping self-originated packet", inet_ntoa(iph->ip_src)); } - return 0; + return OSPF_READ_CONTINUE; } - /* Advance from IP header to OSPF header (iph->ip_hl has been verified - by ospf_recv_packet() to be correct). */ + /* + * Advance from IP header to OSPF header (iph->ip_hl has + * been verified by ospf_recv_packet() to be correct). + */ stream_forward_getp(ibuf, iph->ip_hl * 4); ospfh = (struct ospf_header *)stream_pnt(ibuf); if (MSG_OK - != ospf_packet_examin( - ospfh, stream_get_endp(ibuf) - stream_get_getp(ibuf))) - return -1; + != ospf_packet_examin(ospfh, stream_get_endp(ibuf) + - stream_get_getp(ibuf))) + return OSPF_READ_CONTINUE; /* Now it is safe to access all fields of OSPF packet header. */ /* associate packet with ospf interface */ oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp); - /* ospf_verify_header() relies on a valid "oi" and thus can be called - only - after the passive/backbone/other checks below are passed. These - checks - in turn access the fields of unverified "ospfh" structure for their - own - purposes and must remain very accurate in doing this. */ + /* + * ospf_verify_header() relies on a valid "oi" and thus can be called + * only after the passive/backbone/other checks below are passed. + * These checks in turn access the fields of unverified "ospfh" + * structure for their own purposes and must remain very accurate + * in doing this. + */ /* If incoming interface is passive one, ignore it. */ if (oi && OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) { @@ -3031,8 +3031,7 @@ int ospf_read(struct thread *thread) if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ignoring packet from router %s sent to %s, " - "received on a passive interface, %s", + "ignoring packet from router %s sent to %s, received on a passive interface, %s", inet_ntop(AF_INET, &ospfh->router_id, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], @@ -3048,7 +3047,7 @@ int ospf_read(struct thread *thread) OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); ospf_if_set_multicast(oi); } - return 0; + return OSPF_READ_CONTINUE; } @@ -3056,34 +3055,35 @@ int ospf_read(struct thread *thread) * or header area is backbone but ospf_interface is not * check for VLINK interface */ - if ((oi == NULL) || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id) - && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) { + if ((oi == NULL) + || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id) + && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) { if ((oi = ospf_associate_packet_vl(ospf, ifp, iph, ospfh)) == NULL) { if (!ospf->instance && IS_DEBUG_OSPF_EVENT) zlog_debug( - "Packet from [%s] received on link %s" - " but no ospf_interface", + "Packet from [%s] received on link %s but no ospf_interface", inet_ntoa(iph->ip_src), ifp->name); - return 0; + return OSPF_READ_CONTINUE; } } - /* else it must be a local ospf interface, check it was received on - * correct link + /* + * else it must be a local ospf interface, check it was + * received on correct link */ else if (oi->ifp != ifp) { if (IS_DEBUG_OSPF_EVENT) flog_warn(EC_OSPF_PACKET, "Packet from [%s] received on wrong link %s", inet_ntoa(iph->ip_src), ifp->name); - return 0; + return OSPF_READ_CONTINUE; } else if (oi->state == ISM_Down) { char buf[2][INET_ADDRSTRLEN]; + flog_warn( EC_OSPF_PACKET, - "Ignoring packet from %s to %s received on interface that is " - "down [%s]; interface flags are %s", + "Ignoring packet from %s to %s received on interface that is down [%s]; interface flags are %s", inet_ntop(AF_INET, &iph->ip_src, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], @@ -3096,13 +3096,15 @@ int ospf_read(struct thread *thread) OI_MEMBER_JOINED(oi, MEMBER_DROUTERS); if (oi->multicast_memberships) ospf_if_set_multicast(oi); - return 0; + return OSPF_READ_CONTINUE; } /* - * If the received packet is destined for AllDRouters, the packet - * should be accepted only if the received ospf interface state is - * either DR or Backup -- endo. + * If the received packet is destined for AllDRouters, the + * packet should be accepted only if the received ospf + * interface state is either DR or Backup -- endo. + * + * I wonder who endo is? */ if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS) && (oi->state != ISM_DR && oi->state != ISM_Backup)) { @@ -3114,7 +3116,7 @@ int ospf_read(struct thread *thread) /* Try to fix multicast membership. */ SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS); ospf_if_set_multicast(oi); - return 0; + return OSPF_READ_CONTINUE; } /* Verify more OSPF header fields. */ @@ -3125,7 +3127,7 @@ int ospf_read(struct thread *thread) "ospf_read[%s]: Header check failed, " "dropping.", inet_ntoa(iph->ip_src)); - return ret; + return OSPF_READ_CONTINUE; } /* Show debug receiving packet. */ @@ -3152,7 +3154,8 @@ int ospf_read(struct thread *thread) /* Adjust size to message length. */ length = ntohs(ospfh->length) - OSPF_HEADER_SIZE; - /* Read rest of the packet and call each sort of packet routine. */ + /* Read rest of the packet and call each sort of packet routine. + */ switch (ospfh->type) { case OSPF_MSG_HELLO: ospf_hello(iph, ospfh, ibuf, oi, length); @@ -3170,12 +3173,41 @@ int ospf_read(struct thread *thread) ospf_ls_ack(iph, ospfh, ibuf, oi, length); break; default: - flog_warn(EC_OSPF_PACKET, - "interface %s: OSPF packet header type %d is illegal", - IF_NAME(oi), ospfh->type); + flog_warn( + EC_OSPF_PACKET, + "interface %s(%s): OSPF packet header type %d is illegal", + IF_NAME(oi), ospf_get_name(ospf), ospfh->type); break; } + return OSPF_READ_CONTINUE; +} + +/* Starting point of packet process function. */ +int ospf_read(struct thread *thread) +{ + struct ospf *ospf; + int32_t count = 0; + enum ospf_read_return_enum ret; + + /* first of all get interface pointer. */ + ospf = THREAD_ARG(thread); + + /* prepare for next packet. */ + thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read); + + while (count < ospf->write_oi_count) { + count++; + ret = ospf_read_helper(ospf); + switch (ret) { + case OSPF_READ_ERROR: + return -1; + break; + case OSPF_READ_CONTINUE: + break; + } + } + return 0; } @@ -3714,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)); @@ -4303,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..152a7e83b7 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -53,7 +53,12 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_bfd.h" -static const char *ospf_network_type_str[] = { +FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES, + { .val_long = true, .match_profile = "datacenter", }, + { .val_long = false }, +) + +static const char *const ospf_network_type_str[] = { "Null", "POINTOPOINT", "BROADCAST", "NBMA", "POINTOMULTIPOINT", "VIRTUALLINK", "LOOPBACK"}; @@ -138,6 +143,7 @@ static struct ospf *ospf_cmd_lookup_ospf(struct vty *vty, struct ospf *ospf = NULL; int idx_vrf = 0, idx_inst = 0; const char *vrf_name = NULL; + bool created = false; *instance = 0; if (argv_find(argv, argc, "(1-65535)", &idx_inst)) @@ -149,18 +155,23 @@ static struct ospf *ospf_cmd_lookup_ospf(struct vty *vty, vrf_name = NULL; if (enable) { /* Allocate VRF aware instance */ - ospf = ospf_get(*instance, vrf_name); + ospf = ospf_get(*instance, vrf_name, &created); } else { ospf = ospf_lookup_by_inst_name(*instance, vrf_name); } } else { if (enable) { - ospf = ospf_get(*instance, NULL); + ospf = ospf_get(*instance, NULL, &created); } else { ospf = ospf_lookup_instance(*instance); } } + if (created) { + if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) + SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); + } + return ospf; } @@ -2622,11 +2633,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) @@ -4151,7 +4165,7 @@ DEFUN (show_ip_ospf_interface_traffic, static void show_ip_ospf_neighbour_header(struct vty *vty) { - vty_out(vty, "\n%-15s %3s %-15s %9s %-15s %-20s %5s %5s %5s\n", + vty_out(vty, "\n%-15s %3s %-15s %9s %-15s %-32s %5s %5s %5s\n", "Neighbor ID", "Pri", "State", "Dead Time", "Address", "Interface", "RXmtL", "RqstL", "DBsmL"); } @@ -4257,7 +4271,7 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, timebuf, sizeof(timebuf))); vty_out(vty, "%-15s ", inet_ntoa(nbr->src)); - vty_out(vty, "%-20s %5ld %5ld %5d\n", + vty_out(vty, "%-32s %5ld %5ld %5d\n", IF_NAME(oi), ospf_ls_retransmit_count(nbr), ospf_ls_request_count(nbr), @@ -4521,7 +4535,7 @@ static int show_ip_ospf_neighbor_all_common(struct vty *vty, struct ospf *ospf, "-", nbr_nbma->priority, "Down", "-"); vty_out(vty, - "%-15s %-20s %5d %5d %5d\n", + "%-32s %-20s %5d %5d %5d\n", inet_ntoa(nbr_nbma->addr), IF_NAME(oi), 0, 0, 0); } @@ -5767,7 +5781,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 +5796,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 +5848,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 +5856,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 +6061,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 +9660,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 +9717,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) { @@ -10348,9 +10369,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf) if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) vty_out(vty, " log-adjacency-changes detail\n"); - else if (!DFLT_OSPF_LOG_ADJACENCY_CHANGES) + else if (!SAVE_OSPF_LOG_ADJACENCY_CHANGES) vty_out(vty, " log-adjacency-changes\n"); - } else if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) { + } else if (SAVE_OSPF_LOG_ADJACENCY_CHANGES) { vty_out(vty, " no log-adjacency-changes\n"); } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index b12fa63723..6a4e63372a 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -293,11 +293,6 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) new->oi_write_q = list_new(); new->write_oi_count = OSPF_WRITE_INTERFACE_COUNT_DEFAULT; -/* Enable "log-adjacency-changes" */ -#if DFLT_OSPF_LOG_ADJACENCY_CHANGES - SET_FLAG(new->config, OSPF_LOG_ADJACENCY_CHANGES); -#endif - QOBJ_REG(new, ospf); new->fd = -1; @@ -368,7 +363,7 @@ struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name) return NULL; } -struct ospf *ospf_get(unsigned short instance, const char *name) +struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) { struct ospf *ospf; @@ -379,6 +374,7 @@ struct ospf *ospf_get(unsigned short instance, const char *name) else ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); + *created = (ospf == NULL); if (ospf == NULL) { ospf = ospf_new(instance, name); ospf_add(ospf); @@ -392,27 +388,18 @@ struct ospf *ospf_get(unsigned short instance, const char *name) return ospf; } -struct ospf *ospf_get_instance(unsigned short instance) +struct ospf *ospf_get_instance(unsigned short instance, bool *created) { struct ospf *ospf; ospf = ospf_lookup_instance(instance); + *created = (ospf == NULL); if (ospf == NULL) { ospf = ospf_new(instance, NULL /* VRF_DEFAULT*/); ospf_add(ospf); - if (ospf->router_id_static.s_addr == 0) { - if (vrf_lookup_by_id(ospf->vrf_id)) - ospf_router_id_update(ospf); - else { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "%s: ospf VRF (id %d) is not active yet, skip router id update", - __PRETTY_FUNCTION__, - ospf->vrf_id); - } + if (ospf->router_id_static.s_addr == 0) ospf_router_id_update(ospf); - } ospf_opaque_type11_lsa_init(ospf); } @@ -584,7 +571,6 @@ static void ospf_finish_final(struct ospf *ospf) struct ospf_vl_data *vl_data; struct listnode *node, *nnode; int i; - unsigned short instance = 0; QOBJ_UNREG(ospf); @@ -755,9 +741,6 @@ static void ospf_finish_final(struct ospf *ospf) ospf_distance_reset(ospf); route_table_finish(ospf->distance_table); - if (!CHECK_FLAG(om->options, OSPF_MASTER_SHUTDOWN)) - instance = ospf->instance; - list_delete(&ospf->areas); list_delete(&ospf->oi_write_q); @@ -778,9 +761,6 @@ static void ospf_finish_final(struct ospf *ospf) } XFREE(MTYPE_OSPF_TOP, ospf); - - if (!CHECK_FLAG(om->options, OSPF_MASTER_SHUTDOWN)) - ospf_get_instance(instance); } @@ -2173,3 +2153,11 @@ const char *ospf_vrf_id_to_name(vrf_id_t vrf_id) return vrf ? vrf->name : "NIL"; } + +const char *ospf_get_name(const struct ospf *ospf) +{ + if (ospf->name) + return ospf->name; + else + return VRF_DEFAULT_NAME; +} diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index b31ad30375..5e91e6f8e6 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -117,6 +117,14 @@ struct ospf_redist { #define ROUTEMAP(R) (R->route_map.map) }; +/* ospf->config */ +enum { + OSPF_RFC1583_COMPATIBLE = (1 << 0), + OSPF_OPAQUE_CAPABLE = (1 << 2), + OSPF_LOG_ADJACENCY_CHANGES = (1 << 3), + OSPF_LOG_ADJACENCY_DETAIL = (1 << 4), +}; + /* OSPF instance structure. */ struct ospf { /* OSPF's running state based on the '[no] router ospf [<instance>]' @@ -151,12 +159,8 @@ struct ospf { /* NSSA ABR */ uint8_t anyNSSA; /* Bump for every NSSA attached. */ - /* Configured variables. */ + /* Configuration bitmask, refer to enum above */ uint8_t config; -#define OSPF_RFC1583_COMPATIBLE (1 << 0) -#define OSPF_OPAQUE_CAPABLE (1 << 2) -#define OSPF_LOG_ADJACENCY_CHANGES (1 << 3) -#define OSPF_LOG_ADJACENCY_DETAIL (1 << 4) /* Opaque-LSA administrative flags. */ uint8_t opaque; @@ -500,8 +504,9 @@ extern struct zebra_privs_t ospfd_privs; /* Prototypes. */ extern const char *ospf_redist_string(unsigned int route_type); extern struct ospf *ospf_lookup_instance(unsigned short); -extern struct ospf *ospf_get(unsigned short instance, const char *name); -extern struct ospf *ospf_get_instance(unsigned short); +extern struct ospf *ospf_get(unsigned short instance, const char *name, + bool *created); +extern struct ospf *ospf_get_instance(unsigned short, bool *created); extern struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name); extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id); @@ -572,4 +577,5 @@ extern void ospf_vrf_unlink(struct ospf *ospf, struct vrf *vrf); const char *ospf_vrf_id_to_name(vrf_id_t vrf_id); int ospf_area_nssa_no_summary_set(struct ospf *, struct in_addr); +const char *ospf_get_name(const struct ospf *ospf); #endif /* _ZEBRA_OSPFD_H */ 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..53248f5aaf 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -127,11 +127,16 @@ DEFPY(pbr_map_match_src, pbr_map_match_src_cmd, pbrms->family = prefix->family; if (!no) { - if (prefix_same(pbrms->src, prefix)) - return CMD_SUCCESS; + if (pbrms->src) { + if (prefix_same(pbrms->src, prefix)) + return CMD_SUCCESS; + + vty_out(vty, + "A `match src-ip XX` command already exists, please remove that first\n"); + return CMD_WARNING_CONFIG_FAILED; + } - if (!pbrms->src) - pbrms->src = prefix_new(); + pbrms->src = prefix_new(); prefix_copy(pbrms->src, prefix); } else prefix_free(&pbrms->src); @@ -145,7 +150,7 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd, "[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix", NO_STR "Match the rest of the command\n" - "Choose the src ip or ipv6 prefix to use\n" + "Choose the dst ip or ipv6 prefix to use\n" "v4 Prefix\n" "v6 Prefix\n") { @@ -154,11 +159,16 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd, pbrms->family = prefix->family; if (!no) { - if (prefix_same(pbrms->dst, prefix)) - return CMD_SUCCESS; + if (pbrms->dst) { + if (prefix_same(pbrms->dst, prefix)) + return CMD_SUCCESS; - if (!pbrms->dst) - pbrms->dst = prefix_new(); + vty_out(vty, + "A `match dst-ip XX` command already exists, please remove that first\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + pbrms->dst = prefix_new(); prefix_copy(pbrms->dst, prefix); } else prefix_free(&pbrms->dst); @@ -183,24 +193,33 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd, #endif if (!no) { - if (pbrms->mark == (uint32_t) mark) - return CMD_SUCCESS; - pbrms->mark = (uint32_t) mark; - } else { + if (pbrms->mark) { + if (pbrms->mark == (uint32_t)mark) + return CMD_SUCCESS; + + vty_out(vty, + "A `match mark XX` command already exists, please remove that first\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + pbrms->mark = (uint32_t)mark; + } else pbrms->mark = 0; - } 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,19 +230,25 @@ 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", + "Nexthop Group specified: %s does not exist to remove\n", name); return CMD_WARNING_CONFIG_FAILED; } @@ -231,7 +256,7 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, if (pbrms->nhgrp_name) { if (strcmp(name, pbrms->nhgrp_name) != 0) { vty_out(vty, - "Please delete current nexthop group before modifying current one"); + "Please delete current nexthop group before modifying current one\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -268,7 +293,12 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, if (pbrms->nhgrp_name) { vty_out(vty, - "Please unconfigure the nexthop group before adding an individual nexthop"); + "Please unconfigure the nexthop group before adding an individual nexthop\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (pbrms->vrf_lookup || pbrms->vrf_unchanged) { + vty_out(vty, SET_VRF_EXISTS_STR); return CMD_WARNING_CONFIG_FAILED; } @@ -345,7 +375,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, if (pbrms->nhg->nexthop) { vty_out(vty, - "If you would like more than one nexthop please use nexthop-groups"); + "If you would like more than one nexthop please use nexthop-groups\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -372,6 +402,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 +585,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 +753,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 +834,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..06ad0f40a4 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; @@ -205,23 +234,21 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) switch (note) { case ZAPI_RULE_FAIL_INSTALL: pbrms->installed &= ~installed; - DEBUGD(&pbr_dbg_zebra, - "%s: Received RULE_FAIL_INSTALL: %" PRIu64, - __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_INSTALLED: pbrms->installed |= installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %" PRIu64, - __PRETTY_FUNCTION__, pbrms->installed); break; case ZAPI_RULE_FAIL_REMOVE: + /* Don't change state on rule removal failure */ + break; case ZAPI_RULE_REMOVED: pbrms->installed &= ~installed; - DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED: %" PRIu64, - __PRETTY_FUNCTION__, pbrms->installed); break; } + DEBUGD(&pbr_dbg_zebra, "%s: Received %s: %" PRIu64, __func__, + zapi_rule_notify_owner2str(note), pbrms->installed); + pbr_map_final_interface_deletion(pbrms->parent, pmi); return 0; @@ -421,6 +448,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 +511,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 +549,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_bsm.c b/pimd/pim_bsm.c index 1383e3db11..4a69e4d1ab 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -1111,6 +1111,13 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, int ins_count = 0; while (buflen > offset) { + if (offset + (int)sizeof(struct bsmmsg_grpinfo) > buflen) { + if (PIM_DEBUG_BSM) + zlog_debug( + "%s: buflen received %d is less than the internal data structure of the packet would suggest", + __PRETTY_FUNCTION__, buflen); + return false; + } /* Extract Group tlv from BSM */ memcpy(&grpinfo, buf, sizeof(struct bsmmsg_grpinfo)); @@ -1142,6 +1149,12 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, } group.family = AF_INET; + if (grpinfo.group.mask > IPV4_MAX_BITLEN) { + if (PIM_DEBUG_BSM) + zlog_debug("%s, v4 prefix length specified: %d is too long", + __PRETTY_FUNCTION__, grpinfo.group.mask); + return false; + } group.prefixlen = grpinfo.group.mask; group.u.prefix4.s_addr = grpinfo.group.addr.s_addr; @@ -1174,6 +1187,15 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, ins_count = 0; while (frag_rp_cnt--) { + if (offset + (int)sizeof(struct bsmmsg_rpinfo) + > buflen) { + if (PIM_DEBUG_BSM) + zlog_debug( + "%s, buflen received: %u is less than the internal data structure of the packet would suggest", + __PRETTY_FUNCTION__, buflen); + return false; + } + /* Extract RP address tlv from BSM */ memcpy(&rpinfo, buf, sizeof(struct bsmmsg_rpinfo)); rpinfo.rp_holdtime = ntohs(rpinfo.rp_holdtime); @@ -1245,6 +1267,13 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf, return -1; } + if (buf_size < (PIM_MSG_HEADER_LEN + sizeof(struct bsm_hdr))) { + if (PIM_DEBUG_BSM) + zlog_debug("%s: received buffer length of %d which is too small to properly decode", + __PRETTY_FUNCTION__, buf_size); + return -1; + } + bshdr = (struct bsm_hdr *)(buf + PIM_MSG_HEADER_LEN); pim_inet4_dump("<bsr?>", bshdr->bsr_addr.addr, bsr_str, sizeof(bsr_str)); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index ae7d32bb3b..7375e6d9b8 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" @@ -7588,12 +7589,14 @@ static int pim_cmd_interface_add(struct interface *ifp) struct pim_interface *pim_ifp = ifp->info; if (!pim_ifp) - (void)pim_if_new(ifp, false, true, false, false); + pim_ifp = pim_if_new(ifp, false, true, false, false); else PIM_IF_DO_PIM(pim_ifp->options); pim_if_addr_add_all(ifp); pim_if_membership_refresh(ifp); + + pim_if_create_pimreg(pim_ifp->pim); return 1; } @@ -7665,9 +7668,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; } @@ -8585,6 +8588,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", @@ -10613,6 +10630,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_iface.c b/pimd/pim_iface.c index 3ee9caebcf..c615540149 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1481,6 +1481,13 @@ void pim_if_create_pimreg(struct pim_instance *pim) pim_if_new(pim->regiface, false, false, true, false /*vxlan_term*/); + /* + * On vrf moves we delete the interface if there + * is nothing going on with it. We cannot have + * the pimregiface deleted. + */ + pim->regiface->configured = true; + } } @@ -1581,6 +1588,7 @@ int pim_ifp_create(struct interface *ifp) int pim_ifp_up(struct interface *ifp) { + struct pim_interface *pim_ifp; struct pim_instance *pim; uint32_t table_id; @@ -1593,24 +1601,21 @@ int pim_ifp_up(struct interface *ifp) } pim = pim_get_pim_instance(ifp->vrf_id); - if (if_is_operative(ifp)) { - struct pim_interface *pim_ifp; - pim_ifp = ifp->info; - /* - * If we have a pim_ifp already and this is an if_add - * that means that we probably have a vrf move event - * If that is the case, set the proper vrfness. - */ - if (pim_ifp) - pim_ifp->pim = pim; + pim_ifp = ifp->info; + /* + * If we have a pim_ifp already and this is an if_add + * that means that we probably have a vrf move event + * If that is the case, set the proper vrfness. + */ + if (pim_ifp) + pim_ifp->pim = pim; - /* - pim_if_addr_add_all() suffices for bringing up both IGMP and - PIM - */ - pim_if_addr_add_all(ifp); - } + /* + pim_if_addr_add_all() suffices for bringing up both IGMP and + PIM + */ + pim_if_addr_add_all(ifp); /* * If we have a pimreg device callback and it's for a specific 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_join.c b/pimd/pim_join.c index d63bc83862..fbb547c80e 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -83,6 +83,11 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, && (source_flags & PIM_WILDCARD_BIT_MASK)) { struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); + if (!rp) { + zlog_warn("%s: Lookup of RP failed for %pSG4", + __PRETTY_FUNCTION__, sg); + return; + } /* * If the RP sent in the message is not * our RP for the group, drop the message @@ -136,6 +141,12 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, && (source_flags & PIM_WILDCARD_BIT_MASK)) { struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); + if (!rp) { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: RP for %pSG4 completely failed lookup", + __PRETTY_FUNCTION__, sg); + return; + } // Ignoring Prune *,G's at the moment. if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) return; diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 6a7dbe769f..f0ca367258 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -29,7 +29,6 @@ #include "memory.h" #include "vrf.h" -#include "memory_vty.h" #include "filter.h" #include "vty.h" #include "sigevent.h" @@ -47,6 +46,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 +71,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 +131,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 503333a206..1fe2289a8e 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_pim.c b/pimd/pim_pim.c index cd2d306f3d..342c0a74e0 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -190,6 +190,12 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) no_fwd = header->Nbit; if (header->type == PIM_MSG_TYPE_REGISTER) { + if (pim_msg_len < PIM_MSG_REGISTER_LEN) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("PIM Register Message size=%d shorther than min length %d", + pim_msg_len, PIM_MSG_REGISTER_LEN); + return -1; + } /* First 8 byte header checksum */ checksum = in_cksum(pim_msg, PIM_MSG_REGISTER_LEN); if (checksum != pim_checksum) { diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index bf42d03604..bd295b0fef 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -448,6 +448,10 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct pim_upstream *up; struct listnode *upnode; + if (rp_addr.s_addr == INADDR_ANY || + rp_addr.s_addr == INADDR_NONE) + return PIM_RP_BAD_ADDRESS; + rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); rp_info->rp.rpf_addr.family = AF_INET; @@ -1181,8 +1185,8 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, rp_info = pim_rp_find_match_group(pim, &g); - if ((pim_rpf_addr_is_inaddr_none(&rp_info->rp)) - && (source.s_addr == INADDR_ANY)) { + if (!rp_info || ((pim_rpf_addr_is_inaddr_none(&rp_info->rp)) + && (source.s_addr == INADDR_ANY))) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); @@ -1254,7 +1258,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) json = json_object_new_object(); else vty_out(vty, - "RP address group/prefix-list OIF I am RP Source\n"); + "RP address group/prefix-list OIF I am RP Source\n"); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) { char buf[48]; @@ -1331,7 +1335,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) vty_out(vty, "%-16s ", "(Unknown)"); if (rp_info->i_am_rp) - vty_out(vty, "yes\n"); + vty_out(vty, "yes"); else vty_out(vty, "no"); diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 4fe3237395..93e1cc1f8d 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -603,9 +603,9 @@ int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags, if (type) { zlog_warn( - "%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x", + "%s: unknown source address encoding type=%d: %02x%02x%02x%02x", __PRETTY_FUNCTION__, type, buf[0], buf[1], buf[2], - buf[3], buf[4], buf[5], buf[6], buf[7]); + buf[3]); return -2; } @@ -644,9 +644,9 @@ int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags, break; default: { zlog_warn( - "%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x", + "%s: unknown source address encoding family=%d: %02x%02x%02x%02x", __PRETTY_FUNCTION__, family, buf[0], buf[1], buf[2], - buf[3], buf[4], buf[5], buf[6], buf[7]); + buf[3]); return -5; } } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 89c4e3657c..0417d0d063 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. */ @@ -471,6 +472,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..060bb76585 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -25,7 +25,6 @@ #include "thread.h" #include "command.h" #include "memory.h" -#include "memory_vty.h" #include "prefix.h" #include "filter.h" #include "keychain.h" @@ -113,7 +112,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..9daeeb9580 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -27,7 +27,6 @@ #include "vty.h" #include "command.h" #include "memory.h" -#include "memory_vty.h" #include "thread.h" #include "log.h" #include "prefix.h" @@ -113,7 +112,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/snapcraft/defaults/vrrpd.conf.default b/snapcraft/defaults/vrrpd.conf.default new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/snapcraft/defaults/vrrpd.conf.default diff --git a/snapcraft/scripts/Makefile b/snapcraft/scripts/Makefile index 7ddb7f0769..0435b3bc52 100644 --- a/snapcraft/scripts/Makefile +++ b/snapcraft/scripts/Makefile @@ -18,6 +18,7 @@ install: install -D -m 0755 staticd-service $(DESTDIR)/bin/ install -D -m 0755 bfdd-service $(DESTDIR)/bin/ install -D -m 0755 fabricd-service $(DESTDIR)/bin/ + install -D -m 0755 vrrpd-service $(DESTDIR)/bin/ install -D -m 0755 set-options $(DESTDIR)/bin/ install -D -m 0755 show_version $(DESTDIR)/bin/ diff --git a/snapcraft/scripts/vrrpd-service b/snapcraft/scripts/vrrpd-service new file mode 100644 index 0000000000..1f60d11469 --- /dev/null +++ b/snapcraft/scripts/vrrpd-service @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e -x + +if ! [ -e $SNAP_DATA/vrrpd.conf ]; then + cp $SNAP/etc/frr/vrrpd.conf.default $SNAP_DATA/vrrpd.conf +fi +exec $SNAP/sbin/vrrpd \ + -f $SNAP_DATA/vrrpd.conf \ + --pid_file $SNAP_DATA/vrrpd.pid \ + --socket $SNAP_DATA/zsock \ + --vty_socket $SNAP_DATA + diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index d8071e8cfe..b06e841f74 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -134,6 +134,13 @@ apps: - network - network-bind - network-control + vrrpd: + command: bin/vrrpd-service + daemon: simple + plugs: + - network + - network-bind + - network-control set: command: bin/set-options zebra-debug: @@ -232,7 +239,12 @@ apps: - network - network-bind - network-control - + vrrpd-debug: + command: sbin/vrrpd -f $SNAP_DATA/vrrpd.conf --pid_file $SNAP_DATA/vrrpd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA + plugs: + - network + - network-bind + - network-control parts: rtrlib: build-packages: @@ -327,6 +339,7 @@ parts: - --enable-fpm - --enable-protobuf - --enable-rpki + - --enable-vrrpd - --enable-configfile-mask=0640 - --enable-logfile-mask=0640 - --localstatedir=/var/run @@ -353,6 +366,7 @@ parts: pbrd.conf.default: etc/frr/pbrd.conf.default bfdd.conf.default: etc/frr/bfdd.conf.default fabricd.conf.default: etc/frr/fabricd.conf.default + vrrpd.conf.default: etc/frr/vrrpd.conf.default vtysh.conf.default: etc/frr/vtysh.conf.default staticd.conf.default: etc/frr/staticd.conf.default frr-scripts: 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 8cc4ccced1..8db37589af 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -431,10 +431,10 @@ static int static_route_leak( || strcasecmp(ifname, "blackhole") == 0) { if (vty) vty_out(vty, - "%% Nexthop interface cannot be Null0, reject or blackhole\n"); + "%% Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n"); else zlog_warn( - "%s: Nexthop interface cannot be Null0, reject or blackhole for %s", + "%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/staticd/static_zebra.c b/staticd/static_zebra.c index a474613b4d..42646d15bc 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -388,7 +388,8 @@ extern void static_zebra_route_add(struct route_node *rn, continue; api_nh->vrf_id = si->nh_vrf_id; - api_nh->onlink = si->onlink; + if (si->onlink) + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); si->state = STATIC_SENT_TO_ZEBRA; @@ -441,7 +442,7 @@ extern void static_zebra_route_add(struct route_node *rn, if (si->snh_label.num_labels) { int i; - SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL); api_nh->label_num = si->snh_label.num_labels; for (i = 0; i < api_nh->label_num; i++) api_nh->labels[i] = si->snh_label.label[i]; diff --git a/tests/.gitignore b/tests/.gitignore index 6252cea823..5414cb8cc9 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -45,6 +45,7 @@ /lib/test_timer_performance /lib/test_ttable /lib/test_typelist +/lib/test_versioncmp /lib/test_zlog /lib/test_zmq /ospf6d/test_lsdb diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 96e398512b..1b3f90434b 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -923,7 +923,7 @@ int main(void) if (fileno(stdout) >= 0) tty = isatty(fileno(stdout)); - if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT)) + if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0) return -1; peer = peer_create_accept(bgp); diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index fbf2a9fed2..af9e5791b7 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -1087,7 +1087,7 @@ int main(void) if (fileno(stdout) >= 0) tty = isatty(fileno(stdout)); - if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT)) + if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0) return -1; peer = peer_create_accept(bgp); diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c index 7a038fb02e..d2c093fbea 100644 --- a/tests/bgpd/test_packet.c +++ b/tests/bgpd/test_packet.c @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); - if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT)) + if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0) return -1; peer = peer_create_accept(bgp); diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c index b1dcfcf707..2de29cbdbc 100644 --- a/tests/helpers/c/main.c +++ b/tests/helpers/c/main.c @@ -24,7 +24,7 @@ #include "vty.h" #include "command.h" #include "memory.h" -#include "memory_vty.h" +#include "lib_vty.h" extern void test_init(void); @@ -154,7 +154,7 @@ int main(int argc, char **argv) /* Library inits. */ cmd_init(1); vty_init(master, false); - memory_init(); + lib_cmd_init(); yang_init(); nb_init(master, NULL, 0); diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index 2071ae08cd..e091372ab8 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -25,7 +25,7 @@ #include "vty.h" #include "command.h" #include "memory.h" -#include "memory_vty.h" +#include "lib_vty.h" #include "log.h" #include "common_cli.h" @@ -83,7 +83,7 @@ int main(int argc, char **argv) cmd_domainname_set("test.domain"); vty_init(master, false); - memory_init(); + lib_cmd_init(); yang_init(); nb_init(master, NULL, 0); diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c index 88126e84bc..391ccd9268 100644 --- a/tests/lib/cxxcompat.c +++ b/tests/lib/cxxcompat.c @@ -51,13 +51,13 @@ #include "lib/json.h" #include "lib/keychain.h" #include "lib/lib_errors.h" +#include "lib/lib_vty.h" #include "lib/libfrr.h" #include "lib/libospf.h" #include "lib/linklist.h" #include "lib/log.h" #include "lib/md5.h" #include "lib/memory.h" -#include "lib/memory_vty.h" #include "lib/mlag.h" #include "lib/module.h" #include "lib/monotime.h" diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c index 3180f9f9f3..18d3180889 100644 --- a/tests/lib/northbound/test_oper_data.c +++ b/tests/lib/northbound/test_oper_data.c @@ -23,7 +23,7 @@ #include "vty.h" #include "command.h" #include "memory.h" -#include "memory_vty.h" +#include "lib_vty.h" #include "log.h" #include "northbound.h" @@ -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, }; @@ -412,7 +412,7 @@ int main(int argc, char **argv) cmd_init(1); cmd_hostname_set("test"); vty_init(master, false); - memory_init(); + lib_cmd_init(); yang_init(); nb_init(master, modules, array_size(modules)); diff --git a/tests/lib/test_buffer.c b/tests/lib/test_buffer.c index b56cc30cf3..7fb9a769d3 100644 --- a/tests/lib/test_buffer.c +++ b/tests/lib/test_buffer.c @@ -20,7 +20,7 @@ #include <zebra.h> #include <memory.h> -#include <memory_vty.h> +#include <lib_vty.h> #include <buffer.h> struct thread_master *master; @@ -32,7 +32,7 @@ int main(int argc, char **argv) char junk[3]; char c = 'a'; - memory_init(); + lib_cmd_init(); if ((argc != 2) || (sscanf(argv[1], "%d%1s", &n, junk) != 1)) { fprintf(stderr, "Usage: %s <number of chars to simulate>\n", diff --git a/tests/lib/test_privs.c b/tests/lib/test_privs.c index de638bc67a..c06ebbeb38 100644 --- a/tests/lib/test_privs.c +++ b/tests/lib/test_privs.c @@ -22,7 +22,7 @@ #include "getopt.h" #include "privs.h" #include "memory.h" -#include "memory_vty.h" +#include "lib_vty.h" zebra_capabilities_t _caps_p[] = { ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_DAC_OVERRIDE, @@ -105,7 +105,7 @@ int main(int argc, char **argv) } /* Library inits. */ - memory_init(); + lib_cmd_init(); zprivs_preinit(&test_privs); zprivs_init(&test_privs); diff --git a/tests/lib/test_versioncmp.c b/tests/lib/test_versioncmp.c new file mode 100644 index 0000000000..bb819e36f5 --- /dev/null +++ b/tests/lib/test_versioncmp.c @@ -0,0 +1,66 @@ +/* + * frr_version_cmp() tests + * Copyright (C) 2018 David Lamparter for NetDEF, Inc. + * + * 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 <defaults.h> + +static const char *rel(int x) +{ + if (x < 0) + return "<"; + if (x > 0) + return ">"; + return "=="; +} + +static int fail; + +static void compare(const char *a, const char *b, int expect) +{ + int result = frr_version_cmp(a, b); + + if (expect == result) + printf("\"%s\" %s \"%s\"\n", a, rel(result), b); + else { + printf("\"%s\" %s \"%s\", expected %s!\n", a, rel(result), b, + rel(expect)); + fail = 1; + } +} + +int main(int argc, char **argv) +{ + compare("", "", 0); + compare("1", "1", 0); + compare("1.0", "1.00", 0); + compare("10.0", "1", 1); + compare("10.0", "2", 1); + compare("2.1", "10.0", -1); + compare("1.1.1", "1.1.0", 1); + compare("1.0a", "1.0", 1); + compare("1.0a", "1.0b", -1); + compare("1.0a10", "1.0a2", 1); + compare("1.00a2", "1.0a2", 0); + compare("1.00a2", "1.0a3", -1); + compare("1.0-dev", "1.0", 1); + compare("1.0~foo", "1.0", -1); + compare("1.0~1", "1.0~0", 1); + compare("1.00~1", "1.0~0", 1); + printf("final tally: %s\n", fail ? "FAILED" : "ok"); + return fail; +} diff --git a/tests/lib/test_versioncmp.py b/tests/lib/test_versioncmp.py new file mode 100644 index 0000000000..0990757000 --- /dev/null +++ b/tests/lib/test_versioncmp.py @@ -0,0 +1,6 @@ +import frrtest + +class TestVersionCmp(frrtest.TestMultiOut): + program = './test_versioncmp' + +TestVersionCmp.exit_cleanly() diff --git a/tests/subdir.am b/tests/subdir.am index 270c0811b4..d87d348949 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -69,6 +69,7 @@ check_PROGRAMS = \ tests/lib/test_timer_performance \ tests/lib/test_ttable \ tests/lib/test_typelist \ + tests/lib/test_versioncmp \ tests/lib/test_zlog \ tests/lib/test_graph \ tests/lib/cli/test_cli \ @@ -293,6 +294,10 @@ tests_lib_test_typelist_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_typelist_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_typelist_LDADD = $(ALL_TESTS_LDADD) tests_lib_test_typelist_SOURCES = tests/lib/test_typelist.c tests/helpers/c/prng.c +tests_lib_test_versioncmp_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_versioncmp_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_versioncmp_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_versioncmp_SOURCES = tests/lib/test_versioncmp.c tests_lib_test_zlog_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_zlog_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_zlog_LDADD = $(ALL_TESTS_LDADD) @@ -344,6 +349,7 @@ EXTRA_DIST += \ tests/lib/test_ttable.py \ tests/lib/test_ttable.refout \ tests/lib/test_typelist.py \ + tests/lib/test_versioncmp.py \ tests/lib/test_zlog.py \ tests/lib/test_graph.py \ tests/lib/test_graph.refout \ diff --git a/tests/topotests/bgp_distance_change/__init__.py b/tests/topotests/bgp_distance_change/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_distance_change/__init__.py diff --git a/tests/topotests/bgp_distance_change/r1/bgpd.conf b/tests/topotests/bgp_distance_change/r1/bgpd.conf new file mode 100644 index 0000000000..67994702bc --- /dev/null +++ b/tests/topotests/bgp_distance_change/r1/bgpd.conf @@ -0,0 +1,4 @@ +router bgp 65000 + neighbor 192.168.255.2 remote-as 65001 + exit-address-family +! diff --git a/tests/topotests/bgp_distance_change/r1/zebra.conf b/tests/topotests/bgp_distance_change/r1/zebra.conf new file mode 100644 index 0000000000..6e9b0b4a7e --- /dev/null +++ b/tests/topotests/bgp_distance_change/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_distance_change/r2/bgpd.conf b/tests/topotests/bgp_distance_change/r2/bgpd.conf new file mode 100644 index 0000000000..206f626da4 --- /dev/null +++ b/tests/topotests/bgp_distance_change/r2/bgpd.conf @@ -0,0 +1,6 @@ +router bgp 65001 + neighbor 192.168.255.1 remote-as 65000 + address-family ipv4 + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_distance_change/r2/zebra.conf b/tests/topotests/bgp_distance_change/r2/zebra.conf new file mode 100644 index 0000000000..93e3590448 --- /dev/null +++ b/tests/topotests/bgp_distance_change/r2/zebra.conf @@ -0,0 +1,9 @@ +! +interface lo + ip address 172.16.255.254/32 +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py new file mode 100644 index 0000000000..cf95aec098 --- /dev/null +++ b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python + +# +# bgp_distance_change.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. +# + +""" +bgp_distance_change.py: + +Test if works the following commands: +router bgp 65031 + address-family ipv4 unicast + distance bgp 123 123 123 + +Changed distance should reflect to RIB after changes. +""" + +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, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +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_maximum_prefix_invalid(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r1'] + + 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_distance_change(router): + router.vtysh_cmd(""" + configure terminal + router bgp 65000 + address-family ipv4 unicast + distance bgp 123 123 123 + """) + + def _bgp_check_distance_change(router): + output = json.loads(router.vtysh_cmd("show ip route 172.16.255.254/32 json")) + expected = { + '172.16.255.254/32': [ + { + 'protocol': 'bgp', + 'distance': 123 + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + + assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) + + _bgp_distance_change(router) + + test_func = functools.partial(_bgp_check_distance_change, router) + success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + + assert result is None, 'Failed to see applied BGP distance in RIB "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 02fba97316..e62d139a0c 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -153,8 +153,10 @@ def ltemplatePreRouterStartHook(): if topotest.version_cmp(krel, '4.15') >= 0 and \ topotest.version_cmp(krel, '4.18') <= 0: l3mdev_accept = 1 - else: - l3mdev_accept = 0 + + if topotest.version_cmp(krel, '5.0') >= 0: + l3mdev_accept = 1 + logger.info('setting net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)) #check for mpls if tgen.hasmpls != True: 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/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py index 6b4df78c69..2944b3729c 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py @@ -31,6 +31,7 @@ import sys import json from functools import partial import pytest +import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -68,6 +69,19 @@ def setup_module(mod): router_list = tgen.routers() logger.info('Testing with VRF Lite support') + krel = platform.release() + + # May need to adjust handling of vrf traffic depending on kernel version + l3mdev_accept = 0 + if topotest.version_cmp(krel, '4.15') >= 0 and \ + topotest.version_cmp(krel, '4.18') <= 0: + l3mdev_accept = 1 + + if topotest.version_cmp(krel, '5.0') >= 0: + l3mdev_accept = 1 + + logger.info('krel \'{0}\' setting net.ipv4.tcp_l3mdev_accept={1}'.format( + krel, l3mdev_accept)) cmds = ['ip link add {0}-cust1 type vrf table 1001', 'ip link add loop1 type dummy', @@ -78,6 +92,15 @@ def setup_module(mod): for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) + output = tgen.net[rname].cmd('sysctl -n net.ipv4.tcp_l3mdev_accept') + logger.info( + 'router {0}: existing tcp_l3mdev_accept was {1}'.format( + rname, output)) + + if l3mdev_accept: + output = tgen.net[rname].cmd( + 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)) + for rname, router in router_list.iteritems(): router.load_config( TopoRouter.RD_ZEBRA, diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 9f2fef52ea..fc7581b1f2 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -28,6 +28,7 @@ from subprocess import PIPE as SUB_PIPE from subprocess import Popen from functools import wraps from re import search as re_search +from tempfile import mkdtemp import StringIO import os @@ -276,11 +277,19 @@ def reset_config_on_routers(tgen, routerName=None): run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname) init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname) - command = "/usr/lib/frr/frr-reload.py --input {} --test {} > {}". \ - format(run_cfg_file, init_cfg_file, dname) + + tempdir = mkdtemp() + with open(os.path.join(tempdir, 'vtysh.conf'), 'w') as fd: + pass + + command = "/usr/lib/frr/frr-reload.py --confdir {} --input {} --test {} > {}". \ + format(tempdir, run_cfg_file, init_cfg_file, dname) result = call(command, shell=True, stderr=SUB_STDOUT, stdout=SUB_PIPE) + os.unlink(os.path.join(tempdir, 'vtysh.conf')) + os.rmdir(tempdir) + # Assert if command fail if result > 0: logger.error("Delta file creation failed. Command executed %s", diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index 79c52d30d1..8bec3c5bb6 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -56,6 +56,11 @@ bfdd_options=" -A 127.0.0.1" fabricd_options="-A 127.0.0.1" vrrpd_options=" -A 127.0.0.1" +# configuration profile +# +#frr_profile="traditional" +#frr_profile="datacenter" + # # This is the maximum number of FD's that will be available. # Upon startup this is read by the control files and ulimit diff --git a/tools/frr-reload.py b/tools/frr-reload.py index f5784b7ecd..3e97635dfe 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -114,7 +114,7 @@ class Config(object): self.lines = [] self.contexts = OrderedDict() - def load_from_file(self, filename): + def load_from_file(self, filename, bindir, confdir): """ Read configuration from specified file and slurp it into internal memory The internal representation has been marked appropriately by passing it @@ -123,7 +123,7 @@ class Config(object): log.info('Loading Config object from file %s', filename) try: - file_output = subprocess.check_output(['/usr/bin/vtysh', '-m', '-f', filename], + file_output = subprocess.check_output([str(bindir + '/vtysh'), '-m', '-f', filename, '--config_dir', confdir], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: ve = VtyshMarkException(e) @@ -144,7 +144,7 @@ class Config(object): self.load_contexts() - def load_from_show_running(self): + def load_from_show_running(self, bindir, confdir, daemon): """ Read running configuration and slurp it into internal memory The internal representation has been marked appropriately by passing it @@ -154,8 +154,8 @@ class Config(object): try: config_text = subprocess.check_output( - "/usr/bin/vtysh -c 'show run' | /usr/bin/tail -n +4 | /usr/bin/vtysh -m -f -", - shell=True, stderr=subprocess.STDOUT) + bindir + "/vtysh --config_dir " + confdir + " -c 'show run " + daemon + "' | /usr/bin/tail -n +4 | " + bindir + "/vtysh --config_dir " + confdir + " -m -f -", + shell=True) except subprocess.CalledProcessError as e: ve = VtyshMarkException(e) ve.output = e.output @@ -404,7 +404,8 @@ end "ip ", "ipv6 ", "log ", - "mpls", + "mpls lsp", + "mpls label", "no ", "password ", "ptm-enable", @@ -424,7 +425,12 @@ end continue # one line contexts - if new_ctx is True and any(line.startswith(keyword) for keyword in oneline_ctx_keywords): + # there is one exception though: ldpd accepts a 'router-id' clause + # as part of its 'mpls ldp' config context. If we are processing + # ldp configuration and encounter a router-id we should NOT switch + # to a new context + if new_ctx is True and any(line.startswith(keyword) for keyword in oneline_ctx_keywords) and not ( + ctx_keys and ctx_keys[0].startswith("mpls ldp") and line.startswith("router-id ")): self.save_contexts(ctx_keys, current_context_lines) # Start a new context @@ -467,7 +473,7 @@ end current_context_lines = [] log.debug('LINE %-50s: popping from subcontext to ctx%-50s', line, ctx_keys) - elif line == "exit-vni": + elif line in ["exit-vni", "exit-ldp-if"]: if sub_main_ctx_key: self.save_contexts(ctx_keys, current_context_lines) @@ -489,7 +495,8 @@ end elif (line.startswith("address-family ") or line.startswith("vnc defaults") or line.startswith("vnc l2-group") or - line.startswith("vnc nve-group")): + line.startswith("vnc nve-group") or + line.startswith("member pseudowire")): main_ctx_key = [] # Save old context first @@ -498,9 +505,9 @@ end main_ctx_key = copy.deepcopy(ctx_keys) log.debug('LINE %-50s: entering sub-context, append to ctx_keys', line) - if line == "address-family ipv6": + if line == "address-family ipv6" and not ctx_keys[0].startswith("mpls ldp"): ctx_keys.append("address-family ipv6 unicast") - elif line == "address-family ipv4": + elif line == "address-family ipv4" and not ctx_keys[0].startswith("mpls ldp"): ctx_keys.append("address-family ipv4 unicast") elif line == "address-family evpn": ctx_keys.append("address-family l2vpn evpn") @@ -518,6 +525,18 @@ end sub_main_ctx_key = copy.deepcopy(ctx_keys) log.debug('LINE %-50s: entering sub-sub-context, append to ctx_keys', line) ctx_keys.append(line) + + elif ((line.startswith("interface ") and + len(ctx_keys) == 2 and + ctx_keys[0].startswith('mpls ldp') and + ctx_keys[1].startswith('address-family'))): + + # Save old context first + self.save_contexts(ctx_keys, current_context_lines) + current_context_lines = [] + sub_main_ctx_key = copy.deepcopy(ctx_keys) + log.debug('LINE %-50s: entering sub-sub-context, append to ctx_keys', line) + ctx_keys.append(line) else: # Continuing in an existing context, add non-commented lines to it @@ -528,13 +547,15 @@ end self.save_contexts(ctx_keys, current_context_lines) -def line_to_vtysh_conft(ctx_keys, line, delete): +def line_to_vtysh_conft(ctx_keys, line, delete, bindir, confdir): """ Return the vtysh command for the specified context line """ cmd = [] - cmd.append('vtysh') + cmd.append(str(bindir + '/vtysh')) + cmd.append('--config_dir') + cmd.append(confdir) cmd.append('-c') cmd.append('conf t') @@ -755,9 +776,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if re_nbr_bfd_timers: nbr = re_nbr_bfd_timers.group(1) bfd_nbr = "neighbor %s" % nbr + bfd_search_string = bfd_nbr + r' bfd (\S+) (\S+) (\S+)' for (ctx_keys, add_line) in lines_to_add: - re_add_nbr_bfd_timers = re.search(r'neighbor bfd_nbr bfd (\S+) (\S+) (\S+)', add_line) + re_add_nbr_bfd_timers = re.search(bfd_search_string, add_line) if re_add_nbr_bfd_timers: found_add_bfd_nbr = line_exist(lines_to_add, ctx_keys, bfd_nbr, False) @@ -1074,7 +1096,7 @@ def compare_context_objects(newconf, running): -def vtysh_config_available(): +def vtysh_config_available(bindir, confdir): """ Return False if no frr daemon is running or some other vtysh session is in 'configuration terminal' mode which will prevent us from making any @@ -1082,8 +1104,8 @@ def vtysh_config_available(): """ try: - cmd = ['/usr/bin/vtysh', '-c', 'conf t'] - output = subprocess.check_output(cmd, stderr=subprocess.STDOUT).strip() + cmd = [str(bindir + '/vtysh'), '--config_dir', confdir, '-c', 'conf t'] + output = subprocess.check_output(cmd).strip() if 'VTY configuration is locked by other VTY' in output.decode('utf-8'): print(output) @@ -1110,6 +1132,11 @@ if __name__ == '__main__': parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False) parser.add_argument('filename', help='Location of new frr config file') parser.add_argument('--overwrite', action='store_true', help='Overwrite frr.conf with running config output', default=False) + parser.add_argument('--bindir', help='path to the vtysh executable', default='/usr/bin') + parser.add_argument('--confdir', help='path to the daemon config files', default='/etc/frr') + parser.add_argument('--rundir', help='path for the temp config file', default='/var/run/frr') + parser.add_argument('--daemon', help='daemon for which want to replace the config', default='') + args = parser.parse_args() # Logging @@ -1149,8 +1176,29 @@ if __name__ == '__main__': log.error(msg) sys.exit(1) + # Verify that confdir is correct + if not os.path.isdir(args.confdir): + msg = "Confdir %s is not a valid path" % args.confdir + print(msg) + log.error(msg) + sys.exit(1) + + # Verify that bindir is correct + if not os.path.isdir(args.bindir) or not os.path.isfile(args.bindir + '/vtysh'): + msg = "Bindir %s is not a valid path to vtysh" % args.bindir + print(msg) + log.error(msg) + sys.exit(1) + + # verify that the daemon, if specified, is valid + if args.daemon and args.daemon not in ['zebra', 'bgpd', 'fabricd', 'isisd', 'ospf6d', 'ospfd', 'pbrd', 'pimd', 'ripd', 'ripngd', 'sharpd', 'staticd', 'vrrpd', 'ldpd']: + msg = "Daemon %s is not a valid option for 'show running-config'" % args.daemon + print(msg) + log.error(msg) + sys.exit(1) + # Verify that 'service integrated-vtysh-config' is configured - vtysh_filename = '/etc/frr/vtysh.conf' + vtysh_filename = args.confdir + '/vtysh.conf' service_integrated_vtysh_config = True if os.path.isfile(vtysh_filename): @@ -1162,7 +1210,7 @@ if __name__ == '__main__': service_integrated_vtysh_config = False break - if not service_integrated_vtysh_config: + if not service_integrated_vtysh_config and not args.daemon: msg = "'service integrated-vtysh-config' is not configured, this is required for 'service frr reload'" print(msg) log.error(msg) @@ -1175,7 +1223,7 @@ if __name__ == '__main__': # Create a Config object from the config generated by newconf newconf = Config() - newconf.load_from_file(args.filename) + newconf.load_from_file(args.filename, args.bindir, args.confdir) reload_ok = True if args.test: @@ -1184,9 +1232,9 @@ if __name__ == '__main__': running = Config() if args.input: - running.load_from_file(args.input) + running.load_from_file(args.input, args.bindir, args.confdir) else: - running.load_from_show_running() + running.load_from_show_running(args.bindir, args.confdir, args.daemon) (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) lines_to_configure = [] @@ -1220,7 +1268,7 @@ if __name__ == '__main__': elif args.reload: # We will not be able to do anything, go ahead and exit(1) - if not vtysh_config_available(): + if not vtysh_config_available(args.bindir, args.confdir): sys.exit(1) log.debug('New Frr Config\n%s', newconf.get_lines()) @@ -1264,7 +1312,7 @@ if __name__ == '__main__': for x in range(2): running = Config() - running.load_from_show_running() + running.load_from_show_running(args.bindir, args.confdir, args.daemon) log.debug('Running Frr Config (Pass #%d)\n%s', x, running.get_lines()) (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) @@ -1296,7 +1344,7 @@ if __name__ == '__main__': # 'no' commands are tricky, we can't just put them in a file and # vtysh -f that file. See the next comment for an explanation # of their quirks - cmd = line_to_vtysh_conft(ctx_keys, line, True) + cmd = line_to_vtysh_conft(ctx_keys, line, True, args.bindir, args.confdir) original_cmd = cmd # Some commands in frr are picky about taking a "no" of the entire line. @@ -1315,7 +1363,7 @@ if __name__ == '__main__': while True: try: - _ = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + _ = subprocess.check_output(cmd) except subprocess.CalledProcessError: @@ -1352,7 +1400,7 @@ if __name__ == '__main__': string.ascii_uppercase + string.digits) for _ in range(6)) - filename = "/var/run/frr/reload-%s.txt" % random_string + filename = args.rundir + "/reload-%s.txt" % random_string log.info("%s content\n%s" % (filename, pformat(lines_to_configure))) with open(filename, 'w') as fh: @@ -1360,15 +1408,16 @@ if __name__ == '__main__': fh.write(line + '\n') try: - subprocess.check_output(['/usr/bin/vtysh', '-f', filename], stderr=subprocess.STDOUT) + subprocess.check_output([str(args.bindir + '/vtysh'), '--config_dir', args.confdir, '-f', filename]) except subprocess.CalledProcessError as e: log.warning("frr-reload.py failed due to\n%s" % e.output) reload_ok = False os.unlink(filename) # Make these changes persistent - if args.overwrite or args.filename != '/etc/frr/frr.conf': - subprocess.call(['/usr/bin/vtysh', '-c', 'write']) + target = str(args.confdir + '/frr.conf') + if args.overwrite or (not args.daemon and args.filename != target): + subprocess.call([str(args.bindir + '/vtysh'), '--config_dir', args.confdir, '-c', 'write']) if not reload_ok: sys.exit(1) diff --git a/tools/frr.in b/tools/frr.in index 50f7ecaa9f..d9816c2568 100755 --- a/tools/frr.in +++ b/tools/frr.in @@ -21,6 +21,7 @@ VTYSH="@vtysh_bin@" # /usr/bin/vtysh FRR_USER="@enable_user@" # frr FRR_GROUP="@enable_group@" # frr FRR_VTY_GROUP="@enable_vty_group@" # frrvty +FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter # Local Daemon selection may be done by using /etc/frr/daemons. # See /usr/share/doc/frr/README.Debian.gz for further information. @@ -151,7 +152,7 @@ start() --pidfile=`pidfile $dmn-$inst` \ --exec "$D_PATH/$dmn" \ -- \ - `eval echo "$""$dmn""_options"` -n "$inst" + `eval echo "$""$dmn""_options"` $frr_global_options -n "$inst" else if ! check_daemon $dmn; then echo -n " (binary does not exist)" @@ -164,14 +165,14 @@ start() --pidfile=`pidfile $dmn` \ --exec "$valgrind" \ -- --trace-children=no --leak-check=full --log-file=/var/log/frr/$dmn-valgrind.log $D_PATH/$dmn \ - `eval echo "$""$dmn""_options"` + `eval echo "$""$dmn""_options"` $frr_global_options else ${SSD} \ --start \ --pidfile=`pidfile $dmn` \ --exec "$D_PATH/$dmn" \ -- \ - `eval echo "$""$dmn""_options"` + `eval echo "$""$dmn""_options"` $frr_global_options fi fi @@ -188,7 +189,7 @@ start() --pidfile=`pidfile staticd` \ --exec "$D_PATH/staticd" \ -- \ - `eval echo "$"staticd"_options"` + `eval echo "$"staticd"_options"` $frr_global_options fi } @@ -511,6 +512,18 @@ fi # Read configuration variable file if it is present [ -r /etc/default/frr ] && . /etc/default/frr +if test -z "$frr_profile"; then + # try to autodetect config profile + if test -d /etc/cumulus; then + frr_profile=datacenter + # elif test ...; then + # -- add your distro/system here + elif test -n "$FRR_DEFAULT_PROFILE"; then + frr_profile="$FRR_DEFAULT_PROFILE" + fi +fi +test -n "$frr_profile" && frr_global_options="$frr_global_options -F $frr_profile" + MAX_INSTANCES=${MAX_INSTANCES:=5} # Set priority of un-startable daemons to 'no' and substitute 'yes' to '0' @@ -561,7 +574,7 @@ case "$1" in stop_prio 0 $dmn fi - if [ [ -n "$dmn" ] && [ "$dmn" != "zebra" ] ]; then + if [ -n "$dmn" -a "$dmn" != "zebra" ]; then [ -n "$dmn" ] && eval "${dmn/-/_}=0" start_watchfrr fi diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index 3fc38d4bed..0dfdfd0efa 100644 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -24,6 +24,7 @@ VTYSH="@vtysh_bin@" # /usr/bin/vtysh FRR_USER="@enable_user@" # frr FRR_GROUP="@enable_group@" # frr FRR_VTY_GROUP="@enable_vty_group@" # frrvty +FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter # ORDER MATTERS FOR $DAEMONS! # - keep zebra first @@ -151,7 +152,7 @@ daemon_start() { instopt="${inst:+-n $inst}" eval args="\$${daemon}_options" - if eval "$all_wrap $wrap $bin -d $instopt $args"; then + if eval "$all_wrap $wrap $bin -d $frr_global_options $instopt $args"; then log_success_msg "Started $dmninst" vtysh_b "$daemon" else @@ -298,6 +299,18 @@ if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a' unset watchfrr_options fi +if test -z "$frr_profile"; then + # try to autodetect config profile + if test -d /etc/cumulus; then + frr_profile=datacenter + # elif test ...; then + # -- add your distro/system here + elif test -n "$FRR_DEFAULT_PROFILE"; then + frr_profile="$FRR_DEFAULT_PROFILE" + fi +fi +test -n "$frr_profile" && frr_global_options="$frr_global_options -F $frr_profile" + # # other defaults and dispatch # 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/vtysh/extract.pl.in b/vtysh/extract.pl.in index d0b0c701a7..e8df08ef60 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -96,7 +96,7 @@ sub scan_file { elsif ($file =~ /lib\/if\.c$/) { $protocol = "VTYSH_INTERFACE"; } - elsif ($file =~ /lib\/filter\.c$/) { + elsif ($file =~ /lib\/(filter|lib_vty)\.c$/) { $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/agentx\.c$/) { diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 643dcb7edc..5c4e8a313b 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -725,19 +725,19 @@ int vtysh_mark_file(const char *filename) switch (vty->node) { case LDP_IPV4_IFACE_NODE: if (strncmp(vty_buf_copy, " ", 3)) { - vty_out(vty, " end\n"); + vty_out(vty, " exit-ldp-if\n"); vty->node = LDP_IPV4_NODE; } break; case LDP_IPV6_IFACE_NODE: if (strncmp(vty_buf_copy, " ", 3)) { - vty_out(vty, " end\n"); + vty_out(vty, " exit-ldp-if\n"); vty->node = LDP_IPV6_NODE; } break; case LDP_PSEUDOWIRE_NODE: if (strncmp(vty_buf_copy, " ", 2)) { - vty_out(vty, " end\n"); + vty_out(vty, " exit\n"); vty->node = LDP_L2VPN_NODE; } break; diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index c7e1d252c7..0ba1b9d9c8 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -45,7 +45,6 @@ #include "command.h" #include "memory.h" #include "linklist.h" -#include "memory_vty.h" #include "libfrr.h" #include "ferr.h" #include "lib_errors.h" diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index ea59655824..ed9616963d 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -25,7 +25,6 @@ #include <sigevent.h> #include <lib/version.h> #include "command.h" -#include "memory_vty.h" #include "libfrr.h" #include "lib_errors.h" @@ -76,7 +75,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 +143,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..bcb833b8d8 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. */ @@ -1972,6 +1977,8 @@ DEFUN (shutdown_if, struct zebra_if *if_data; if (ifp->ifindex != IFINDEX_INTERNAL) { + /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */ + rtadv_stop_ra(ifp); ret = if_unset_flags(ifp, IFF_UP); if (ret < 0) { vty_out(vty, "Can't shutdown interface\n"); 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..75f825e507 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -27,7 +27,6 @@ #include "filter.h" #include "memory.h" #include "zebra_memory.h" -#include "memory_vty.h" #include "prefix.h" #include "log.h" #include "plist.h" @@ -84,7 +83,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'}, @@ -145,6 +144,9 @@ static void sigint(void) atomic_store_explicit(&zrouter.in_shutdown, true, memory_order_relaxed); + /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */ + rtadv_stop_ra_all(); + frr_early_fini(); zebra_dplane_pre_finish(); @@ -229,7 +231,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/redistribute.c b/zebra/redistribute.c index 98603c9693..6aa52bcb61 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -637,13 +637,15 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *newre; struct route_entry *same; struct prefix p; + struct nexthop_group *ng; route_map_result_t ret = RMAP_PERMITMATCH; afi_t afi; afi = family2afi(rn->p.family); if (rmap_name) ret = zebra_import_table_route_map_check( - afi, re->type, re->instance, &rn->p, re->ng->nexthop, + afi, re->type, re->instance, &rn->p, + re->nhe->nhg->nexthop, zvrf->vrf->vrf_id, re->tag, rmap_name); if (ret != RMAP_PERMITMATCH) { @@ -678,10 +680,11 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, newre->table = zvrf->table_id; newre->uptime = monotime(NULL); newre->instance = re->table; - newre->ng = nexthop_group_new(); - route_entry_copy_nexthops(newre, re->ng->nexthop); - rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre); + ng = nexthop_group_new(); + copy_nexthops(&ng->nexthop, re->nhe->nhg->nexthop, NULL); + + rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre, ng); return 0; } @@ -696,8 +699,9 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, prefix_copy(&p, &rn->p); rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE, - re->table, re->flags, &p, NULL, re->ng->nexthop, re->nhe_id, - zvrf->table_id, re->metric, re->distance, false); + re->table, re->flags, &p, NULL, re->nhe->nhg->nexthop, + re->nhe_id, zvrf->table_id, re->metric, re->distance, + false); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index 35aa011c0d..927675e3d9 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -35,6 +35,7 @@ #include "if.h" #include "mpls.h" #include "srcdest_table.h" +#include "zebra/zebra_nhg.h" #ifdef __cplusplus extern "C" { @@ -87,10 +88,14 @@ struct route_entry { /* Link list. */ struct re_list_item next; - /* Nexthop structure (from RIB) */ - struct nexthop_group *ng; + /* Nexthop group, shared/refcounted, based on the nexthop(s) + * provided by the owner of the route + */ + struct nhg_hash_entry *nhe; - /* Nexthop group from FIB (optional) */ + /* Nexthop group from FIB (optional), reflecting what is actually + * installed in the FIB if that differs. + */ struct nexthop_group fib_ng; /* Nexthop group hash entry ID */ @@ -307,33 +312,9 @@ typedef enum { RIB_UPDATE_MAX } rib_update_event_t; -extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re, - ifindex_t ifindex, - vrf_id_t nh_vrf_id); -extern struct nexthop * -route_entry_nexthop_blackhole_add(struct route_entry *re, - enum blackhole_type bh_type); -extern struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *re, - struct in_addr *ipv4, - struct in_addr *src, - vrf_id_t nh_vrf_id); -extern struct nexthop * -route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, - struct in_addr *ipv4, struct in_addr *src, - ifindex_t ifindex, vrf_id_t nh_vrf_id); -extern void route_entry_nexthop_delete(struct route_entry *re, - struct nexthop *nexthop); -extern struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *re, - struct in6_addr *ipv6, - vrf_id_t nh_vrf_id); -extern struct nexthop * -route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, - struct in6_addr *ipv6, ifindex_t ifindex, - vrf_id_t nh_vrf_id); -extern void route_entry_nexthop_add(struct route_entry *re, - struct nexthop *nexthop); extern void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh); +int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new); #define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re) extern void _route_entry_dump(const char *func, union prefixconstptr pp, @@ -368,7 +349,8 @@ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, uint32_t mtu, uint8_t distance, route_tag_t tag); extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, - struct prefix_ipv6 *src_p, struct route_entry *re); + struct prefix_ipv6 *src_p, struct route_entry *re, + struct nexthop_group *ng); extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, @@ -533,7 +515,7 @@ static inline struct nexthop_group *rib_active_nhg(struct route_entry *re) if (re->fib_ng.nexthop) return &(re->fib_ng); else - return re->ng; + return re->nhe->nhg; } extern void zebra_vty_init(void); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index c9a9a81b18..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 @@ -390,7 +390,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, } static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, - struct route_entry *re, + struct nexthop_group *ng, struct rtmsg *rtm, struct rtnexthop *rtnh, struct rtattr **tb, @@ -407,8 +407,6 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); vrf_id_t nh_vrf_id = vrf_id; - re->ng = nexthop_group_new(); - for (;;) { struct nexthop *nh = NULL; @@ -454,21 +452,19 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, if (gate && rtm->rtm_family == AF_INET) { if (index) - nh = route_entry_nexthop_ipv4_ifindex_add( - re, gate, prefsrc, index, nh_vrf_id); + nh = nexthop_from_ipv4_ifindex( + gate, prefsrc, index, nh_vrf_id); else - nh = route_entry_nexthop_ipv4_add( - re, gate, prefsrc, nh_vrf_id); + nh = nexthop_from_ipv4(gate, prefsrc, + nh_vrf_id); } else if (gate && rtm->rtm_family == AF_INET6) { if (index) - nh = route_entry_nexthop_ipv6_ifindex_add( - re, gate, index, nh_vrf_id); + nh = nexthop_from_ipv6_ifindex( + gate, index, nh_vrf_id); else - nh = route_entry_nexthop_ipv6_add(re, gate, - nh_vrf_id); + nh = nexthop_from_ipv6(gate, nh_vrf_id); } else - nh = route_entry_nexthop_ifindex_add(re, index, - nh_vrf_id); + nh = nexthop_from_ifindex(index, nh_vrf_id); if (nh) { if (num_labels) @@ -477,6 +473,9 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, if (rtnh->rtnh_flags & RTNH_F_ONLINK) SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK); + + /* Add to temporary list */ + nexthop_group_add_sorted(ng, nh); } if (rtnh->rtnh_len == 0) @@ -486,10 +485,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, rtnh = RTNH_NEXT(rtnh); } - uint8_t nhop_num = nexthop_group_nexthop_num(re->ng); - - if (!nhop_num) - nexthop_group_delete(&re->ng); + uint8_t nhop_num = nexthop_group_nexthop_num(ng); return nhop_num; } @@ -737,6 +733,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, } else { /* This is a multipath route */ struct route_entry *re; + struct nexthop_group *ng = NULL; struct rtnexthop *rtnh = (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); @@ -753,19 +750,30 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, re->nhe_id = nhe_id; if (!nhe_id) { - uint8_t nhop_num = + uint8_t nhop_num; + + /* Use temporary list of nexthops; parse + * message payload's nexthops. + */ + ng = nexthop_group_new(); + nhop_num = parse_multipath_nexthops_unicast( - ns_id, re, rtm, rtnh, tb, + ns_id, ng, rtm, rtnh, tb, prefsrc, vrf_id); zserv_nexthop_num_warn( __func__, (const struct prefix *)&p, nhop_num); + + if (nhop_num == 0) { + nexthop_group_delete(&ng); + ng = NULL; + } } - if (nhe_id || re->ng) + if (nhe_id || ng) rib_add_multipath(afi, SAFI_UNICAST, &p, - &src_p, re); + &src_p, re, ng); else XFREE(MTYPE_RE, re); } 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 2228fcfd3f..5dd6012f62 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, @@ -164,7 +166,8 @@ static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf, #define RTADV_MSG_SIZE 4096 /* Send router advertisement packet. */ -static void rtadv_send_packet(int sock, struct interface *ifp) +static void rtadv_send_packet(int sock, struct interface *ifp, + ipv6_nd_suppress_ra_status stop) { struct msghdr msg; struct iovec iov; @@ -250,7 +253,10 @@ static void rtadv_send_packet(int sock, struct interface *ifp) zif->rtadv.AdvDefaultLifetime != -1 ? zif->rtadv.AdvDefaultLifetime : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval); - rtadv->nd_ra_router_lifetime = htons(pkt_RouterLifetime); + + /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */ + rtadv->nd_ra_router_lifetime = + (stop == RA_SUPPRESS) ? htons(0) : htons(pkt_RouterLifetime); rtadv->nd_ra_reachable = htonl(zif->rtadv.AdvReachableTime); rtadv->nd_ra_retransmit = htonl(0); @@ -495,7 +501,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 */ @@ -509,7 +516,7 @@ static int rtadv_timer(struct thread *thread) ifp->name); rtadv_send_packet(rtadv_get_socket(zvrf), - ifp); + ifp, RA_ENABLE); } else { zif->rtadv.AdvIntervalTimer -= period; if (zif->rtadv.AdvIntervalTimer <= 0) { @@ -523,7 +530,7 @@ static int rtadv_timer(struct thread *thread) .MaxRtrAdvInterval; rtadv_send_packet( rtadv_get_socket(zvrf), - ifp); + ifp, RA_ENABLE); } } } @@ -535,9 +542,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, RA_ENABLE); + zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; + } else + zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS; } /* @@ -889,6 +915,8 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, if (status == RA_SUPPRESS) { /* RA is currently enabled */ if (zif->rtadv.AdvSendAdvertisements) { + rtadv_send_packet(rtadv_get_socket(zvrf), ifp, + RA_SUPPRESS); zif->rtadv.AdvSendAdvertisements = 0; zif->rtadv.AdvIntervalTimer = 0; zvrf->rtadv.adv_if_count--; @@ -904,9 +932,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; @@ -987,6 +1018,38 @@ stream_failure: return; } +/* + * send router lifetime value of zero in RAs on this interface since we're + * ceasing to advertise and want to let our neighbors know. + * RFC 4861 secion 6.2.5 + */ +void rtadv_stop_ra(struct interface *ifp) +{ + struct zebra_if *zif; + struct zebra_vrf *zvrf; + + zif = ifp->info; + zvrf = vrf_info_lookup(ifp->vrf_id); + + if (zif->rtadv.AdvSendAdvertisements) + rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_SUPPRESS); +} + +/* + * send router lifetime value of zero in RAs on all interfaces since we're + * ceasing to advertise globally and want to let all of our neighbors know + * RFC 4861 secion 6.2.5 + */ +void rtadv_stop_ra_all(void) +{ + struct vrf *vrf; + struct interface *ifp; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + FOR_ALL_INTERFACES (vrf, ifp) + rtadv_stop_ra(ifp); +} + void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS) { zebra_interface_radv_set(client, hdr, msg, zvrf, 0); @@ -996,6 +1059,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 +2062,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 +2137,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); @@ -2120,14 +2235,8 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) &rtadv->ra_timer); break; case RTADV_STOP: - if (rtadv->ra_timer) { - thread_cancel(rtadv->ra_timer); - rtadv->ra_timer = NULL; - } - if (rtadv->ra_read) { - thread_cancel(rtadv->ra_read); - rtadv->ra_read = NULL; - } + THREAD_OFF(rtadv->ra_timer); + THREAD_OFF(rtadv->ra_read); break; case RTADV_TIMER: thread_add_timer(zrouter.master, rtadv_timer, zvrf, val, @@ -2152,10 +2261,11 @@ void rtadv_init(struct zebra_vrf *zvrf) if (vrf_is_backend_netns()) { zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id); zrouter.rtadv_sock = -1; - } else if (!zrouter.rtadv_sock) { + } else { zvrf->rtadv.sock = -1; - if (!zrouter.rtadv_sock) - zrouter.rtadv_sock = rtadv_make_socket(zvrf->zns->ns_id); + if (zrouter.rtadv_sock < 0) + zrouter.rtadv_sock = + rtadv_make_socket(zvrf->zns->ns_id); } } @@ -2178,6 +2288,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..63cec94434 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 { @@ -137,6 +140,8 @@ typedef enum { extern void rtadv_init(struct zebra_vrf *zvrf); extern void rtadv_terminate(struct zebra_vrf *zvrf); +extern void rtadv_stop_ra(struct interface *ifp); +extern void rtadv_stop_ra_all(void); extern void rtadv_cmd_init(void); extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); 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 d6ade783cf..e1654a1a3c 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -559,7 +559,8 @@ int zsend_redistribute_route(int cmd, struct zserv *client, memcpy(&api.src_prefix, src_p, sizeof(api.src_prefix)); } - for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->nhe->nhg->nexthop; + nexthop; nexthop = nexthop->next) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -666,7 +667,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, * nexthop we are looking up. Therefore, we will just iterate * over the top chain of nexthops. */ - for (nexthop = re->ng->nexthop; nexthop; + for (nexthop = re->nhe->nhg->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) num += zserv_encode_nexthop(s, nexthop); @@ -1022,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, @@ -1393,6 +1394,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) struct prefix_ipv6 *src_p = NULL; struct route_entry *re; struct nexthop *nexthop = NULL; + struct nexthop_group *ng = NULL; int i, ret; vrf_id_t vrf_id = 0; struct ipaddr vtep_ip; @@ -1409,11 +1411,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) char buf_prefix[PREFIX_STRLEN]; prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: p=%s, ZAPI_MESSAGE_LABEL: %sset, flags=0x%x", - __func__, buf_prefix, - (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL) ? "" - : "un"), - api.flags); + zlog_debug("%s: p=%s, flags=0x%x", + __func__, buf_prefix, api.flags); } /* Allocate new route. */ @@ -1424,7 +1423,6 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) re->flags = api.flags; re->uptime = monotime(NULL); re->vrf_id = vrf_id; - re->ng = nexthop_group_new(); if (api.tableid) re->table = api.tableid; @@ -1438,11 +1436,13 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, &api.prefix, zebra_route_string(client->proto)); - nexthop_group_delete(&re->ng); XFREE(MTYPE_RE, re); return; } + /* Use temporary list of nexthops */ + ng = nexthop_group_new(); + /* * TBD should _all_ of the nexthop add operations use * api_nh->vrf_id instead of re->vrf_id ? I only changed @@ -1457,8 +1457,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) switch (api_nh->type) { case NEXTHOP_TYPE_IFINDEX: - nexthop = route_entry_nexthop_ifindex_add( - re, api_nh->ifindex, api_nh->vrf_id); + nexthop = nexthop_from_ifindex(api_nh->ifindex, + api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4: if (IS_ZEBRA_DEBUG_RECV) { @@ -1469,8 +1469,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) zlog_debug("%s: nh=%s, vrf_id=%d", __func__, nhbuf, api_nh->vrf_id); } - nexthop = route_entry_nexthop_ipv4_add( - re, &api_nh->gate.ipv4, NULL, api_nh->vrf_id); + nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, + NULL, api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -1486,8 +1486,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, nhbuf, api_nh->vrf_id, re->vrf_id, ifindex); } - nexthop = route_entry_nexthop_ipv4_ifindex_add( - re, &api_nh->gate.ipv4, NULL, ifindex, + nexthop = nexthop_from_ipv4_ifindex( + &api_nh->gate.ipv4, NULL, ifindex, api_nh->vrf_id); /* Special handling for IPv4 routes sourced from EVPN: @@ -1504,15 +1504,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } break; case NEXTHOP_TYPE_IPV6: - nexthop = route_entry_nexthop_ipv6_add( - re, &api_nh->gate.ipv6, api_nh->vrf_id); + nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, + api_nh->vrf_id); break; case NEXTHOP_TYPE_IPV6_IFINDEX: memset(&vtep_ip, 0, sizeof(struct ipaddr)); ifindex = api_nh->ifindex; - nexthop = route_entry_nexthop_ipv6_ifindex_add( - re, &api_nh->gate.ipv6, ifindex, - api_nh->vrf_id); + nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6, + ifindex, + api_nh->vrf_id); /* Special handling for IPv6 routes sourced from EVPN: * the nexthop and associated MAC need to be installed. @@ -1527,8 +1527,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } break; case NEXTHOP_TYPE_BLACKHOLE: - nexthop = route_entry_nexthop_blackhole_add( - re, api_nh->bh_type); + nexthop = nexthop_from_blackhole(api_nh->bh_type); break; } @@ -1537,15 +1536,16 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) EC_ZEBRA_NEXTHOP_CREATION_FAILED, "%s: Nexthops Specified: %d but we failed to properly create one", __PRETTY_FUNCTION__, api.nexthop_num); - nexthop_group_delete(&re->ng); + nexthop_group_delete(&ng); XFREE(MTYPE_RE, re); return; } - if (api_nh->onlink) + + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); /* MPLS labels for BGP-LU or Segment Routing */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL) + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) && api_nh->type != NEXTHOP_TYPE_IFINDEX && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { enum lsp_types_t label_type; @@ -1563,6 +1563,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) api_nh->label_num, &api_nh->labels[0]); } + + /* Add new nexthop to temporary list */ + nexthop_group_add_sorted(ng, nexthop); } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) @@ -1579,14 +1582,14 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) flog_warn(EC_ZEBRA_RX_SRCDEST_WRONG_AFI, "%s: Received SRC Prefix but afi is not v6", __PRETTY_FUNCTION__); - nexthop_group_delete(&re->ng); + nexthop_group_delete(&ng); XFREE(MTYPE_RE, re); return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) src_p = &api.src_prefix; - ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re); + ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng); /* Stats */ switch (api.prefix.family) { @@ -1782,7 +1785,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)) @@ -1883,7 +1886,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)) { @@ -2282,10 +2285,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: @@ -2485,7 +2489,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, @@ -2556,6 +2560,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 7f993442a6..ca72ea5227 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; } @@ -1507,7 +1508,8 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, ctx->u.rinfo.zd_safi = info->safi; /* Copy nexthops; recursive info is included too */ - copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), re->ng->nexthop, NULL); + copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), + re->nhe->nhg->nexthop, NULL); /* Ensure that the dplane's nexthops flags are clear. */ for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) @@ -1660,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; @@ -1746,7 +1749,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, if (re) copy_nexthops(&(ctx->u.pw.nhg.nexthop), - re->ng->nexthop, NULL); + re->nhe->nhg->nexthop, NULL); route_unlock_node(rn); } @@ -1842,7 +1845,7 @@ dplane_route_update_internal(struct route_node *rn, * We'll need these to do per-nexthop deletes. */ copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop), - old_re->ng->nexthop, NULL); + old_re->nhe->nhg->nexthop, NULL); #endif /* !HAVE_NETLINK */ } @@ -2811,6 +2814,7 @@ int dplane_provider_register(const char *name, TAILQ_INIT(&(p->dp_ctx_in_q)); TAILQ_INIT(&(p->dp_ctx_out_q)); + p->dp_flags = flags; p->dp_priority = prio; p->dp_fp = fp; p->dp_start = start_fp; 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_fpm.c b/zebra/zebra_fpm.c index 5d88d4eeb4..fa48c03c71 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -498,6 +498,11 @@ static inline void zfpm_write_off(void) THREAD_WRITE_OFF(zfpm_g->t_write); } +static inline void zfpm_connect_off(void) +{ + THREAD_TIMER_OFF(zfpm_g->t_connect); +} + /* * zfpm_conn_up_thread_cb * @@ -731,7 +736,6 @@ static int zfpm_read_cb(struct thread *thread) fpm_msg_hdr_t *hdr; zfpm_g->stats.read_cb_calls++; - zfpm_g->t_read = NULL; /* * Check if async connect is now done. @@ -1157,7 +1161,6 @@ static int zfpm_write_cb(struct thread *thread) int num_writes; zfpm_g->stats.write_cb_calls++; - zfpm_g->t_write = NULL; /* * Check if async connect is now done. @@ -1241,7 +1244,6 @@ static int zfpm_connect_cb(struct thread *t) int sock, ret; struct sockaddr_in serv; - zfpm_g->t_connect = NULL; assert(zfpm_g->state == ZFPM_STATE_ACTIVE); sock = socket(AF_INET, SOCK_STREAM, 0); @@ -2029,11 +2031,24 @@ static int zfpm_init(struct thread_master *master) return 0; } +static int zfpm_fini(void) +{ + zfpm_write_off(); + zfpm_read_off(); + zfpm_connect_off(); + + zfpm_stop_stats_timer(); + + hook_unregister(rib_update, zfpm_trigger_update); + return 0; +} + static int zebra_fpm_module_init(void) { hook_register(rib_update, zfpm_trigger_update); hook_register(zebra_rmac_update, zfpm_trigger_rmac_update); hook_register(frr_late_init, zfpm_init); + hook_register(frr_early_fini, zfpm_fini); return 0; } diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c index debcf60ee5..389781d4f7 100644 --- a/zebra/zebra_fpm_dt.c +++ b/zebra/zebra_fpm_dt.c @@ -90,7 +90,7 @@ static int zfpm_dt_find_route(rib_dest_t **dest_p, struct route_entry **re_p) if (!re) continue; - if (nexthop_group_active_nexthop_num(re->ng) == 0) + if (nexthop_group_active_nexthop_num(re->nhe->nhg) == 0) continue; *dest_p = dest; diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index b54d8fbc12..7786dc246c 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -314,7 +314,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, ri->rtm_type = RTN_UNICAST; ri->metric = &re->metric; - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { if (ri->num_nhs >= zrouter.multipath_num) break; diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c index a11517ab8b..c09fa1c65d 100644 --- a/zebra/zebra_fpm_protobuf.c +++ b/zebra/zebra_fpm_protobuf.c @@ -173,7 +173,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, * Figure out the set of nexthops to be added to the message. */ num_nhs = 0; - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { if (num_nhs >= zrouter.multipath_num) break; 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 6942a37989..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); @@ -185,7 +186,8 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, * the label advertised by the recursive nexthop (plus we don't have the * logic yet to push multiple labels). */ - for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) { + for (nexthop = re->nhe->nhg->nexthop; + nexthop; nexthop = nexthop->next) { /* Skip inactive and recursive entries. */ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -218,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; @@ -635,7 +638,7 @@ static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe, || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) continue; - for (match_nh = match->ng->nexthop; match_nh; + for (match_nh = match->nhe->nhg->nexthop; match_nh; match_nh = match_nh->next) { if (match->type == ZEBRA_ROUTE_CONNECT || nexthop->ifindex == match_nh->ifindex) { @@ -686,10 +689,10 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, break; } - if (!match || !match->ng->nexthop) + if (!match || !match->nhe->nhg->nexthop) return 0; - nexthop->ifindex = match->ng->nexthop->ifindex; + nexthop->ifindex = match->nhe->nhg->nexthop->ifindex; return 1; } @@ -1197,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; @@ -1216,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; @@ -2083,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); } /* @@ -2572,7 +2578,7 @@ static void mpls_zebra_nhg_update(struct route_entry *re, afi_t afi, nhe = zebra_nhg_rib_find(0, new_grp, afi); - zebra_nhg_re_update_ref(re, nhe); + route_entry_update_nhe(re, nhe); } static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop, @@ -2626,7 +2632,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, * We can't just change the values here since we are hashing * on labels. We need to create a whole new group */ - nexthop_group_copy(&new_grp, re->ng); + nexthop_group_copy(&new_grp, re->nhe->nhg); found = false; for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { @@ -2707,7 +2713,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, if (re == NULL) return -1; - nexthop_group_copy(&new_grp, re->ng); + nexthop_group_copy(&new_grp, re->nhe->nhg); for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) nexthop_del_labels(nexthop); @@ -2730,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; @@ -2759,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); @@ -2921,7 +2950,7 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, RNODE_FOREACH_RE (rn, re) { struct nexthop_group new_grp = {}; - nexthop_group_copy(&new_grp, re->ng); + nexthop_group_copy(&new_grp, re->nhe->nhg); for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { @@ -3058,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 d33f3a432a..1a70250627 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -299,13 +299,22 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe, } } -static struct nhg_hash_entry *zebra_nhg_copy(struct nhg_hash_entry *copy, - uint32_t id) +struct nhg_hash_entry *zebra_nhg_alloc(void) { struct nhg_hash_entry *nhe; nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry)); + return nhe; +} + +static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy, + uint32_t id) +{ + struct nhg_hash_entry *nhe; + + nhe = zebra_nhg_alloc(); + nhe->id = id; nhe->nhg = nexthop_group_new(); @@ -468,7 +477,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, struct nhg_hash_entry *depend = NULL; struct nexthop_group resolved_ng = {}; - _nexthop_group_add_sorted(&resolved_ng, nh); + nexthop_group_add_sorted(&resolved_ng, nh); depend = zebra_nhg_rib_find(0, &resolved_ng, afi); depends_add(nhg_depends, depend); @@ -582,27 +591,13 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type) struct nhg_hash_entry *nhe = NULL; struct nexthop_group nhg = {}; - _nexthop_group_add_sorted(&nhg, nh); + nexthop_group_add_sorted(&nhg, nh); zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, 0); return nhe; } -static struct nhg_ctx *nhg_ctx_new() -{ - struct nhg_ctx *new = NULL; - - new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx)); - - return new; -} - -static void nhg_ctx_free(struct nhg_ctx *ctx) -{ - XFREE(MTYPE_NHG_CTX, ctx); -} - static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx) { return ctx->id; @@ -658,6 +653,36 @@ static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx) return ctx->u.grp; } +static struct nhg_ctx *nhg_ctx_new() +{ + struct nhg_ctx *new = NULL; + + new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx)); + + return new; +} + +static void nhg_ctx_free(struct nhg_ctx **ctx) +{ + struct nexthop *nh; + + if (ctx == NULL) + return; + + assert((*ctx) != NULL); + + if (nhg_ctx_get_count(*ctx)) + goto done; + + nh = nhg_ctx_get_nh(*ctx); + + nexthop_del_labels(nh); + +done: + XFREE(MTYPE_NHG_CTX, *ctx); + *ctx = NULL; +} + static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, struct nh_grp *grp, vrf_id_t vrf_id, afi_t afi, int type, uint8_t count) @@ -906,23 +931,13 @@ static int nhg_ctx_process_del(struct nhg_ctx *ctx) return 0; } -static void nhg_ctx_process_finish(struct nhg_ctx *ctx) +static void nhg_ctx_fini(struct nhg_ctx **ctx) { - struct nexthop *nh; - /* * Just freeing for now, maybe do something more in the future * based on flag. */ - if (nhg_ctx_get_count(ctx)) - goto done; - - nh = nhg_ctx_get_nh(ctx); - - nexthop_del_labels(nh); - -done: nhg_ctx_free(ctx); } @@ -978,7 +993,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx) nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS)); - nhg_ctx_process_finish(ctx); + nhg_ctx_fini(&ctx); return ret; } @@ -1007,7 +1022,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, return nhg_ctx_process(ctx); if (queue_add(ctx)) { - nhg_ctx_process_finish(ctx); + nhg_ctx_fini(&ctx); return -1; } @@ -1024,7 +1039,7 @@ int zebra_nhg_kernel_del(uint32_t id) nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL); if (queue_add(ctx)) { - nhg_ctx_process_finish(ctx); + nhg_ctx_fini(&ctx); return -1; } @@ -1037,6 +1052,9 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) struct nexthop *lookup = NULL; struct nhg_hash_entry *nhe = NULL; + if (!nh) + goto done; + copy_nexthops(&lookup, nh, NULL); /* Clear it, in case its a group */ @@ -1049,6 +1067,7 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) nexthops_free(lookup); +done: return nhe; } @@ -1118,12 +1137,8 @@ static void zebra_nhg_free_members(struct nhg_hash_entry *nhe) nhg_connected_tree_free(&nhe->nhg_dependents); } -void zebra_nhg_free(void *arg) +void zebra_nhg_free(struct nhg_hash_entry *nhe) { - struct nhg_hash_entry *nhe = NULL; - - nhe = (struct nhg_hash_entry *)arg; - if (nhe->refcnt) zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt); @@ -1132,6 +1147,11 @@ void zebra_nhg_free(void *arg) XFREE(MTYPE_NHG, nhe); } +void zebra_nhg_hash_free(void *p) +{ + zebra_nhg_free((struct nhg_hash_entry *)p); +} + void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe) { nhe->refcnt--; @@ -1344,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) { @@ -1426,7 +1457,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ - newhop = match->ng->nexthop; + newhop = match->nhe->nhg->nexthop; if (newhop) { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV6) @@ -1435,7 +1466,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return 1; } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; - for (ALL_NEXTHOPS_PTR(match->ng, newhop)) { + for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; @@ -1456,7 +1487,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return resolved; } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; - for (ALL_NEXTHOPS_PTR(match->ng, newhop)) { + for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; @@ -1647,7 +1678,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); /* Copy over the nexthops in current state */ - nexthop_group_copy(&new_grp, re->ng); + nexthop_group_copy(&new_grp, re->nhe->nhg); for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { @@ -1665,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; } @@ -1694,7 +1728,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) new_nhe = zebra_nhg_rib_find(0, &new_grp, rt_afi); - zebra_nhg_re_update_ref(re, new_nhe); + route_entry_update_nhe(re, new_nhe); } if (curr_active) { @@ -1720,40 +1754,6 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) return curr_active; } -static void zebra_nhg_re_attach_ref(struct route_entry *re, - struct nhg_hash_entry *new) -{ - re->ng = new->nhg; - re->nhe_id = new->id; - - zebra_nhg_increment_ref(new); -} - -int zebra_nhg_re_update_ref(struct route_entry *re, struct nhg_hash_entry *new) -{ - struct nhg_hash_entry *old = NULL; - int ret = 0; - - if (new == NULL) { - re->ng = NULL; - goto done; - } - - if (re->nhe_id != new->id) { - old = zebra_nhg_lookup_id(re->nhe_id); - - zebra_nhg_re_attach_ref(re, new); - - if (old) - zebra_nhg_decrement_ref(old); - } else if (!re->ng) - /* This is the first time it's being attached */ - zebra_nhg_re_attach_ref(re, new); - -done: - return ret; -} - /* Convert a nhe into a group array */ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, int max_num) diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 1f695433c9..522ec1e9dd 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -23,11 +23,9 @@ #ifndef __ZEBRA_NHG_H__ #define __ZEBRA_NHG_H__ -#include "zebra/rib.h" +#include "lib/nexthop.h" #include "lib/nexthop_group.h" -#include "zebra/zebra_dplane.h" - /* This struct is used exclusively for dataplane * interaction via a dataplane context. * @@ -160,6 +158,11 @@ struct nhg_ctx { * NHE abstracted tree functions. * Use these where possible instead of the direct ones access ones. */ +struct nhg_hash_entry *zebra_nhg_alloc(void); +void zebra_nhg_free(struct nhg_hash_entry *nhe); +/* In order to clear a generic hash, we need a generic api, sigh. */ +void zebra_nhg_hash_free(void *p); + extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe); extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe); @@ -201,8 +204,6 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi); /* Reference counter functions */ extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); -extern int zebra_nhg_re_update_ref(struct route_entry *re, - struct nhg_hash_entry *nhe); /* Check validity of nhe, if invalid will update dependents as well */ extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe); @@ -224,5 +225,6 @@ extern void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx); extern void zebra_nhg_sweep_table(struct hash *hash); /* Nexthop resolution processing */ +struct route_entry; /* Forward ref to avoid circular includes */ extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); #endif diff --git a/zebra/zebra_nhg_private.h b/zebra/zebra_nhg_private.h index 170e2357e3..79107b047c 100644 --- a/zebra/zebra_nhg_private.h +++ b/zebra/zebra_nhg_private.h @@ -57,6 +57,4 @@ extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head, extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head, struct nhg_hash_entry *nhe); -extern void zebra_nhg_free(void *arg); - #endif /* __ZEBRA_NHG_PRIVATE_H__ */ diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 3f1567a95b..618a232408 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -259,7 +259,7 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw) * Need to ensure that there's a label binding for all nexthops. * Otherwise, ECMP for this route could render the pseudowire unusable. */ - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { if (!nexthop->nh_label) { if (IS_ZEBRA_DEBUG_PW) zlog_debug("%s: unlabeled route for %s", diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 781963793e..d525da26ee 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -193,144 +193,47 @@ int zebra_check_addr(const struct prefix *p) return 1; } -/* Add nexthop to the end of a rib node's nexthop list */ -void route_entry_nexthop_add(struct route_entry *re, struct nexthop *nexthop) -{ - _nexthop_group_add_sorted(re->ng, nexthop); -} - - /** * copy_nexthop - copy a nexthop to the rib structure. */ void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh) { - assert(!re->ng->nexthop); - copy_nexthops(&re->ng->nexthop, nh, NULL); -} - -/* Delete specified nexthop from the list. */ -void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop) -{ - if (nexthop->next) - nexthop->next->prev = nexthop->prev; - if (nexthop->prev) - nexthop->prev->next = nexthop->next; - else - re->ng->nexthop = nexthop->next; + assert(!re->nhe->nhg->nexthop); + copy_nexthops(&re->nhe->nhg->nexthop, nh, NULL); } - -struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re, - ifindex_t ifindex, - vrf_id_t nh_vrf_id) +static void route_entry_attach_ref(struct route_entry *re, + struct nhg_hash_entry *new) { - struct nexthop *nexthop; - - nexthop = nexthop_new(); - nexthop->type = NEXTHOP_TYPE_IFINDEX; - nexthop->ifindex = ifindex; - nexthop->vrf_id = nh_vrf_id; - - route_entry_nexthop_add(re, nexthop); + re->nhe = new; + re->nhe_id = new->id; - return nexthop; + zebra_nhg_increment_ref(new); } -struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *re, - struct in_addr *ipv4, - struct in_addr *src, - vrf_id_t nh_vrf_id) +int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new) { - struct nexthop *nexthop; - - nexthop = nexthop_new(); - nexthop->type = NEXTHOP_TYPE_IPV4; - nexthop->vrf_id = nh_vrf_id; - nexthop->gate.ipv4 = *ipv4; - if (src) - nexthop->src.ipv4 = *src; - - route_entry_nexthop_add(re, nexthop); - - return nexthop; -} - -struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re, - struct in_addr *ipv4, - struct in_addr *src, - ifindex_t ifindex, - vrf_id_t nh_vrf_id) -{ - struct nexthop *nexthop; - struct interface *ifp; - - nexthop = nexthop_new(); - nexthop->vrf_id = nh_vrf_id; - nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; - nexthop->gate.ipv4 = *ipv4; - if (src) - nexthop->src.ipv4 = *src; - nexthop->ifindex = ifindex; - ifp = if_lookup_by_index(nexthop->ifindex, nh_vrf_id); - /*Pending: need to think if null ifp here is ok during bootup? - There was a crash because ifp here was coming to be NULL */ - if (ifp) - if (connected_is_unnumbered(ifp)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - - route_entry_nexthop_add(re, nexthop); - - return nexthop; -} - -struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *re, - struct in6_addr *ipv6, - vrf_id_t nh_vrf_id) -{ - struct nexthop *nexthop; - - nexthop = nexthop_new(); - nexthop->vrf_id = nh_vrf_id; - nexthop->type = NEXTHOP_TYPE_IPV6; - nexthop->gate.ipv6 = *ipv6; - - route_entry_nexthop_add(re, nexthop); - - return nexthop; -} - -struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re, - struct in6_addr *ipv6, - ifindex_t ifindex, - vrf_id_t nh_vrf_id) -{ - struct nexthop *nexthop; + struct nhg_hash_entry *old = NULL; + int ret = 0; - nexthop = nexthop_new(); - nexthop->vrf_id = nh_vrf_id; - nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; - nexthop->gate.ipv6 = *ipv6; - nexthop->ifindex = ifindex; + if (new == NULL) { + re->nhe->nhg = NULL; + goto done; + } - route_entry_nexthop_add(re, nexthop); + if (re->nhe_id != new->id) { + old = zebra_nhg_lookup_id(re->nhe_id); - return nexthop; -} + route_entry_attach_ref(re, new); -struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re, - enum blackhole_type bh_type) -{ - struct nexthop *nexthop; + if (old) + zebra_nhg_decrement_ref(old); + } else if (!re->nhe->nhg) + /* This is the first time it's being attached */ + route_entry_attach_ref(re, new); - nexthop = nexthop_new(); - nexthop->vrf_id = VRF_DEFAULT; - nexthop->type = NEXTHOP_TYPE_BLACKHOLE; - nexthop->bh_type = bh_type; - - route_entry_nexthop_add(re, nexthop); - - return nexthop; +done: + return ret; } struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, @@ -501,7 +404,7 @@ int zebra_rib_labeled_unicast(struct route_entry *re) if (re->type != ZEBRA_ROUTE_BGP) return 0; - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) if (!nexthop->nh_label || !nexthop->nh_label->num_labels) return 0; @@ -525,7 +428,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode_prefixes(rn, &p, &src_p); if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } @@ -603,7 +506,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) if (info->safi != SAFI_UNICAST) { UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } @@ -663,7 +566,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) re->fib_ng.nexthop = NULL; } - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } @@ -839,7 +742,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, /* Update real nexthop. This may actually determine if nexthop is active * or not. */ - if (!nexthop_group_active_nexthop_num(new->ng)) { + if (!nexthop_group_active_nexthop_num(new->nhe->nhg)) { UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); return; } @@ -908,7 +811,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, /* Update the nexthop; we could determine here that nexthop is * inactive. */ - if (nexthop_group_active_nexthop_num(new->ng)) + if (nexthop_group_active_nexthop_num(new->nhe->nhg)) nh_active = 1; /* If nexthop is active, install the selected route, if @@ -1026,7 +929,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, /* both are connected. are either loop or vrf? */ struct nexthop *nexthop = NULL; - for (ALL_NEXTHOPS_PTR(alternate->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(alternate->nhe->nhg, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, alternate->vrf_id); @@ -1034,7 +937,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return alternate; } - for (ALL_NEXTHOPS_PTR(current->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(current->nhe->nhg, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, current->vrf_id); @@ -1365,7 +1268,7 @@ static void zebra_rib_fixup_system(struct route_node *rn) SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); - for (ALL_NEXTHOPS_PTR(re->ng, nhop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nhop)) { if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1468,13 +1371,13 @@ static bool rib_update_re_from_ctx(struct route_entry *re, /* Get the first `installed` one to check against. * If the dataplane doesn't set these to be what was actually installed, - * it will just be whatever was in re->ng? + * it will just be whatever was in re->nhe->nhg? */ if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_RECURSIVE) || !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE)) ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop); - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -2421,8 +2324,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) nhe = zebra_nhg_lookup_id(re->nhe_id); if (nhe) zebra_nhg_decrement_ref(nhe); - } else if (re->ng) - nexthop_group_delete(&re->ng); + } else if (re->nhe->nhg) + nexthop_group_delete(&re->nhe->nhg); nexthops_free(re->fib_ng.nexthop); @@ -2489,10 +2392,10 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", straddr, re->metric, re->mtu, re->distance, re->flags, re->status); zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, - nexthop_group_nexthop_num(re->ng), - nexthop_group_active_nexthop_num(re->ng)); + nexthop_group_nexthop_num(re->nhe->nhg), + nexthop_group_active_nexthop_num(re->nhe->nhg)); - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { struct interface *ifp; struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); @@ -2641,7 +2544,8 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id) } int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, - struct prefix_ipv6 *src_p, struct route_entry *re) + struct prefix_ipv6 *src_p, struct route_entry *re, + struct nexthop_group *ng) { struct nhg_hash_entry *nhe = NULL; struct route_table *table; @@ -2658,8 +2562,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id, re->table); if (!table) { - if (re->ng) - nexthop_group_delete(&re->ng); + if (ng) + nexthop_group_delete(&ng); XFREE(MTYPE_RE, re); return 0; } @@ -2676,13 +2580,13 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, return -1; } } else { - nhe = zebra_nhg_rib_find(0, re->ng, afi); + nhe = zebra_nhg_rib_find(0, ng, afi); /* * The nexthops got copied over into an nhe, * so free them now. */ - nexthop_group_delete(&re->ng); + nexthop_group_delete(&ng); if (!nhe) { char buf[PREFIX_STRLEN] = ""; @@ -2708,7 +2612,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, * level protocols, as the refcnt might be wrong, since it checks * if old_id != new_id. */ - zebra_nhg_re_update_ref(re, nhe); + route_entry_update_nhe(re, nhe); /* Make it sure prefixlen is applied to the prefix. */ apply_mask(p); @@ -2851,7 +2755,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) continue; - if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = re->ng->nexthop) + if (re->type == ZEBRA_ROUTE_CONNECT && + (rtnh = re->nhe->nhg->nexthop) && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { if (rtnh->ifindex != nh->ifindex) continue; @@ -2869,7 +2774,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, same = re; break; } - for (ALL_NEXTHOPS_PTR(re->ng, rtnh)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, rtnh)) { /* * No guarantee all kernel send nh with labels * on delete. @@ -2911,7 +2816,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (allow_delete) { UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ - for (rtnh = fib->ng->nexthop; rtnh; + for (rtnh = fib->nhe->nhg->nexthop; rtnh; rtnh = rtnh->next) UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); @@ -2967,7 +2872,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; - for (ALL_NEXTHOPS_PTR(re->ng, tmp_nh)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, tmp_nh)) { struct ipaddr vtep_ip; memset(&vtep_ip, 0, sizeof(struct ipaddr)); @@ -3007,6 +2912,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, { struct route_entry *re = NULL; struct nexthop *nexthop = NULL; + struct nexthop_group *ng = NULL; /* Allocate new route_entry structure. */ re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); @@ -3022,16 +2928,19 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, re->tag = tag; re->nhe_id = nhe_id; + /* If the owner of the route supplies a shared nexthop-group id, + * we'll use that. Otherwise, pass the nexthop along directly. + */ if (!nhe_id) { - re->ng = nexthop_group_new(); + ng = nexthop_group_new(); /* Add nexthop. */ nexthop = nexthop_new(); *nexthop = *nh; - route_entry_nexthop_add(re, nexthop); + nexthop_group_add_sorted(ng, nexthop); } - return rib_add_multipath(afi, safi, p, src_p, re); + return rib_add_multipath(afi, safi, p, src_p, re, ng); } static const char *rib_update_event2str(rib_update_event_t event) @@ -3289,7 +3198,7 @@ void rib_sweep_table(struct route_table *table) * this decision needs to be revisited */ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); rib_uninstall_kernel(rn, re); @@ -3639,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_rnh.c b/zebra/zebra_rnh.c index 60e23cc4d4..2d9c83becb 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -384,7 +384,7 @@ static void zebra_rnh_clear_nexthop_rnh_filters(struct route_entry *re) struct nexthop *nexthop; if (re) { - for (nexthop = re->ng->nexthop; nexthop; + for (nexthop = re->nhe->nhg->nexthop; nexthop; nexthop = nexthop->next) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED); } @@ -403,7 +403,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf, route_map_result_t ret; if (prn && re) { - for (nexthop = re->ng->nexthop; nexthop; + for (nexthop = re->nhe->nhg->nexthop; nexthop; nexthop = nexthop->next) { ret = zebra_nht_route_map_check( afi, proto, &prn->p, zvrf, re, nexthop); @@ -688,7 +688,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, /* Just being SELECTED isn't quite enough - must * have an installed nexthop to be useful. */ - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { if (rnh_nexthop_valid(re, nexthop)) break; } @@ -707,7 +707,8 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, break; if (re->type == ZEBRA_ROUTE_NHRP) { - for (nexthop = re->ng->nexthop; nexthop; + for (nexthop = re->nhe->nhg->nexthop; + nexthop; nexthop = nexthop->next) if (nexthop->type == NEXTHOP_TYPE_IFINDEX) @@ -940,7 +941,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, return; /* free RE and nexthops */ - nexthop_group_delete(&re->ng); + zebra_nhg_free(re->nhe); XFREE(MTYPE_RE, re); } @@ -963,9 +964,11 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state->metric = re->metric; state->vrf_id = re->vrf_id; state->status = re->status; - state->ng = nexthop_group_new(); - route_entry_copy_nexthops(state, re->ng->nexthop); + state->nhe = zebra_nhg_alloc(); + state->nhe->nhg = nexthop_group_new(); + + nexthop_group_copy(state->nhe->nhg, re->nhe->nhg); rnh->state = state; } @@ -983,11 +986,12 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) if (r1->metric != r2->metric) return 1; - if (nexthop_group_nexthop_num(r1->ng) - != nexthop_group_nexthop_num(r2->ng)) + if (nexthop_group_nexthop_num(r1->nhe->nhg) + != nexthop_group_nexthop_num(r2->nhe->nhg)) return 1; - if (nexthop_group_hash(r1->ng) != nexthop_group_hash(r2->ng)) + if (nexthop_group_hash(r1->nhe->nhg) != + nexthop_group_hash(r2->nhe->nhg)) return 1; return 0; @@ -1030,6 +1034,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, break; } if (re) { + struct zapi_nexthop znh; + stream_putc(s, re->type); stream_putw(s, re->instance); stream_putc(s, re->distance); @@ -1037,39 +1043,10 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, num = 0; nump = stream_get_endp(s); stream_putc(s, 0); - for (ALL_NEXTHOPS_PTR(re->ng, nh)) + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nh)) if (rnh_nexthop_valid(re, nh)) { - stream_putl(s, nh->vrf_id); - stream_putc(s, nh->type); - switch (nh->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - stream_put_in_addr(s, &nh->gate.ipv4); - stream_putl(s, nh->ifindex); - break; - case NEXTHOP_TYPE_IFINDEX: - stream_putl(s, nh->ifindex); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - stream_put(s, &nh->gate.ipv6, 16); - stream_putl(s, nh->ifindex); - break; - default: - /* do nothing */ - break; - } - if (nh->nh_label) { - stream_putc(s, - nh->nh_label->num_labels); - if (nh->nh_label->num_labels) - stream_put( - s, - &nh->nh_label->label[0], - nh->nh_label->num_labels - * sizeof(mpls_label_t)); - } else - stream_putc(s, 0); + zapi_nexthop_from_nexthop(&znh, nh); + zapi_nexthop_encode(s, &znh, 0 /* flags */); num++; } stream_putc_at(s, nump, num); @@ -1137,7 +1114,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) if (rnh->state) { vty_out(vty, " resolved via %s\n", zebra_route_string(rnh->state->type)); - for (nexthop = rnh->state->ng->nexthop; nexthop; + for (nexthop = rnh->state->nhe->nhg->nexthop; nexthop; nexthop = nexthop->next) print_nh(nexthop, vty); } else 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.c b/zebra/zebra_router.c index e5319c64af..a891ffb76a 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -29,7 +29,7 @@ #include "zebra_pbr.h" #include "zebra_vxlan.h" #include "zebra_mlag.h" -#include "zebra_nhg_private.h" +#include "zebra_nhg.h" #include "debug.h" DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info") @@ -223,7 +223,7 @@ void zebra_router_terminate(void) zebra_vxlan_disable(); zebra_mlag_terminate(); - hash_clean(zrouter.nhgs, zebra_nhg_free); + hash_clean(zrouter.nhgs, zebra_nhg_hash_free); hash_free(zrouter.nhgs); hash_clean(zrouter.nhgs_id, NULL); hash_free(zrouter.nhgs_id); @@ -245,6 +245,8 @@ void zebra_router_init(void) zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; + zrouter.rtadv_sock = -1; + zebra_vxlan_init(); zebra_mlag_init(); 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_snmp.c b/zebra/zebra_snmp.c index 56c7664328..4c52651981 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -285,8 +285,8 @@ static void check_replace(struct route_node *np2, struct route_entry *re2, return; } - if (in_addr_cmp((uint8_t *)&(*re)->ng->nexthop->gate.ipv4, - (uint8_t *)&re2->ng->nexthop->gate.ipv4) + if (in_addr_cmp((uint8_t *)&(*re)->nhe->nhg->nexthop->gate.ipv4, + (uint8_t *)&re2->nhe->nhg->nexthop->gate.ipv4) <= 0) return; @@ -371,9 +371,9 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], if (!in_addr_cmp(&(*np)->p.u.prefix, (uint8_t *)&dest)) { RNODE_FOREACH_RE (*np, *re) { - if (!in_addr_cmp((uint8_t *)&(*re) - ->ng->nexthop - ->gate.ipv4, + if (!in_addr_cmp((uint8_t *)&(*re)->nhe + ->nhg->nexthop + ->gate.ipv4, (uint8_t *)&nexthop)) if (proto == proto_trans((*re)->type)) @@ -406,8 +406,8 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], || ((policy == policy2) && (proto < proto2)) || ((policy == policy2) && (proto == proto2) && (in_addr_cmp( - (uint8_t *)&re2->ng->nexthop - ->gate.ipv4, + (uint8_t *)&re2->nhe + ->nhg->nexthop->gate.ipv4, (uint8_t *)&nexthop) >= 0))) check_replace(np2, re2, np, re); @@ -432,7 +432,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], { struct nexthop *nexthop; - nexthop = (*re)->ng->nexthop; + nexthop = (*re)->nhe->nhg->nexthop; if (nexthop) { pnt = (uint8_t *)&nexthop->gate.ipv4; for (i = 0; i < 4; i++) @@ -462,7 +462,7 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len, if (!np) return NULL; - nexthop = re->ng->nexthop; + nexthop = re->nhe->nhg->nexthop; if (!nexthop) return NULL; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 12517f3135..eca86d5fe2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -263,7 +263,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, if (show_ng) vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); - for (ALL_NEXTHOPS_PTR(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { char addrstr[32]; vty_out(vty, " %c%s", @@ -413,7 +413,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (is_fib) nhg = rib_active_nhg(re); else - nhg = re->ng; + nhg = re->nhe->nhg; if (json) { json_route = json_object_new_object(); @@ -466,9 +466,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_int_add(json_route, "internalFlags", re->flags); json_object_int_add(json_route, "internalNextHopNum", - nexthop_group_nexthop_num(re->ng)); + nexthop_group_nexthop_num(re->nhe->nhg)); json_object_int_add(json_route, "internalNextHopActiveNum", - nexthop_group_active_nexthop_num(re->ng)); + nexthop_group_active_nexthop_num( + re->nhe->nhg)); if (uptime < ONE_DAY_SECOND) sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -1833,7 +1834,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, fib_cnt[ZEBRA_ROUTE_TOTAL]++; fib_cnt[re->type]++; } - for (nexthop = re->ng->nexthop; (!cnt && nexthop); + for (nexthop = re->nhe->nhg->nexthop; (!cnt && nexthop); nexthop = nexthop->next) { cnt++; rib_cnt[ZEBRA_ROUTE_TOTAL]++; @@ -2227,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 1d2748c8ef..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); @@ -4615,18 +4683,21 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, { char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; + char buf2[PREFIX_STRLEN]; zebra_mac_t *zrmac = NULL; zrmac = zl3vni_rmac_lookup(zl3vni, rmac); if (!zrmac) { + /* Create the RMAC entry, or update its vtep, if necessary. */ zrmac = zl3vni_rmac_add(zl3vni, rmac); if (!zrmac) { zlog_debug( - "Failed to add RMAC %s L3VNI %u Remote VTEP %s", + "Failed to add RMAC %s L3VNI %u Remote VTEP %s, prefix %s", prefix_mac2str(rmac, buf, sizeof(buf)), zl3vni->vni, - ipaddr2str(vtep_ip, buf1, sizeof(buf1))); + ipaddr2str(vtep_ip, buf1, sizeof(buf1)), + prefix2str(host_prefix, buf2, sizeof(buf2))); return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); @@ -4638,6 +4709,21 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); + } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, + &vtep_ip->ipaddr_v4)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "L3VNI %u Remote VTEP change(%s -> %s) for RMAC %s, prefix %s", + zl3vni->vni, + inet_ntoa(zrmac->fwd_info.r_vtep_ip), + ipaddr2str(vtep_ip, buf1, sizeof(buf1)), + prefix_mac2str(rmac, buf, sizeof(buf)), + prefix2str(host_prefix, buf2, sizeof(buf2))); + + zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + + /* install rmac in kernel */ + zl3vni_rmac_install(zl3vni, zrmac); } rb_find_or_add_host(&zrmac->host_rb, host_prefix); @@ -4786,24 +4872,39 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, struct prefix *host_prefix) { char buf[ETHER_ADDR_STRLEN]; - char buf1[INET6_ADDRSTRLEN]; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + char buf3[PREFIX_STRLEN]; zebra_neigh_t *nh = NULL; + /* Create the next hop entry, or update its mac, if necessary. */ nh = zl3vni_nh_lookup(zl3vni, vtep_ip); if (!nh) { nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac); if (!nh) { - zlog_debug( - "Failed to add NH as Neigh (IP %s MAC %s L3-VNI %u)", - ipaddr2str(vtep_ip, buf1, sizeof(buf1)), + "Failed to add NH %s as Neigh (RMAC %s L3-VNI %u prefix %s)", + ipaddr2str(vtep_ip, buf1, sizeof(buf2)), prefix_mac2str(rmac, buf, sizeof(buf)), - zl3vni->vni); + zl3vni->vni, + prefix2str(host_prefix, buf2, sizeof(buf2))); return -1; } /* install the nh neigh in kernel */ zl3vni_nh_install(zl3vni, nh); + } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("L3VNI %u RMAC change(%s --> %s) for nexthop %s, prefix %s", + zl3vni->vni, + prefix_mac2str(&nh->emac, buf, sizeof(buf)), + prefix_mac2str(rmac, buf1, sizeof(buf1)), + ipaddr2str(vtep_ip, buf2, sizeof(buf2)), + prefix2str(host_prefix, buf3, sizeof(buf3))); + + memcpy(&nh->emac, rmac, ETH_ALEN); + /* install (update) the nh neigh in kernel */ + zl3vni_nh_install(zl3vni, nh); } rb_find_or_add_host(&nh->host_rb, host_prefix); @@ -5023,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; @@ -5106,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. */ @@ -5113,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" @@ -7136,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]; @@ -7150,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; @@ -7158,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); + } } } @@ -7329,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; @@ -7340,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( @@ -7363,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); } } @@ -8419,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) @@ -8498,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); @@ -8669,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( @@ -8828,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 { @@ -8960,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; |
