From 34687162ce39d4c34bf60bc55ea13b597b04c2ac Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 29 Mar 2017 23:02:41 -0400 Subject: [PATCH 01/34] pimd: Convert pim address family from #define -> enum Convert the pim address family from a #define into an enum. Signed-off-by: Donald Sharp --- pimd/pim_msg.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index de663aa3b5..e5676289b7 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -34,7 +34,11 @@ From: http://www.iana.org/assignments/address-family-numbers */ -#define PIM_MSG_ADDRESS_FAMILY_IPV4 (1) +enum pim_msg_address_family { + PIM_MSG_ADDRESS_FAMILY_RESERVED, + PIM_MSG_ADDRESS_FAMILY_IPV4, + PIM_MSG_ADDRESS_FAMILY_IPV6, +}; /* * Network Order pim_msg_hdr From 71bbe73dc4fb308b1abca5a326c6c59e1193d794 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 29 Mar 2017 23:23:25 -0400 Subject: [PATCH 02/34] pimd: Add code to allow backwards compatibility This code change adds the ability to specify that we should be able to work with older versions of PIM. In future commits we will actually use this data. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 27 +++++++++++++++++++++++++++ pimd/pim_vty.c | 6 ++++++ pimd/pimd.c | 2 ++ pimd/pimd.h | 2 ++ 4 files changed, 37 insertions(+) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index cf101b3e24..66fc8185d0 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3509,6 +3509,31 @@ DEFUN (no_ip_pim_packets, return CMD_SUCCESS; } +DEFUN (ip_pim_v6_secondary, + ip_pim_v6_secondary_cmd, + "ip pim send-v6-secondary", + IP_STR + "pim multicast routing\n" + "Send v6 secondary addresses\n") +{ + pimg->send_v6_secondary = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_v6_secondary, + no_ip_pim_v6_secondary_cmd, + "no ip pim send-v6-secondary", + NO_STR + IP_STR + "pim multicast routing\n" + "Send v6 secondary addresses\n") +{ + pimg->send_v6_secondary = 0; + + return CMD_SUCCESS; +} + DEFUN (ip_pim_rp, ip_pim_rp_cmd, "ip pim rp A.B.C.D [A.B.C.D/M]", @@ -6037,6 +6062,8 @@ void pim_cmd_init() install_element (CONFIG_NODE, &no_ip_pim_keep_alive_cmd); install_element (CONFIG_NODE, &ip_pim_packets_cmd); install_element (CONFIG_NODE, &no_ip_pim_packets_cmd); + install_element (CONFIG_NODE, &ip_pim_v6_secondary_cmd); + install_element (CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); install_element (CONFIG_NODE, &ip_ssmpingd_cmd); install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); install_element (CONFIG_NODE, &ip_msdp_peer_cmd); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 5b6a79b95a..9788c58cd9 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -148,6 +148,12 @@ int pim_global_config_write(struct vty *vty) writes += pim_msdp_config_write (vty); + if (!pimg->send_v6_secondary) + { + vty_out (vty, "no ip pim send-v6-secondary%s", VTY_NEWLINE); + ++writes; + } + writes += pim_rp_config_write (vty); if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) diff --git a/pimd/pimd.c b/pimd/pimd.c index b67544b28e..9058e14b0a 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -109,6 +109,8 @@ pim_vrf_enable (struct vrf *vrf) if (pimg == NULL) zlog_err ("%s %s: pim class init failure ", __FILE__, __PRETTY_FUNCTION__); + + pimg->send_v6_secondary = 1; } return 0; } diff --git a/pimd/pimd.h b/pimd/pimd.h index b3bdd9e243..8dc5899022 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -240,6 +240,8 @@ struct pim_instance afi_t afi; vrf_id_t vrf_id; struct hash *rpf_hash; + + int send_v6_secondary; }; extern struct pim_instance *pimg; //Pim Global Instance From 7399328a6fbd9e41e03cc8d0c9bfbf16a5738c9a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 29 Mar 2017 23:27:25 -0400 Subject: [PATCH 03/34] pimd: Fix RP determination to handle secondary addresses better When we are checking RP addresses and looking at the secondary address. With the addition of the ability to handle v6 addresses in the secondary list. Assuming that the secondary address is a v4 address is a no go. Convert to prefix_same. Signed-off-by: Donald Sharp --- pimd/pim_rp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 6c83811d9a..8afc87956d 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -261,7 +261,7 @@ pim_rp_check_interface_addrs(struct rp_info *rp_info, } for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) { - if (sec_addr->addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) { + if (prefix_same(&sec_addr->addr, &rp_info->rp.rpf_addr)) { return 1; } } From 07b17d5927499beaf42665bb7bd2bcaea0b1e9d6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 29 Mar 2017 23:44:12 -0400 Subject: [PATCH 04/34] pimd: Add code to find neighbor by secondary With RFC 5549 we need a methodology to find a neighbor based upon a nexthop that is v6 based. This commit sets us up for that by allowing you to find the neigbor by the secondary list. In a future commit we will add code to pass the v6 secondary addresses. Signed-off-by: Donald Sharp --- pimd/pim_iface.c | 7 ++++++- pimd/pim_neighbor.c | 38 ++++++++++++++++++++++++++++++-------- pimd/pim_neighbor.h | 5 +++-- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 0864796431..a753cc4aff 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1105,6 +1105,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, struct listnode *neighnode; struct pim_neighbor *neigh; struct pim_interface *pim_ifp; + struct prefix p; zassert(ifp); @@ -1116,6 +1117,10 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return 0; } + p.family = AF_INET; + p.u.prefix4 = addr; + p.prefixlen = IPV4_MAX_PREFIXLEN; + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { /* primary address ? */ @@ -1123,7 +1128,7 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, return neigh; /* secondary address ? */ - if (pim_neighbor_find_secondary(neigh, addr)) + if (pim_neighbor_find_secondary(neigh, &p)) return neigh; } diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index c1325df260..133d4edb21 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -423,6 +423,31 @@ void pim_neighbor_free(struct pim_neighbor *neigh) XFREE(MTYPE_PIM_NEIGHBOR, neigh); } +struct pim_neighbor * +pim_neighbor_find_by_secondary (struct interface *ifp, + struct prefix *src) +{ + struct pim_interface *pim_ifp; + struct listnode *node, *pnode; + struct pim_neighbor *neigh; + struct prefix *p; + + pim_ifp = ifp->info; + if (!pim_ifp) + return NULL; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) + { + for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, pnode, p)) + { + if (prefix_same (p, src)) + return neigh; + } + } + + return NULL; +} + struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct in_addr source_addr) { @@ -669,7 +694,7 @@ void pim_neighbor_delete_all(struct interface *ifp, } struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, - struct in_addr addr) + struct prefix *addr) { struct listnode *node; struct prefix *p; @@ -678,14 +703,11 @@ struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, return 0; for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) { - if (p->family == AF_INET) { - if (addr.s_addr == p->u.prefix4.s_addr) { - return p; - } - } + if (prefix_same (p, addr)) + return p; } - return 0; + return NULL; } /* @@ -729,7 +751,7 @@ static void delete_from_neigh_addr(struct interface *ifp, for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { { - struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4); + struct prefix *p = pim_neighbor_find_secondary(neigh, addr); if (p) { char addr_str[INET_ADDRSTRLEN]; char this_neigh_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index 986721666e..e27920fdd8 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -50,7 +50,8 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct in_addr source_addr); - +struct pim_neighbor *pim_neighbor_find_by_secondary (struct interface *ifp, + struct prefix *src); struct pim_neighbor *pim_neighbor_find_if (struct interface *ifp); @@ -77,7 +78,7 @@ void pim_neighbor_update(struct pim_neighbor *neigh, uint32_t dr_priority, struct list *addr_list); struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, - struct in_addr addr); + struct prefix *addr); int pim_if_dr_election(struct interface *ifp); #endif /* PIM_NEIGHBOR_H */ From 0f4b1d2d95e4f9bdb1412b5792941289332a7cc6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 30 Mar 2017 00:07:18 -0400 Subject: [PATCH 05/34] pimd: Add ability to encode/decode v6 secondary addresses Add ability to encode/decode the v6 secondary addresses if they are passed to us. This also fixes the issue where if we are passed a v6 secondary address list we will not refuse to form neighbors. Signed-off-by: Donald Sharp --- pimd/pim_hello.c | 3 ++- pimd/pim_tlv.c | 53 +++++++++++++++++++++++++++++++++++++++--------- pimd/pim_tlv.h | 3 ++- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 3d7ae4ad22..d9b04ea952 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -507,7 +507,8 @@ int pim_hello_build_tlv(const char *ifname, if (ifconnected) { curr = pim_tlv_append_addrlist_ucast(curr, pastend, - ifconnected); + ifconnected, + AF_INET); if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s", diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 5223f60e1b..1d58ce3ac6 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -94,6 +94,7 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, } #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) +#define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr)) /* * An Encoded-Unicast address takes the following format: @@ -135,6 +136,14 @@ pim_encode_addr_ucast (uint8_t *buf, struct prefix *p) memcpy (buf, &p->u.prefix4, sizeof (struct in_addr)); return ucast_ipv4_encoding_len; break; + case AF_INET6: + *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6; + ++buf; + *(uint8_t *)buf = 0; + ++buf; + memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr)); + return ucast_ipv6_encoding_len; + break; default: return 0; break; @@ -216,12 +225,13 @@ pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, - struct list *ifconnected) + struct list *ifconnected, + int family) { struct listnode *node; uint16_t option_len = 0; - uint8_t *curr; + size_t uel; node = listhead(ifconnected); @@ -230,8 +240,10 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, return buf; } - /* Skip first address (primary) */ - node = listnextnode(node); + if (family == AF_INET) + uel = ucast_ipv4_encoding_len; + else + uel = ucast_ipv6_encoding_len; /* Scan secondary address list */ curr = buf + 4; /* skip T and L */ @@ -240,8 +252,14 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, struct prefix *p = ifc->address; int l_encode; - if ((curr + ucast_ipv4_encoding_len) > buf_pastend) - return 0; + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) + continue; + + if ((curr + uel) > buf_pastend) + return 0; + + if (p->family != family) + continue; l_encode = pim_encode_addr_ucast (curr, p); curr += l_encode; @@ -251,7 +269,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, if (PIM_DEBUG_PIM_TRACE_DETAIL) { zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", __PRETTY_FUNCTION__, - option_len / ucast_ipv4_encoding_len); + option_len / uel); } if (option_len < 1) { @@ -491,9 +509,23 @@ pim_parse_addr_ucast (struct prefix *p, p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); - + p->prefixlen = IPV4_MAX_PREFIXLEN; addr += sizeof(struct in_addr); + break; + case PIM_MSG_ADDRESS_FAMILY_IPV6: + if ((addr + sizeof(struct in6_addr)) > pastend) { + zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu", + __PRETTY_FUNCTION__, + pastend - addr, sizeof(struct in6_addr)); + return -3; + } + + p->family = AF_INET6; + p->prefixlen = IPV6_MAX_PREFIXLEN; + memcpy(&p->u.prefix6, addr, 16); + addr += sizeof(struct in6_addr); + break; default: { @@ -706,6 +738,8 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, addr_str, src_str, ifname); } break; + case AF_INET6: + break; default: { char src_str[INET_ADDRSTRLEN]; @@ -759,8 +793,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, FREE_ADDR_LIST(*hello_option_addr_list); return -3; } - p->family = tmp.family; - p->u.prefix4 = tmp.u.prefix4; + prefix_copy(p, &tmp); listnode_add(*hello_option_addr_list, p); } diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index 9c4ebc9f0f..7e0a8a147f 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -80,7 +80,8 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf, uint32_t option_value); uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, - struct list *ifconnected); + struct list *ifconnected, + int family); int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, From dba7860904ec03bf3c856efee1fae9fc06821121 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 30 Mar 2017 09:01:09 -0400 Subject: [PATCH 06/34] pimd: Send v6 secondary addresses to neighbors in hello Send v6 secondary addresses to our neighbor in hello's. Additionally allow the disabling it via the cli introduced earlier. Signed-off-by: Donald Sharp --- pimd/pim_hello.c | 35 ++++++++++++++++++++++++----------- pimd/pim_hello.h | 5 ++--- pimd/pim_pim.c | 5 ++--- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index d9b04ea952..ee9433d797 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -428,15 +428,14 @@ int pim_hello_recv(struct interface *ifp, return 0; } -int pim_hello_build_tlv(const char *ifname, +int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, - int can_disable_join_suppression, - struct list *ifconnected) + int can_disable_join_suppression) { uint8_t *curr = tlv_buf; uint8_t *pastend = tlv_buf + tlv_buf_size; @@ -454,7 +453,7 @@ int pim_hello_build_tlv(const char *ifname, if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Holdtime option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -1; } @@ -468,7 +467,7 @@ int pim_hello_build_tlv(const char *ifname, if (!tmp) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM LAN Prune Delay option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -1; } @@ -485,7 +484,7 @@ int pim_hello_build_tlv(const char *ifname, if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello DR Priority option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -2; } @@ -498,24 +497,38 @@ int pim_hello_build_tlv(const char *ifname, if (!curr) { if (PIM_DEBUG_PIM_HELLO) { zlog_debug("%s: could not set PIM hello Generation ID option for interface %s", - __PRETTY_FUNCTION__, ifname); + __PRETTY_FUNCTION__, ifp->name); } return -3; } /* Secondary Address List */ - if (ifconnected) { + if (ifp->connected->count) { curr = pim_tlv_append_addrlist_ucast(curr, pastend, - ifconnected, + ifp->connected, AF_INET); if (!curr) { if (PIM_DEBUG_PIM_HELLO) { - zlog_debug("%s: could not set PIM hello Secondary Address List option for interface %s", - __PRETTY_FUNCTION__, ifname); + zlog_debug("%s: could not set PIM hello v4 Secondary Address List option for interface %s", + __PRETTY_FUNCTION__, ifp->name); } return -4; } + if (pimg->send_v6_secondary) + { + curr = pim_tlv_append_addrlist_ucast(curr, + pastend, + ifp->connected, + AF_INET6); + if (!curr) { + if (PIM_DEBUG_PIM_HELLO) { + zlog_debug("%s: could not sent PIM hello v6 secondary Address List option for interface %s", + __PRETTY_FUNCTION__, ifp->name); + } + return -4; + } + } } return curr - tlv_buf; diff --git a/pimd/pim_hello.h b/pimd/pim_hello.h index 3a6d3361ba..de5359e2c0 100644 --- a/pimd/pim_hello.h +++ b/pimd/pim_hello.h @@ -29,15 +29,14 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); -int pim_hello_build_tlv(const char *ifname, +int pim_hello_build_tlv(struct interface *ifname, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, - int can_disable_join_suppression, - struct list *ifconnected); + int can_disable_join_suppression); void pim_hello_require(struct interface *ifp); diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index f82687245d..bc13e10a61 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -629,7 +629,7 @@ static int hello_send(struct interface *ifp, listcount(ifp->connected)); } - pim_tlv_size = pim_hello_build_tlv(ifp->name, + pim_tlv_size = pim_hello_build_tlv(ifp, pim_msg + PIM_PIM_MIN_LEN, sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime, @@ -637,8 +637,7 @@ static int hello_send(struct interface *ifp, pim_ifp->pim_generation_id, pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, - PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), - ifp->connected); + PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)); if (pim_tlv_size < 0) { return -1; } From eeff6d3f99c8965bbb4870d9ca0f8da5f6a53e57 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 30 Mar 2017 09:07:06 -0400 Subject: [PATCH 07/34] pimd: Use better 5549 resolution When we receive a v6 nexthop in v4, lookup the nbr by it's secondary address. Signed-off-by: Donald Sharp --- pimd/pim_zlookup.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index f77990ab5a..620137b33b 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -222,6 +222,7 @@ static int zclient_read_nexthop(struct zclient *zlookup, for (i = 0; i < nexthop_num; ++i) { enum nexthop_types_t nexthop_type; struct pim_neighbor *nbr; + struct prefix p; nexthop_type = stream_getc(s); if (num_ifindex >= tab_size) { @@ -253,7 +254,18 @@ static int zclient_read_nexthop(struct zclient *zlookup, nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6; stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16); nexthop_tab[num_ifindex].ifindex = stream_getl (s); - nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT)); + + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_PREFIXLEN; + memcpy (&p.u.prefix6, &nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, 16); + + /* + * If we are sending v6 secondary assume we receive v6 secondary + */ + if (pimg->send_v6_secondary) + nbr = pim_neighbor_find_by_secondary(if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT), &p); + else + nbr = pim_neighbor_find_if (if_lookup_by_index (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT)); if (nbr) { nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET; From 294b6d7243983270d69c85aaa8528c78a2521da5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 30 Mar 2017 09:10:05 -0400 Subject: [PATCH 08/34] pimd: Receive incoming v6 addresses and place in pim_ifp list Add code to properly receive v6 addresses up from zebra and to properly place them into our interface secondary address list. Additionally cleanup some code in pim_cmd.c that was broken by these changes. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 17 +++++++------- pimd/pim_iface.c | 60 ++++++++++++++++++++++++++++++------------------ pimd/pim_iface.h | 2 +- pimd/pim_zebra.c | 22 +----------------- 4 files changed, 48 insertions(+), 53 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 66fc8185d0..91d870fb1e 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -816,6 +816,7 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); if (uj) { + char pbuf[PREFIX2STR_BUFFER]; json_row = json_object_new_object(); json_object_pim_ifp_add(json_row, ifp); @@ -827,7 +828,8 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch sec_list = json_object_new_array(); for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) { - json_object_array_add(sec_list, json_object_new_string(inet_ntoa(sec_addr->addr))); + json_object_array_add(sec_list, + json_object_new_string(prefix2str(&sec_addr->addr, pbuf, PREFIX2STR_BUFFER))); } json_object_object_add(json_row, "secondaryAddressList", sec_list); } @@ -918,11 +920,12 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE); } if (pim_ifp->sec_addr_list) { + char pbuf[PREFIX2STR_BUFFER]; vty_out(vty, "Address : %s (primary)%s", - inet_ntoa(ifaddr), VTY_NEWLINE); + inet_ntoa(ifaddr), VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) { vty_out(vty, " %s%s", - inet_ntoa(sec_addr->addr), VTY_NEWLINE); + prefix2str(&sec_addr->addr, pbuf, PREFIX2STR_BUFFER), VTY_NEWLINE); } } else { vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE); @@ -1607,13 +1610,9 @@ static void pim_show_neighbors_secondary(struct vty *vty) neigh_src_str, sizeof(neigh_src_str)); for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) { - char neigh_sec_str[INET_ADDRSTRLEN]; + char neigh_sec_str[100]; - if (p->family != AF_INET) - continue; - - pim_inet4_dump("", p->u.prefix4, - neigh_sec_str, sizeof(neigh_sec_str)); + prefix2str(p, neigh_sec_str, 100); vty_out(vty, "%-9s %-15s %-15s %-15s%s", ifp->name, diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index a753cc4aff..f038acab8f 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -324,12 +324,29 @@ static int pim_sec_addr_comp(const void *p1, const void *p2) const struct pim_secondary_addr *sec1 = p1; const struct pim_secondary_addr *sec2 = p2; - if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr)) + if (sec1->addr.family == AF_INET && + sec2->addr.family == AF_INET6) return -1; - if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr)) + if (sec1->addr.family == AF_INET6 && + sec2->addr.family == AF_INET) return 1; + if (sec1->addr.family == AF_INET) + { + if (ntohl(sec1->addr.u.prefix4.s_addr) < ntohl(sec2->addr.u.prefix4.s_addr)) + return -1; + + if (ntohl(sec1->addr.u.prefix4.s_addr) > ntohl(sec2->addr.u.prefix4.s_addr)) + return 1; + } + else + { + return memcmp (&sec1->addr.u.prefix6, + &sec2->addr.u.prefix6, + sizeof (struct in6_addr)); + } + return 0; } @@ -339,7 +356,7 @@ static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr) } static struct pim_secondary_addr * -pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr) +pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr) { struct pim_secondary_addr *sec_addr; struct listnode *node; @@ -349,7 +366,7 @@ pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr) } for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) { - if (sec_addr->addr.s_addr == addr.s_addr) { + if (prefix_cmp(&sec_addr->addr, addr)) { return sec_addr; } } @@ -364,7 +381,7 @@ static void pim_sec_addr_del(struct pim_interface *pim_ifp, pim_sec_addr_free(sec_addr); } -static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr) +static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr) { int changed = 0; struct pim_secondary_addr *sec_addr; @@ -391,7 +408,7 @@ static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr) } changed = 1; - sec_addr->addr = addr; + sec_addr->addr = *addr; listnode_add_sort(pim_ifp->sec_addr_list, sec_addr); return changed; @@ -433,10 +450,6 @@ static int pim_sec_addr_update(struct interface *ifp) for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { struct prefix *p = ifc->address; - if (p->family != AF_INET) { - continue; - } - if (PIM_INADDR_IS_ANY(p->u.prefix4)) { continue; } @@ -446,7 +459,7 @@ static int pim_sec_addr_update(struct interface *ifp) continue; } - if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) { + if (pim_sec_addr_add(pim_ifp, p)) { changed = 1; } } @@ -571,12 +584,15 @@ void pim_if_addr_add(struct connected *ifc) detect_address_change(ifp, 0, __PRETTY_FUNCTION__); + if (ifc->address->family != AF_INET) + return; + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, - ifaddr); + ifaddr); if (!igmp) { /* if addr new, add IGMP socket */ pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp); @@ -675,14 +691,17 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) ifp = ifc->ifp; zassert(ifp); + if (ifc->address->family != AF_INET) + return; + if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s", - __PRETTY_FUNCTION__, - ifp->name, ifp->ifindex, buf, - CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? - "secondary" : "primary"); + __PRETTY_FUNCTION__, + ifp->name, ifp->ifindex, buf, + CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? + "secondary" : "primary"); } detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__); @@ -709,12 +728,9 @@ void pim_if_addr_add_all(struct interface *ifp) struct prefix *p = ifc->address; if (p->family != AF_INET) - { - v6_addrs++; - continue; - } - - v4_addrs++; + v6_addrs++; + else + v4_addrs++; pim_if_addr_add(ifc); } diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 8d332c70b0..f4d7518d7a 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -69,7 +69,7 @@ enum pim_secondary_addr_flags { }; struct pim_secondary_addr { - struct in_addr addr; + struct prefix addr; enum pim_secondary_addr_flags flags; }; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index d02560bfc2..bbee95bddd 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -257,31 +257,11 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, #endif } - if (p->family != AF_INET) - { - struct listnode *cnode; - struct connected *conn; - int v4addrs = 0; - - for (ALL_LIST_ELEMENTS_RO (c->ifp->connected, cnode, conn)) - { - if (conn->address->family == AF_INET) - v4addrs++; - } - if (!v4addrs && pim_ifp) - { - pim_ifp->primary_address = pim_find_primary_addr (c->ifp); - pim_if_addr_add_all (c->ifp); - pim_if_add_vif (c->ifp); - } - return 0; - } - if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { /* trying to add primary address */ struct in_addr primary_addr = pim_find_primary_addr(c->ifp); - if (primary_addr.s_addr != p->u.prefix4.s_addr) { + if (p->family != AF_INET || primary_addr.s_addr != p->u.prefix4.s_addr) { if (PIM_DEBUG_ZEBRA) { /* but we had a primary address already */ From 2e725ad140e14ed03195028881be65c2cefc079a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 30 Mar 2017 10:22:00 -0400 Subject: [PATCH 09/34] pimd: Fix header to be more descriptive of what it is doing Signed-off-by: Donald Sharp --- pimd/pim_hello.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pimd/pim_hello.h b/pimd/pim_hello.h index de5359e2c0..1f8b348bd7 100644 --- a/pimd/pim_hello.h +++ b/pimd/pim_hello.h @@ -29,7 +29,7 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); -int pim_hello_build_tlv(struct interface *ifname, +int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, From 508f9997f271c066b0ffc4fe0d5861ef20430317 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sun, 2 Apr 2017 13:55:58 -0400 Subject: [PATCH 10/34] bgp: fix a couple of instances of bm being used before init'ed Signed-off-by: Lou Berger --- bgpd/bgp_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 423c9453eb..55bf410628 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -363,6 +363,7 @@ main (int argc, char **argv) int bgp_port = BGP_PORT_DEFAULT; char *bgp_address = NULL; + int no_fib_flag = 0; frr_preinit(&bgpd_di, argc, argv); frr_opt_add("p:l:rne:", longopts, @@ -389,7 +390,7 @@ main (int argc, char **argv) if (tmp_port <= 0 || tmp_port > 0xffff) bgp_port = BGP_PORT_DEFAULT; else - bm->port = tmp_port; + bgp_port = tmp_port; break; case 'e': multipath_num = atoi (optarg); @@ -406,7 +407,7 @@ main (int argc, char **argv) bgp_address = optarg; /* listenon implies -n */ case 'n': - bgp_option_set (BGP_OPT_NO_FIB); + no_fib_flag = 1; break; default: frr_help_exit (1); @@ -418,6 +419,8 @@ main (int argc, char **argv) bgp_master_init (frr_init ()); bm->port = bgp_port; bm->address = bgp_address; + if (no_fib_flag) + bgp_option_set (BGP_OPT_NO_FIB); /* Initializations. */ bgp_vrf_init (); From c888ea16473ea3b0c69f59d62030d7c678b64b63 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sun, 2 Apr 2017 13:57:10 -0400 Subject: [PATCH 11/34] lib/frr: fix reference to zsuid before it is set Signed-off-by: Lou Berger --- lib/privs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/privs.c b/lib/privs.c index 376d6f3365..87ad074f1b 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -769,6 +769,7 @@ zprivs_init(struct zebra_privs_t *zprivs) } } + zprivs_state.zsuid = geteuid(); /* initial uid */ /* add groups only if we changed uid - otherwise skip */ if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid)) { From 3135834e1f8c4b3a13d2cd43f30e30313980112e Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sun, 2 Apr 2017 15:34:55 -0400 Subject: [PATCH 12/34] bgpd: restore -S, --skip_runas options Signed-off-by: Lou Berger --- bgpd/bgp_main.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 55bf410628..1773070fe3 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -66,6 +66,7 @@ static const struct option longopts[] = { "listenon", required_argument, NULL, 'l'}, { "retain", no_argument, NULL, 'r'}, { "no_kernel", no_argument, NULL, 'n'}, + { "skip_runas", no_argument, NULL, 'S'}, { "ecmp", required_argument, NULL, 'e'}, { 0 } }; @@ -151,7 +152,8 @@ sigint (void) if (! retain_mode) { bgp_terminate (); - zprivs_terminate (&bgpd_privs); + if (bgpd_privs.user) /* NULL if skip_runas flag set */ + zprivs_terminate (&bgpd_privs); } bgp_exit (0); @@ -364,6 +366,7 @@ main (int argc, char **argv) int bgp_port = BGP_PORT_DEFAULT; char *bgp_address = NULL; int no_fib_flag = 0; + int skip_runas = 0; frr_preinit(&bgpd_di, argc, argv); frr_opt_add("p:l:rne:", longopts, @@ -371,6 +374,7 @@ main (int argc, char **argv) " -l, --listenon Listen on specified address (implies -n)\n" " -r, --retain When program terminates, retain added route by bgpd.\n" " -n, --no_kernel Do not install route to kernel.\n" + " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n" " -e, --ecmp Specify ECMP to use.\n"); /* Command line argument treatment. */ @@ -409,11 +413,16 @@ main (int argc, char **argv) case 'n': no_fib_flag = 1; break; + case 'S': + skip_runas = 1; + break; default: frr_help_exit (1); break; } } + if (skip_runas) + memset (&bgpd_privs, 0, sizeof (bgpd_privs)); /* BGP master init. */ bgp_master_init (frr_init ()); From 52884837196a26d75150b55a88d768b3a27eab8b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 4 Apr 2017 20:18:24 -0400 Subject: [PATCH 13/34] *: Clean up some wrong references Signed-off-by: Donald Sharp --- README | 10 +++++----- bgpd/bgp_attr_evpn.c | 8 ++++---- bgpd/bgp_attr_evpn.h | 8 ++++---- bgpd/bgp_evpn.c | 8 ++++---- bgpd/bgp_evpn.h | 8 ++++---- bgpd/bgp_evpn_vty.c | 8 ++++---- bgpd/bgp_evpn_vty.h | 8 ++++---- bgpd/bgp_vpn.c | 8 ++++---- bgpd/bgp_vpn.h | 8 ++++---- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/README b/README index a0aa895367..7c6ef7034e 100644 --- a/README +++ b/README @@ -1,13 +1,13 @@ -Free Range Routing is free software that manages various IPv4 and IPv6 routing +FRRouting is free software that manages various IPv4 and IPv6 routing protocols. -Currently Free Range Routing supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, +Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS. See the file REPORTING-BUGS to report bugs. -Free Range Routing is free software. See the file COPYING for copying conditions. +Free RRRouting is free software. See the file COPYING for copying conditions. -Public email discussion can be found at https://lists.nox.tf/listinfo/frr +Public email discussion can be found at https://lists.frrouting.org/listinfo -Our public slack channel is at https://freerangerouting.slack.com +Our public slack channel is at https://frrouting.slack.com diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index be97ffda69..5b24d4ec61 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -1,20 +1,20 @@ /* Ethernet-VPN Attribute handling file Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index e6da7e7080..4b7d24de18 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -1,20 +1,20 @@ /* E-VPN attribute handling structure file Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 1ab8e23236..612f49f1cb 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1,20 +1,20 @@ /* Ethernet-VPN Packet and vty Processing File Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 63c1a766ea..9b24bb066a 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -1,20 +1,20 @@ /* E-VPN header for packet handling Copyright (C) 2016 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 1654265a72..97ce7ee969 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1,20 +1,20 @@ /* Ethernet-VPN Packet and vty Processing File Copyright (C) 2017 6WIND -This file is part of Free Range Routing +This file is part of FRRouting -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h index 11e93a5281..68b5f5cfbf 100644 --- a/bgpd/bgp_evpn_vty.h +++ b/bgpd/bgp_evpn_vty.h @@ -1,20 +1,20 @@ /* EVPN VTY functions to EVPN Copyright (C) 2017 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index edc5891d22..5b1b1b85b2 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -1,20 +1,20 @@ /* VPN Related functions Copyright (C) 2017 6WIND -This file is part of Free Range Routing +This file is part of FRRouting -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ diff --git a/bgpd/bgp_vpn.h b/bgpd/bgp_vpn.h index a16914b65e..dd53503bf3 100644 --- a/bgpd/bgp_vpn.h +++ b/bgpd/bgp_vpn.h @@ -1,20 +1,20 @@ /* VPN common functions to MP-BGP Copyright (C) 2017 6WIND -This file is part of Free Range Routing. +This file is part of FRRouting. -Free Range Routing is free software; you can redistribute it and/or modify it +FRRouting 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. -Free Range Routing is distributed in the hope that it will be useful, but +FRRouting 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 Free Range Routing; see the file COPYING. If not, write to the Free +along with FRRouting; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ From fab7c7260158439d57209479a0d3244bfe0e076d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 4 Apr 2017 20:36:16 -0400 Subject: [PATCH 14/34] doc: Cleanup 'Build the Software' The frrouting.org web page: https://frrouting.org/manual/Build-the-Software.html#Build-the-Software is built from doc/install.texi. The output on this page is a bit missleading, let's clean it up some. Signed-off-by: Donald Sharp --- doc/install.texi | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/doc/install.texi b/doc/install.texi index b34f316844..d989928b8f 100644 --- a/doc/install.texi +++ b/doc/install.texi @@ -218,18 +218,14 @@ routing utility. It contains @command{ifconfig}, @command{route}, After configuring the software, you will need to compile it for your system. Simply issue the command @command{make} in the root of the source -directory and the software will be compiled. If you have *any* problems -at this stage, be certain to send a bug report @xref{Bug Reports}. +directory and the software will be compiled. Cliff Note versions of +different compilation examples can be found in the doc/Building_FRR_on_XXX.md +files. If you have *any* problems at this stage, be certain to send a +bug report @xref{Bug Reports}. @example -% ./configure -. -. -. -./configure output -. -. -. +% ./bootstrap.sh +% ./configure % make @end example @c A - End of node, Building the Software From 0e374d906d8934e6054a54906449f83a3deefd71 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 24 Mar 2017 15:10:11 -0400 Subject: [PATCH 15/34] pimd: Add # of ifchannels to 'show ip pim int' Add the ability to see the number of ifchannels associated with a particular interface. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 3c5a16ec68..4b12f48314 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1040,6 +1040,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) struct pim_upstream *up; int fhr = 0; int pim_nbrs = 0; + int pim_ifchannels = 0; json_object *json = NULL; json_object *json_row = NULL; json_object *json_tmp; @@ -1056,6 +1057,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) continue; pim_nbrs = pim_ifp->pim_neighbor_list->count; + pim_ifchannels = pim_ifp->pim_ifchannel_list->count; fhr = 0; for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) @@ -1066,6 +1068,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) json_row = json_object_new_object(); json_object_pim_ifp_add(json_row, ifp); json_object_int_add(json_row, "pimNeighbors", pim_nbrs); + json_object_int_add(json_row, "pimIfChannels", pim_ifchannels); json_object_int_add(json_row, "firstHopRouter", fhr); json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr)); @@ -1078,7 +1081,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) if (uj) { vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); } else { - vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR%s", VTY_NEWLINE); + vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR IfChannels%s", VTY_NEWLINE); json_object_object_foreach(json, key, val) { vty_out(vty, "%-9s ", key); @@ -1100,7 +1103,10 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) } json_object_object_get_ex(val, "firstHopRouter", &json_tmp); - vty_out(vty, "%3d%s", json_object_get_int(json_tmp), VTY_NEWLINE); + vty_out(vty, "%3d ", json_object_get_int(json_tmp)); + + json_object_object_get_ex(val, "pimIfChannels", &json_tmp); + vty_out(vty, "%9d%s", json_object_get_int(json_tmp), VTY_NEWLINE); } } From 850a9f99b8e4ba6e043a75c28d25c9cb092770c5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 22 Mar 2017 21:07:57 -0400 Subject: [PATCH 16/34] pimd: Allow SPT switchover This allows SPT switchover for S,G upon receipt of packets on the LHR. 1) When we create a *,G from a IGMP Group Report, install the *,G route with the pimreg device on the OIL. 2) When a packet hits the LHR that matches the *,G, we will get a WHOLEPKT callback from the kernel and if we cannot find the S,G, that means we have matched it on the LHR via the *,G mroute. Create the S,G start the KAT and run inherited_olist. 3) When the S,G times out, safely remove the S,G via the KAT expiry 4) When the *,G is removed, remove any S,G associated with it via the LHR flag. Signed-off-by: Donald Sharp --- pimd/pim_ifchannel.c | 1 + pimd/pim_mroute.c | 17 ++++++++++ pimd/pim_upstream.c | 77 ++++++++++++++++++++++++++++---------------- pimd/pim_upstream.h | 5 +++ 4 files changed, 72 insertions(+), 28 deletions(-) diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index e6b4ba92a9..e1697960e4 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -1006,6 +1006,7 @@ pim_ifchannel_local_membership_add(struct interface *ifp, pim_upstream_switch (child, PIM_UPSTREAM_JOINED); } } + pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); } return 1; diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 2fb243b9bd..cfbd07ede0 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -200,6 +200,23 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf) up = pim_upstream_find(&sg); if (!up) { + struct prefix_sg star = sg; + star.src.s_addr = INADDR_ANY; + + up = pim_upstream_find(&star); + + if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) + { + up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, __PRETTY_FUNCTION__); + pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); + pim_upstream_inherited_olist (up); + pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + + if (PIM_DEBUG_MROUTE) + zlog_debug ("%s: Creating %s upstream on LHR", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } if (PIM_DEBUG_MROUTE_DETAIL) { zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s", __PRETTY_FUNCTION__, pim_str_sg_dump (&sg)); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 172d0d21c9..3e81aaf496 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -198,7 +198,20 @@ pim_upstream_del(struct pim_upstream *up, const char *name) upstream_channel_oil_detach(up); if (up->sources) - list_delete (up->sources); + { + struct listnode *node, *nnode; + struct pim_upstream *child; + for (ALL_LIST_ELEMENTS (up->sources, node, nnode, child)) + { + if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) + { + PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags); + pim_upstream_del(child, __PRETTY_FUNCTION__); + } + } + + list_delete (up->sources); + } up->sources = NULL; /* @@ -1083,26 +1096,31 @@ pim_upstream_keep_alive_timer (struct thread *t) up->t_ka_timer = NULL; if (I_am_RP (up->sg.grp)) - { - pim_br_clear_pmbr (&up->sg); - /* - * We need to do more here :) - * But this is the start. - */ - } + { + pim_br_clear_pmbr (&up->sg); + /* + * We need to do more here :) + * But this is the start. + */ + } /* source is no longer active - pull the SA from MSDP's cache */ pim_msdp_sa_local_del(&up->sg); /* if entry was created because of activity we need to deref it */ if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) - { - pim_upstream_fhr_kat_expiry(up); - if (PIM_DEBUG_TRACE) - zlog_debug ("kat expired on %s; remove stream reference", up->sg_str); - PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags); - pim_upstream_del(up, __PRETTY_FUNCTION__); - } + { + pim_upstream_fhr_kat_expiry(up); + if (PIM_DEBUG_TRACE) + zlog_debug ("kat expired on %s; remove stream reference", up->sg_str); + PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags); + pim_upstream_del(up, __PRETTY_FUNCTION__); + } + else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) + { + PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags); + pim_upstream_del(up, __PRETTY_FUNCTION__); + } return 0; } @@ -1633,25 +1651,28 @@ pim_upstream_sg_running (void *arg) return; } - if (pim_upstream_kat_start_ok(up)) { - /* Add a source reference to the stream if - * one doesn't already exist */ - if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) + if (pim_upstream_kat_start_ok(up)) { - if (PIM_DEBUG_TRACE) - zlog_debug ("source reference created on kat restart %s", up->sg_str); + /* Add a source reference to the stream if + * one doesn't already exist */ + if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) + { + if (PIM_DEBUG_TRACE) + zlog_debug ("source reference created on kat restart %s", up->sg_str); - pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM); - PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); - pim_upstream_fhr_kat_start(up); + pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM); + PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); + pim_upstream_fhr_kat_start(up); + } + pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); } + else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); - } if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) - { - pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); - } + { + pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); + } return; } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 6f7556f323..94bc5a55b9 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -34,6 +34,8 @@ #define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5) #define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6) #define PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE (1 << 7) +#define PIM_UPSTREAM_FLAG_MASK_SRC_LHR (1 << 8) +#define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -43,6 +45,7 @@ #define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM) #define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE) +#define PIM_UPSTREAM_FLAG_TEST_SRC_LHR(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_LHR) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -52,6 +55,7 @@ #define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM) #define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE) +#define PIM_UPSTREAM_FLAG_SET_SRC_LHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_LHR) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -61,6 +65,7 @@ #define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM) #define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP) #define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE) +#define PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_LHR) enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, From 2830b0186384ff53ed33186276936739f2e079cb Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 30 Mar 2017 10:50:04 -0400 Subject: [PATCH 17/34] pimd: Fix crash when failure to create upstream When we have a *,G mroute that starts receiving any particular S,G, we will get wholepkt callbacks due to the pimreg in the OIL for the *,G. So we need to do SPT switchover, but this can fail if we do not have a path to the S( but we do to the RP!). In this case fail gracefully. Ticket: CM-15621 Signed-off-by: Donald Sharp --- pimd/pim_mroute.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index cfbd07ede0..1df4c033bc 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -208,6 +208,13 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf) if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) { up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, __PRETTY_FUNCTION__); + if (!up) + { + if (PIM_DEBUG_MROUTE) + zlog_debug ("%s: Unable to create upstream information for %s", + __PRETTY_FUNCTION__, pim_str_sg_dump (&sg)); + return 0; + } pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); pim_upstream_inherited_olist (up); pim_upstream_switch(up, PIM_UPSTREAM_JOINED); From a7b2b1e29862f82d8a68bda2c72a460cd26aa5a8 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 5 Apr 2017 12:08:53 -0400 Subject: [PATCH 18/34] pimd: Add the ability to never SPT switchover Add the ability to allow pim to determine if we should allow spt-switchover or not on the LHR. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 31 +++++++++++++++++++++++++++++++ pimd/pim_ifchannel.c | 3 ++- pimd/pim_upstream.c | 36 ++++++++++++++++++++++++++++++++++++ pimd/pim_upstream.h | 3 +++ pimd/pim_vty.c | 6 ++++++ pimd/pimd.c | 1 + pimd/pimd.h | 8 ++++++++ 7 files changed, 87 insertions(+), 1 deletion(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 4b12f48314..de2b7cbba6 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3416,6 +3416,35 @@ pim_rp_cmd_worker (struct vty *vty, const char *rp, const char *group, const cha return CMD_SUCCESS; } +DEFUN (ip_pim_spt_switchover_infinity, + ip_pim_spt_switchover_infinity_cmd, + "ip pim spt-switchover infinity-and-beyond", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n") +{ + pimg->spt_switchover = PIM_SPT_INFINITY; + + pim_upstream_remove_lhr_star_pimreg(); + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_spt_switchover_infinity, + no_ip_pim_spt_switchover_infinity_cmd, + "no ip pim spt-switchover infinity-and-beyond", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n") +{ + pimg->spt_switchover = PIM_SPT_IMMEDIATE; + + pim_upstream_add_lhr_star_pimreg(); + return CMD_SUCCESS; +} + DEFUN (ip_pim_joinprune_time, ip_pim_joinprune_time_cmd, "ip pim join-prune-interval <60-600>", @@ -6187,6 +6216,8 @@ void pim_cmd_init() install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd); install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd); install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd); + install_element (CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd); + install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd); install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element (CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); install_element (CONFIG_NODE, &ip_pim_keep_alive_cmd); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index e1697960e4..ebd36f8782 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -1006,7 +1006,8 @@ pim_ifchannel_local_membership_add(struct interface *ifp, pim_upstream_switch (child, PIM_UPSTREAM_JOINED); } } - pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + if (pimg->spt_switchover != PIM_SPT_INFINITY) + pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); } return 1; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 3e81aaf496..5743dac654 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1676,6 +1676,42 @@ pim_upstream_sg_running (void *arg) return; } +void +pim_upstream_add_lhr_star_pimreg (void) +{ + struct pim_upstream *up; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up)) + { + if (up->sg.src.s_addr != INADDR_ANY) + continue; + + if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags)) + continue; + + pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + } +} + +void +pim_upstream_remove_lhr_star_pimreg (void) +{ + struct pim_upstream *up; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up)) + { + if (up->sg.src.s_addr != INADDR_ANY) + continue; + + if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags)) + continue; + + pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); + } +} + void pim_upstream_init (void) { diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 94bc5a55b9..a1af4483ac 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -198,4 +198,7 @@ void pim_upstream_terminate (void); void join_timer_start (struct pim_upstream *up); int pim_upstream_compare (void *arg1, void *arg2); void pim_upstream_register_reevaluate (void); + +void pim_upstream_add_lhr_star_pimreg (void); +void pim_upstream_remove_lhr_star_pimreg (void); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index f4bfcc5ce0..3d52dc9c41 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -182,6 +182,12 @@ int pim_global_config_write(struct vty *vty) ssm->plist_name, VTY_NEWLINE); ++writes; } + if (pimg->spt_switchover == PIM_SPT_INFINITY) + { + vty_out (vty, "ip pim spt-switchover infinity-and-beyond%s", + VTY_NEWLINE); + ++writes; + } if (qpim_ssmpingd_list) { struct listnode *node; diff --git a/pimd/pimd.c b/pimd/pimd.c index bdbd251e20..eaef4ff5c0 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -249,6 +249,7 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi) pim->vrf_id = vrf_id; pim->afi = afi; + pim->spt_switchover = PIM_SPT_IMMEDIATE; pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal); if (PIM_DEBUG_ZEBRA) diff --git a/pimd/pimd.h b/pimd/pimd.h index 69aee28f8f..6c3dcfafca 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -237,11 +237,19 @@ extern int32_t qpim_register_probe_time; #define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS) #define PIM_DONT_DEBUG_MSDP_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL) +enum pim_spt_switchover { + PIM_SPT_IMMEDIATE, + PIM_SPT_INFINITY, +}; + /* Per VRF PIM DB */ struct pim_instance { afi_t afi; vrf_id_t vrf_id; + + enum pim_spt_switchover spt_switchover; + struct hash *rpf_hash; void *ssm_info; /* per-vrf SSM configuration */ }; From 856377cc390301751fa2d4111f6f66cd75b59ec2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 5 Apr 2017 23:08:19 -0400 Subject: [PATCH 19/34] lib: Fix missing help strings Signed-off-by: Donald Sharp --- lib/distribute.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/distribute.c b/lib/distribute.c index 01c338f177..f85994c9a8 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -254,6 +254,7 @@ DEFUN (distribute_list, distribute_list_cmd, "distribute-list [prefix] WORD [WORD]", "Filter networks in routing updates\n" + "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" @@ -316,7 +317,9 @@ DEFUN (no_distribute_list, no_distribute_list_cmd, "no [ipv6] distribute-list [prefix] WORD [WORD]", NO_STR + "IPv6\n" "Filter networks in routing updates\n" + "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" From fa35a883c1d627cac5516d7b751341d5934688b6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 5 Apr 2017 23:18:12 -0400 Subject: [PATCH 20/34] *: Switchover to 3.0 Signed-off-by: Donald Sharp --- configure.ac | 2 +- debian/changelog | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6eac0e3c86..6661f45d7c 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(frr, 2.1-dev, [https://github.com/frrouting/frr/issues]) +AC_INIT(frr, 3.0, [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" PACKAGE_FULLNAME="FRRouting" AC_SUBST(PACKAGE_FULLNAME) diff --git a/debian/changelog b/debian/changelog index 8302af4b4c..fe4ee6b334 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,24 @@ +frr (3.0) Released; urgency=medium + + * New Enabled: BGP Shutdown Message + * New Enabled: BGP Large Community + * New Enabled: BGP RFC 7432 Partial Support w/ Ethernet VPN + * New Enabled: BGP EVPN RT-5 + * New Enabled: LDP RFC 5561 + * New Enabled: LDP RFC 5918 + * New Enabled: LDP RFC 5919 + * New Enabled: LDP RFC 6667 + * New Enabled: LDP RFC 7473 + * New Enabled: OSPF RFC 4552 + * New Enabled: ISIS SPF Backoff draft + * New Enabled: PIM Unnumbered Interfaces + * New Enabled: PIM RFC 4611 + * New Enabled: PIM Sparse Mode + * New Enabled: NHRP RFC 2332 + * New Enabled: Label Manager + + -- frr Wed, 5 Apr 2017 22:23:42 -0500 + frr (2.1) Released; urgency=medium * Switchover to FRR From 4952d0f0b0c30021242fe9d33e8e09015fd26161 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 5 Apr 2017 23:18:12 -0400 Subject: [PATCH 21/34] *: Switchover to 3.1-dev Signed-off-by: Donald Sharp --- configure.ac | 2 +- debian/changelog | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b4a3e37fd2..822c032fe6 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(frr, 2.1-dev, [https://github.com/frrouting/frr/issues]) +AC_INIT(frr, 3.1-dev, [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" PACKAGE_FULLNAME="FRRouting" AC_SUBST(PACKAGE_FULLNAME) diff --git a/debian/changelog b/debian/changelog index 8302af4b4c..4ea86929fc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,30 @@ +frr (3.1-dev) Released; urgency=medium + + * New Enabled: PIM draft Unnumbered + + -- frr Wed, 5 Apr 2017 22:29:42 -0500 + +frr (3.0) Released; urgency=medium + + * New Enabled: BGP Shutdown Message + * New Enabled: BGP Large Community + * New Enabled: BGP RFC 7432 Partial Support w/ Ethernet VPN + * New Enabled: BGP EVPN RT-5 + * New Enabled: LDP RFC 5561 + * New Enabled: LDP RFC 5918 + * New Enabled: LDP RFC 5919 + * New Enabled: LDP RFC 6667 + * New Enabled: LDP RFC 7473 + * New Enabled: OSPF RFC 4552 + * New Enabled: ISIS SPF Backoff draft + * New Enabled: PIM Unnumbered Interfaces + * New Enabled: PIM RFC 4611 + * New Enabled: PIM Sparse Mode + * New Enabled: NHRP RFC 2332 + * New Enabled: Label Manager + + -- frr Wed, 5 Apr 2017 22:23:42 -0500 + frr (2.1) Released; urgency=medium * Switchover to FRR From cba444817883b8b3b22a7ed9958dc9ed77f76230 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 5 Apr 2017 13:14:12 -0700 Subject: [PATCH 22/34] pimd: Pim Nexthop Tracking support with ECMP In this patch, PIM nexthop tracking uses locally populated nexthop cached list to determine ECMP based nexthop (w/ ECMP knob enabled), otherwise picks the first nexthop as RPF. Introduced '[no] ip pim ecmp' command to enable/disable PIM ECMP knob. By default, PIM ECMP is disabled. Intorudced '[no] ip pim ecmp rebalance' command to provide existing mcache entry to switch new path based on hash chosen path. Introduced, show command to display pim registered addresses and respective nexthops. Introuduce, show command to find nexthop and out interface for (S,G) or (RP,G). Re-Register an address with nexthop when Interface UP event received, to ensure the PIM nexthop cache is updated (being PIM enabled). During PIM neighbor UP, traverse all RPs and Upstreams nexthop and determine, if any of nexthop's IPv4 address changes/resolves due to neigbor UP event. Testing Done: Run various LHR, RP and FHR related cases to resolve RPF using nexthop cache with ECMP knob disabled, performed interface/PIM neighbor flap events. Executed pim-smoke with knob disabled. Signed-off-by: Chirag Shah --- pimd/pim_cmd.c | 216 ++++++++++++++++- pimd/pim_iface.c | 45 +++- pimd/pim_mroute.c | 12 +- pimd/pim_neighbor.c | 14 ++ pimd/pim_nht.c | 561 ++++++++++++++++++++++++++++++++++++++------ pimd/pim_nht.h | 13 +- pimd/pim_oil.c | 4 +- pimd/pim_register.c | 9 + pimd/pim_rp.c | 174 ++++++++++++-- pimd/pim_rp.h | 2 +- pimd/pim_rpf.c | 69 ++++-- pimd/pim_upstream.c | 22 +- pimd/pim_zebra.c | 168 ++++++++++--- pimd/pimd.c | 4 +- pimd/pimd.h | 3 + 15 files changed, 1143 insertions(+), 173 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 3c5a16ec68..6af072f32f 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -26,6 +26,8 @@ #include "prefix.h" #include "zclient.h" #include "plist.h" +#include "hash.h" +#include "nexthop.h" #include "pimd.h" #include "pim_mroute.h" @@ -55,6 +57,7 @@ #include "pim_zlookup.h" #include "pim_msdp.h" #include "pim_ssm.h" +#include "pim_nht.h" static struct cmd_node pim_global_node = { PIM_NODE, @@ -2059,6 +2062,50 @@ static void pim_show_rpf(struct vty *vty, u_char uj) } } +static int +pim_print_pnc_cache_walkcb (struct hash_backet *backet, void *arg) +{ + struct pim_nexthop_cache *pnc = backet->data; + struct vty *vty = arg; + struct nexthop *nh_node = NULL; + ifindex_t first_ifindex; + struct interface *ifp = NULL; + + if (!pnc) + return CMD_SUCCESS; + + for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) + { + first_ifindex = nh_node->ifindex; + ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT); + + vty_out (vty, "%-15s ", inet_ntoa (pnc->rpf.rpf_addr.u.prefix4)); + vty_out (vty, "%-14s ", ifp ? ifp->name : "NULL"); + vty_out (vty, "%s ", inet_ntoa (nh_node->gate.ipv4)); + vty_out (vty, "%s", VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +static void +pim_show_nexthop (struct vty *vty) +{ + + if (pimg && !pimg->rpf_hash) + { + vty_out (vty, "no nexthop cache %s", VTY_NEWLINE); + return; + } + + vty_out (vty, "Number of registered addresses: %lu %s", + pimg->rpf_hash->count, VTY_NEWLINE); + vty_out (vty, "Address Interface Nexthop%s", VTY_NEWLINE); + vty_out (vty, "-------------------------------------------%s", VTY_NEWLINE); + + hash_walk (pimg->rpf_hash, pim_print_pnc_cache_walkcb, vty); + +} + static void igmp_show_groups(struct vty *vty, u_char uj) { struct listnode *ifnode; @@ -2793,6 +2840,99 @@ DEFUN (show_ip_pim_rpf, return CMD_SUCCESS; } +DEFUN (show_ip_pim_nexthop, + show_ip_pim_nexthop_cmd, + "show ip pim nexthop", + SHOW_STR + IP_STR + PIM_STR + "PIM cached nexthop rpf information\n") +{ + pim_show_nexthop (vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_nexthop_lookup, + show_ip_pim_nexthop_lookup_cmd, + "show ip pim nexthop-lookup A.B.C.D A.B.C.D", + SHOW_STR + IP_STR + PIM_STR + "PIM cached nexthop rpf lookup\n" + "Source/RP address\n" + "Multicast Group address\n") +{ + struct pim_nexthop_cache pnc; + struct prefix nht_p; + int result = 0; + struct in_addr src_addr, grp_addr; + struct in_addr vif_source; + const char *addr_str, *addr_str1; + struct prefix grp; + struct pim_nexthop nexthop; + char nexthop_addr_str[PREFIX_STRLEN]; + char grp_str[PREFIX_STRLEN]; + + addr_str = (const char *)argv[0]; + result = inet_pton (AF_INET, addr_str, &src_addr); + if (result <= 0) + { + vty_out (vty, "Bad unicast address %s: errno=%d: %s%s", + addr_str, errno, safe_strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (pim_is_group_224_4 (src_addr)) + { + vty_out (vty, "Invalid argument. Expected Valid Source Address.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + addr_str1 = (const char *)argv[1]; + result = inet_pton (AF_INET, addr_str1, &grp_addr); + if (result <= 0) + { + vty_out (vty, "Bad unicast address %s: errno=%d: %s%s", + addr_str, errno, safe_strerror (errno), VTY_NEWLINE); + return CMD_WARNING; + } + + if (!pim_is_group_224_4 (grp_addr)) + { + vty_out (vty, "Invalid argument. Expected Valid Multicast Group Address.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!pim_rp_set_upstream_addr (&vif_source, src_addr, grp_addr)) + return CMD_SUCCESS; + + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = vif_source; + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = grp_addr; + memset (&nexthop, 0, sizeof (nexthop)); + + if ((pim_find_or_track_nexthop (&nht_p, NULL, NULL, &pnc)) == 1) + { + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &nexthop, &nht_p, &grp, 0); + } + else + pim_ecmp_nexthop_lookup (&nexthop, vif_source, &nht_p, &grp, 0); + + pim_addr_dump ("", &grp, grp_str, sizeof (grp_str)); + pim_addr_dump ("", &nexthop.mrib_nexthop_addr, + nexthop_addr_str, sizeof (nexthop_addr_str)); + vty_out (vty, "Group %s --- Nexthop %s Interface %s %s", grp_str, + nexthop_addr_str, nexthop.interface->name, VTY_NEWLINE); + + return CMD_SUCCESS; +} + static void show_multicast_interfaces(struct vty *vty) { struct listnode *node; @@ -2871,15 +3011,17 @@ DEFUN (show_ip_multicast, PIM_MAX_USABLE_VIFS, VTY_NEWLINE); - vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, "Upstream Join Timer: %d secs%s", - qpim_t_periodic, - VTY_NEWLINE); - vty_out(vty, "Join/Prune Holdtime: %d secs%s", - PIM_JP_HOLDTIME, - VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "Upstream Join Timer: %d secs%s", + qpim_t_periodic, VTY_NEWLINE); + vty_out (vty, "Join/Prune Holdtime: %d secs%s", + PIM_JP_HOLDTIME, VTY_NEWLINE); + vty_out (vty, "PIM ECMP: %s%s", + qpim_ecmp_enable ? "Enable" : "Disable", VTY_NEWLINE); + vty_out (vty, "PIM ECMP Rebalance: %s%s", + qpim_ecmp_rebalance_enable ? "Enable" : "Disable", VTY_NEWLINE); - vty_out(vty, "%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); show_rpf_refresh_stats(vty, now, NULL); @@ -3826,6 +3968,58 @@ DEFUN (no_ip_ssmpingd, return CMD_SUCCESS; } +DEFUN (ip_pim_ecmp, + ip_pim_ecmp_cmd, + "ip pim ecmp", + IP_STR + "pim multicast routing\n" + "Enable PIM ECMP \n") +{ + qpim_ecmp_enable = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_ecmp, + no_ip_pim_ecmp_cmd, + "no ip pim ecmp", + NO_STR + IP_STR + "pim multicast routing\n" + "Disable PIM ECMP \n") +{ + qpim_ecmp_enable = 0; + + return CMD_SUCCESS; +} + +DEFUN (ip_pim_ecmp_rebalance, + ip_pim_ecmp_rebalance_cmd, + "ip pim ecmp rebalance", + IP_STR + "pim multicast routing\n" + "Enable PIM ECMP \n" + "Enable PIM ECMP Rebalance\n") +{ + qpim_ecmp_rebalance_enable = 1; + + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_ecmp_rebalance, + no_ip_pim_ecmp_rebalance_cmd, + "no ip pim ecmp rebalance", + NO_STR + IP_STR + "pim multicast routing\n" + "Disable PIM ECMP \n" + "Disable PIM ECMP Rebalance\n") +{ + qpim_ecmp_rebalance_enable = 0; + + return CMD_SUCCESS; +} + static int pim_cmd_igmp_start (struct vty *vty, struct interface *ifp) { @@ -6191,6 +6385,10 @@ void pim_cmd_init() install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); install_element (CONFIG_NODE, &ip_msdp_peer_cmd); install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element (CONFIG_NODE, &ip_pim_ecmp_cmd); + install_element (CONFIG_NODE, &no_ip_pim_ecmp_cmd); + install_element (CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd); + install_element (CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd); @@ -6246,6 +6444,8 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_rib_cmd); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); install_element (VIEW_NODE, &show_debugging_pim_cmd); + install_element (VIEW_NODE, &show_ip_pim_nexthop_cmd); + install_element (VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 0864796431..bdad1c531c 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -30,6 +30,7 @@ #include "hash.h" #include "pimd.h" +#include "pim_zebra.h" #include "pim_iface.h" #include "pim_igmp.h" #include "pim_mroute.h" @@ -42,6 +43,7 @@ #include "pim_time.h" #include "pim_ssmpingd.h" #include "pim_rp.h" +#include "pim_nht.h" struct interface *pim_regiface = NULL; struct list *pim_ifchannel_list = NULL; @@ -583,21 +585,40 @@ void pim_if_addr_add(struct connected *ifc) } } /* igmp */ - if (PIM_IF_TEST_PIM(pim_ifp->options)) { + if (PIM_IF_TEST_PIM(pim_ifp->options)) + { - /* Interface has a valid primary address ? */ - if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { + if (PIM_INADDR_ISNOT_ANY (pim_ifp->primary_address)) + { - /* Interface has a valid socket ? */ - if (pim_ifp->pim_sock_fd < 0) { - if (pim_sock_add(ifp)) { - zlog_warn("Failure creating PIM socket for interface %s", - ifp->name); - } - } + /* Interface has a valid socket ? */ + if (pim_ifp->pim_sock_fd < 0) + { + if (pim_sock_add (ifp)) + { + zlog_warn ("Failure creating PIM socket for interface %s", + ifp->name); + } + } + struct pim_nexthop_cache *pnc = NULL; + struct pim_rpf rpf; + struct zclient *zclient = NULL; - } - } /* pim */ + zclient = pim_zebra_zclient_get (); + /* RP config might come prior to (local RP's interface) IF UP event. + In this case, pnc would not have pim enabled nexthops. + Once Interface is UP and pim info is available, reregister + with RNH address to receive update and add the interface as nexthop. */ + memset (&rpf, 0, sizeof (struct pim_rpf)); + rpf.rpf_addr.family = AF_INET; + rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; + rpf.rpf_addr.u.prefix4 = ifc->address->u.prefix4; + pnc = pim_nexthop_cache_find (&rpf); + if (pnc) + pim_sendmsg_zebra_rnh (zclient, pnc, + ZEBRA_NEXTHOP_REGISTER); + } + } /* pim */ /* PIM or IGMP is enabled on interface, and there is at least one diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 2fb243b9bd..23f08efc04 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -178,6 +178,15 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg up->channel_oil->cc.pktcnt++; PIM_UPSTREAM_FLAG_SET_FHR(up->flags); + // resolve mfcc_parent prior to mroute_add in channel_add_oif + if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) + { + int vif_index = 0; + vif_index = + pim_if_find_vifindex_by_ifindex (up->rpf.source_nexthop. + interface->ifindex); + up->channel_oil->oil.mfcc_parent = vif_index; + } pim_register_join (up); return 0; @@ -858,9 +867,8 @@ int pim_mroute_del (struct channel_oil *c_oil, const char *name) pim_channel_oil_dump (c_oil, buf, sizeof(buf))); } - /*reset incoming vifi and kernel installed flags*/ + //Reset kernel installed flag c_oil->installed = 0; - c_oil->oil.mfcc_parent = MAXVIFS; return 0; } diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index c1325df260..71d7ac4148 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -502,6 +502,12 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp, listnode_add(pim_ifp->pim_neighbor_list, neigh); + if (PIM_DEBUG_PIM_TRACE_DETAIL) + { + char str[INET_ADDRSTRLEN]; + pim_inet4_dump("", source_addr, str, sizeof (str)); + zlog_debug ("%s: neighbor %s added ", __PRETTY_FUNCTION__, str); + } /* RFC 4601: 4.3.2. DR Election @@ -532,6 +538,14 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp, pim_upstream_find_new_rpf(); + /* RNH can send nexthop update prior to PIM neibhor UP + in that case nexthop cache would not consider this neighbor + as RPF. + Upon PIM neighbor UP, iterate all RPs and update + nexthop cache with this neighbor. + */ + pim_resolve_rp_nh (); + pim_rp_setup (); pim_neighbor_rpf_update(); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index fe96d01a06..23efd554ea 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -39,12 +39,13 @@ #include "pim_join.h" #include "pim_jp_agg.h" #include "pim_zebra.h" +#include "pim_zlookup.h" /** * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister * command to Zebra. */ -static void +void pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc, int command) { @@ -87,9 +88,9 @@ pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc, { char buf[PREFIX2STR_BUFFER]; prefix2str (p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Addr %s %sregistered with Zebra ret:%d ", - __PRETTY_FUNCTION__, buf, - (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", ret); + zlog_debug ("%s: NHT %sregistered addr %s with Zebra ret:%d ", + __PRETTY_FUNCTION__, + (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", buf, ret); } return; @@ -149,7 +150,8 @@ pim_nexthop_cache_add (struct pim_rpf *rpf_addr) /* This API is used to Register an address with Zebra */ int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp) + struct rp_info *rp, + struct pim_nexthop_cache *out_pnc) { struct pim_nexthop_cache *pnc = NULL; struct pim_rpf rpf; @@ -174,11 +176,14 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, } pnc = pim_nexthop_cache_add (&rpf); if (pnc) - pim_sendmsg_zebra_rnh (zclient, pnc, - ZEBRA_NEXTHOP_REGISTER); + pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_REGISTER); else { - zlog_warn ("%s: pnc node allocation failed. ", __PRETTY_FUNCTION__); + char rpf_str[PREFIX_STRLEN]; + pim_addr_dump ("", addr, rpf_str, sizeof (rpf_str)); + zlog_warn ("%s: pnc node allocation failed. addr %s ", + __PRETTY_FUNCTION__, rpf_str); + return -1; } } @@ -192,7 +197,7 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, char rp_str[PREFIX_STRLEN]; pim_addr_dump ("", &rp->rp.rpf_addr, rp_str, sizeof (rp_str)); - zlog_debug ("%s: NHT add RP %s node to cached list", + zlog_debug ("%s: Add RP %s node to pnc cached list", __PRETTY_FUNCTION__, rp_str); } listnode_add_sort (pnc->rp_list, rp); @@ -209,15 +214,18 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, char buf[PREFIX2STR_BUFFER]; prefix2str (addr, buf, sizeof (buf)); zlog_debug - ("%s: NHT add upstream %s node to cached list, rpf %s", + ("%s: Add upstream %s node to pnc cached list, rpf %s", __PRETTY_FUNCTION__, up->sg_str, buf); } listnode_add_sort (pnc->upstream_list, up); } } - if (CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID)) - return 1; + if (pnc && CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID)) + { + memcpy (out_pnc, pnc, sizeof (struct pim_nexthop_cache)); + return 1; + } return 0; } @@ -249,8 +257,7 @@ pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up, if (pnc->rp_list->count == 0 && pnc->upstream_list->count == 0) { - pim_sendmsg_zebra_rnh (zclient, pnc, - ZEBRA_NEXTHOP_UNREGISTER); + pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_UNREGISTER); list_delete (pnc->rp_list); list_delete (pnc->upstream_list); @@ -277,21 +284,16 @@ pim_update_rp_nh (struct pim_nexthop_cache *pnc) if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) continue; - if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, - rp_info->rp.rpf_addr.u.prefix4, 1) != 0) - { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug ("Unable to lookup nexthop for rp specified"); - ret++; - continue; - } + //Compute PIM RPF using cached nexthop + pim_ecmp_nexthop_search (pnc, &rp_info->rp.source_nexthop, + &rp_info->rp.rpf_addr, &rp_info->group, 1); if (PIM_DEBUG_TRACE) { char rp_str[PREFIX_STRLEN]; pim_addr_dump ("", &rp_info->rp.rpf_addr, rp_str, sizeof (rp_str)); - zlog_debug ("%s: NHT update nexthop for RP %s to interface %s ", + zlog_debug ("%s: NHT update, nexthop for RP %s is interface %s ", __PRETTY_FUNCTION__, rp_str, rp_info->rp.source_nexthop.interface->name); } @@ -304,6 +306,48 @@ pim_update_rp_nh (struct pim_nexthop_cache *pnc) } +/* This API is used to traverse nexthop cache of RPF addr + of upstream entry whose IPv4 nexthop address is in + unresolved state and due to event like pim neighbor + UP event if it can be resolved. +*/ +void +pim_resolve_upstream_nh (struct prefix *nht_p) +{ + struct nexthop *nh_node = NULL; + struct pim_nexthop_cache pnc; + struct pim_neighbor *nbr = NULL; + + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((pim_find_or_track_nexthop (nht_p, NULL, NULL, &pnc)) == 1) + { + for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) + { + if (nh_node->gate.ipv4.s_addr == 0) + { + nbr = + pim_neighbor_find_if (if_lookup_by_index + (nh_node->ifindex, VRF_DEFAULT)); + if (nbr) + { + nh_node->gate.ipv4 = nbr->source_addr; + if (PIM_DEBUG_TRACE) + { + char str[PREFIX_STRLEN]; + char str1[INET_ADDRSTRLEN]; + pim_inet4_dump ("", nbr->source_addr, str1, + sizeof (str1)); + pim_addr_dump ("", nht_p, str, sizeof (str)); + zlog_debug + ("%s: addr %s new nexthop addr %s ifindex %d ", + __PRETTY_FUNCTION__, str, str1, nh_node->ifindex); + } + } + } + } + } +} + /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/ static int pim_update_upstream_nh (struct pim_nexthop_cache *pnc) @@ -312,8 +356,8 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) struct listnode *ifnode; struct listnode *up_nextnode; struct listnode *node; - struct pim_upstream *up; - struct interface *ifp; + struct pim_upstream *up = NULL; + struct interface *ifp = NULL; int vif_index = 0; for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up)) @@ -326,6 +370,26 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) if (rpf_result == PIM_RPF_FAILURE) continue; + /* update kernel multicast forwarding cache (MFC) */ + if (up->channel_oil) + { + vif_index = + pim_if_find_vifindex_by_ifindex (up->rpf. + source_nexthop.interface-> + ifindex); + /* Pass Current selected NH vif index to mroute download */ + if (vif_index) + pim_scan_individual_oil (up->channel_oil, vif_index); + else + { + if (PIM_DEBUG_ZEBRA) + zlog_debug + ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", + __PRETTY_FUNCTION__, up->sg_str, + up->rpf.source_nexthop.interface->name); + } + } + if (rpf_result == PIM_RPF_CHANGED) { struct pim_neighbor *nbr; @@ -377,7 +441,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) returning PIM_RPF_CHANGED ? */ pim_upstream_update_join_desired (up); - } /* PIM_RPF_CHANGED */ + } /* PIM_RPF_CHANGED */ if (PIM_DEBUG_TRACE) { @@ -386,26 +450,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) old.source_nexthop.interface->name, up->rpf.source_nexthop.interface->name); } - /* update kernel multicast forwarding cache (MFC) */ - if (up->channel_oil) - { - vif_index = - pim_if_find_vifindex_by_ifindex (up->rpf. - source_nexthop.interface-> - ifindex); - /* Pass Current selected NH vif index to mroute download */ - if (vif_index) - pim_scan_individual_oil (up->channel_oil, vif_index); - else - { - if (PIM_DEBUG_ZEBRA) - zlog_debug ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", - __PRETTY_FUNCTION__, up->sg_str, - up->rpf.source_nexthop.interface->name); - } - } - - } /* for (pnc->upstream_list) */ + } /* for (pnc->upstream_list) */ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) if (ifp->info) @@ -426,10 +471,209 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc) return 0; } -/* - * This API is used to parse Registered address nexthop update - * coming from Zebra - */ +uint32_t +pim_compute_ecmp_hash (struct prefix * src, struct prefix * grp) +{ + uint32_t hash_val; + uint32_t s = 0, g = 0; + + if ((!src)) + return 0; + + switch (src->family) + { + case AF_INET: + { + s = src->u.prefix4.s_addr; + s = s == 0 ? 1 : s; + if (grp) + g = grp->u.prefix4.s_addr; + } + break; + default: + break; + } + + hash_val = jhash_2words (g, s, 101); + if (PIM_DEBUG_TRACE) + { + char buf[PREFIX2STR_BUFFER]; + char bufg[PREFIX2STR_BUFFER]; + prefix2str (src, buf, sizeof (buf)); + if (grp) + prefix2str (grp, bufg, sizeof (bufg)); + zlog_debug ("%s: addr %s %s hash_val %u", __PRETTY_FUNCTION__, buf, + grp ? bufg : "", hash_val); + + } + return hash_val; +} + +int +pim_ecmp_nexthop_search (struct pim_nexthop_cache *pnc, + struct pim_nexthop *nexthop, struct prefix *src, + struct prefix *grp, int neighbor_needed) +{ + struct pim_neighbor *nbr = NULL; + struct nexthop *nh_node = NULL; + ifindex_t first_ifindex; + struct interface *ifp = NULL; + uint32_t hash_val = 0, mod_val = 0; + uint8_t nh_iter = 0, found = 0; + + if (!pnc || !pnc->nexthop_num || !nexthop) + return -1; + + if (qpim_ecmp_enable) + { + //User configured knob to explicitly switch to new path. + if (qpim_ecmp_rebalance_enable == 0) + { + //Current Nexthop is VALID then stay on the current path. + if (nexthop->interface && nexthop->interface->info && + nexthop->mrib_nexthop_addr.u.prefix4.s_addr != + PIM_NET_INADDR_ANY) + { + if (neighbor_needed + && !pim_if_connected_to_source (nexthop->interface, + src->u.prefix4)) + { + nbr = pim_neighbor_find (nexthop->interface, + nexthop->mrib_nexthop_addr. + u.prefix4); + if (!nbr && !if_is_loopback (nexthop->interface)) + { + if (PIM_DEBUG_TRACE) + zlog_debug ("%s: current nexthop does not have nbr ", + __PRETTY_FUNCTION__); + } + else + { + if (PIM_DEBUG_TRACE) + { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", src->u.prefix4, src_str, + sizeof (src_str)); + char grp_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", grp->u.prefix4, grp_str, + sizeof (grp_str)); + zlog_debug + ("%s: %s %s current nexthop %d is valid, not choosing new path", + __PRETTY_FUNCTION__, src_str, grp_str, + nexthop->interface->ifindex); + } + return 0; + } + } + } + } + //PIM ECMP flag is enable then choose ECMP path. + hash_val = pim_compute_ecmp_hash (src, grp); + mod_val = hash_val % pnc->nexthop_num; + if (PIM_DEBUG_TRACE) + zlog_debug ("%s: hash_val %u mod_val %u ", + __PRETTY_FUNCTION__, hash_val, mod_val); + } + + for (nh_node = pnc->nexthop; nh_node && (found == 0); + nh_node = nh_node->next) + { + first_ifindex = nh_node->ifindex; + ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT); + if (!ifp) + { + if (PIM_DEBUG_ZEBRA) + { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", src->u.prefix4, addr_str, + sizeof (addr_str)); + zlog_debug + ("%s %s: could not find interface for ifindex %d (address %s)", + __FILE__, __PRETTY_FUNCTION__, first_ifindex, addr_str); + } + if (nh_iter == mod_val) + mod_val++; //Select nexthpath + nh_iter++; + continue; + } + if (!ifp->info) + { + if (PIM_DEBUG_ZEBRA) + { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", src->u.prefix4, addr_str, + sizeof (addr_str)); + zlog_debug + ("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", + __PRETTY_FUNCTION__, ifp->name, first_ifindex, addr_str); + } + if (nh_iter == mod_val) + mod_val++; //Select nexthpath + nh_iter++; + continue; + } + + if (neighbor_needed + && !pim_if_connected_to_source (ifp, src->u.prefix4)) + { + nbr = pim_neighbor_find (ifp, nh_node->gate.ipv4); + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_debug ("ifp name: %s, pim nbr: %p", ifp->name, nbr); + if (!nbr && !if_is_loopback (ifp)) + { + if (PIM_DEBUG_ZEBRA) + zlog_debug + ("%s: pim nbr not found on input interface %s", + __PRETTY_FUNCTION__, ifp->name); + if (nh_iter == mod_val) + mod_val++; //Select nexthpath + nh_iter++; + continue; + } + } + + if (nh_iter == mod_val) + { + nexthop->interface = ifp; + nexthop->mrib_nexthop_addr.family = AF_INET; + nexthop->mrib_nexthop_addr.prefixlen = IPV4_MAX_BITLEN; + nexthop->mrib_nexthop_addr.u.prefix4 = nh_node->gate.ipv4; + nexthop->mrib_metric_preference = pnc->distance; + nexthop->mrib_route_metric = pnc->metric; + nexthop->last_lookup = src->u.prefix4; + nexthop->last_lookup_time = pim_time_monotonic_usec (); + nexthop->nbr = nbr; + found = 1; + + if (PIM_DEBUG_ZEBRA) + { + char buf[NEXTHOP_STRLEN]; + char buf2[PREFIX2STR_BUFFER]; + char buf3[PREFIX2STR_BUFFER]; + char buf4[PREFIX2STR_BUFFER]; + pim_inet4_dump ("", src->u.prefix4, buf2, sizeof (buf2)); + if (grp) + pim_inet4_dump ("", grp->u.prefix4, buf3, + sizeof (buf3)); + pim_inet4_dump ("", + nexthop->mrib_nexthop_addr.u.prefix4, buf4, + sizeof (buf4)); + snprintf (buf, sizeof (buf), "%s if %u", + inet_ntoa (nh_node->gate.ipv4), nh_node->ifindex); + zlog_debug + ("%s: NHT %s %s selected nhop interface %s nhop %s (%s) mod_val:%u iter:%d ecmp_enable:%d", + __PRETTY_FUNCTION__, buf2, grp ? buf3 : " ", ifp->name, + buf, buf4, mod_val, nh_iter, qpim_ecmp_enable); + } + } + nh_iter++; + + } + + return 0; +} + +/* This API is used to parse Registered address nexthop update coming from Zebra */ int pim_parse_nexthop_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) @@ -437,7 +681,6 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, struct stream *s; struct prefix p; struct nexthop *nexthop; - struct nexthop *oldnh; struct nexthop *nhlist_head = NULL; struct nexthop *nhlist_tail = NULL; uint32_t metric, distance; @@ -476,8 +719,9 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, { char buf[PREFIX2STR_BUFFER]; prefix2str (&rpf.rpf_addr, buf, sizeof (buf)); - zlog_debug ("%s: NHT addr %s is not in local cached DB.", - __PRETTY_FUNCTION__, buf); + zlog_debug + ("%s: Skipping NHT update, addr %s is not in local cached DB.", + __PRETTY_FUNCTION__, buf); } return 0; } @@ -490,7 +734,7 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, return 0; } - pnc->last_update = pim_time_monotonic_sec (); + pnc->last_update = pim_time_monotonic_usec (); distance = stream_getc (s); metric = stream_getl (s); nexthop_num = stream_getc (s); @@ -499,17 +743,15 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, { char buf[PREFIX2STR_BUFFER]; prefix2str (&p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d", - __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id, - listcount (pnc->upstream_list), listcount (pnc->rp_list)); + zlog_debug + ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d", + __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id, + listcount (pnc->upstream_list), listcount (pnc->rp_list)); } if (nexthop_num) { - pnc->flags |= PIM_NEXTHOP_VALID; - pnc->distance = distance; - pnc->metric = metric; - pnc->nexthop_num = nexthop_num; + pnc->nexthop_num = 0; //Only increment for pim enabled rpf. for (i = 0; i < nexthop_num; i++) { @@ -539,7 +781,34 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, (nexthop->ifindex, VRF_DEFAULT)); /* Overwrite with Nbr address as NH addr */ if (nbr) - nexthop->gate.ipv4 = nbr->source_addr; + { + nexthop->gate.ipv4 = nbr->source_addr; + if (PIM_DEBUG_TRACE) + { + char str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", nbr->source_addr, str, + sizeof (str)); + zlog_debug + ("%s: NHT using pim nbr addr %s ifindex %d as rpf", + __PRETTY_FUNCTION__, str, nexthop->ifindex); + } + } + else + { + if (PIM_DEBUG_TRACE) + { + struct interface *ifp1 = + if_lookup_by_index (nexthop->ifindex, + VRF_DEFAULT); + struct pim_interface *pim_ifp = ifp1->info; + zlog_debug + ("%s: NHT pim nbr not found on interface %s nbr count:%d ", + __PRETTY_FUNCTION__, ifp1->name, + pim_ifp->pim_neighbor_list->count); + } + //Mark nexthop address to 0 until PIM Nbr is resolved. + nexthop->gate.ipv4.s_addr = PIM_NET_INADDR_ANY; + } break; default: @@ -562,9 +831,10 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[NEXTHOP_STRLEN]; - zlog_debug("%s: could not find interface for ifindex %d (addr %s)", - __PRETTY_FUNCTION__, - nexthop->ifindex, nexthop2str (nexthop, buf, sizeof (buf))); + zlog_debug + ("%s: could not find interface for ifindex %d (addr %s)", + __PRETTY_FUNCTION__, nexthop->ifindex, + nexthop2str (nexthop, buf, sizeof (buf))); } nexthop_free (nexthop); continue; @@ -594,14 +864,18 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, nhlist_tail = nexthop; nhlist_head = nexthop; } - - for (oldnh = pnc->nexthop; oldnh; oldnh = oldnh->next) - if (nexthop_same_no_recurse (oldnh, nexthop)) - break; + //Only keep track of nexthops which are PIM enabled. + pnc->nexthop_num++; } /* Reset existing pnc->nexthop before assigning new list */ nexthops_free (pnc->nexthop); pnc->nexthop = nhlist_head; + if (pnc->nexthop_num) + { + pnc->flags |= PIM_NEXTHOP_VALID; + pnc->distance = distance; + pnc->metric = metric; + } } else { @@ -611,6 +885,16 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, pnc->nexthop = NULL; } + if (PIM_DEBUG_TRACE) + { + char buf[PREFIX2STR_BUFFER]; + prefix2str (&p, buf, sizeof (buf)); + zlog_debug + ("%s: NHT Update for %s nexthop_num:%d pim nexthop_num %d vrf:%d up %d rp %d", + __PRETTY_FUNCTION__, buf, nexthop_num, pnc->nexthop_num, vrf_id, + listcount (pnc->upstream_list), listcount (pnc->rp_list)); + } + pim_rpf_set_refresh_time (); if (listcount (pnc->rp_list)) @@ -620,3 +904,142 @@ pim_parse_nexthop_update (int command, struct zclient *zclient, return 0; } + +int +pim_ecmp_nexthop_lookup (struct pim_nexthop *nexthop, struct in_addr addr, + struct prefix *src, struct prefix *grp, + int neighbor_needed) +{ + struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; + struct pim_neighbor *nbr = NULL; + int num_ifindex; + struct interface *ifp; + int first_ifindex; + int found = 0; + uint8_t i = 0; + uint32_t hash_val = 0, mod_val = 0; + + if (PIM_DEBUG_TRACE) + { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", addr, addr_str, sizeof (addr_str)); + zlog_debug ("%s: Looking up: %s, last lookup time: %lld", + __PRETTY_FUNCTION__, addr_str, nexthop->last_lookup_time); + } + + memset (nexthop_tab, 0, + sizeof (struct pim_zlookup_nexthop) * MULTIPATH_NUM); + num_ifindex = + zclient_lookup_nexthop (nexthop_tab, MULTIPATH_NUM, addr, + PIM_NEXTHOP_LOOKUP_MAX); + if (num_ifindex < 1) + { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", addr, addr_str, sizeof (addr_str)); + zlog_warn ("%s %s: could not find nexthop ifindex for address %s", + __FILE__, __PRETTY_FUNCTION__, addr_str); + return -1; + } + + //If PIM ECMP enable then choose ECMP path + if (qpim_ecmp_enable) + { + hash_val = pim_compute_ecmp_hash (src, grp); + mod_val = hash_val % num_ifindex; + if (PIM_DEBUG_TRACE) + zlog_debug ("%s: hash_val %u mod_val %u ", + __PRETTY_FUNCTION__, hash_val, mod_val); + } + + while (!found && (i < num_ifindex)) + { + first_ifindex = nexthop_tab[i].ifindex; + + ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT); + if (!ifp) + { + if (PIM_DEBUG_ZEBRA) + { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", addr, addr_str, sizeof (addr_str)); + zlog_debug + ("%s %s: could not find interface for ifindex %d (address %s)", + __FILE__, __PRETTY_FUNCTION__, first_ifindex, addr_str); + } + if (i == mod_val) + mod_val++; + i++; + continue; + } + + if (!ifp->info) + { + if (PIM_DEBUG_ZEBRA) + { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", addr, addr_str, sizeof (addr_str)); + zlog_debug + ("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", + __PRETTY_FUNCTION__, ifp->name, first_ifindex, addr_str); + } + if (i == mod_val) + mod_val++; + i++; + continue; + } + if (neighbor_needed && !pim_if_connected_to_source (ifp, addr)) + { + nbr = + pim_neighbor_find (ifp, nexthop_tab[i].nexthop_addr.u.prefix4); + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_debug ("ifp name: %s, pim nbr: %p", ifp->name, nbr); + if (!nbr && !if_is_loopback (ifp)) + { + if (i == mod_val) + mod_val++; + i++; + if (PIM_DEBUG_ZEBRA) + { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", addr, addr_str, + sizeof (addr_str)); + zlog_debug + ("%s: NBR not found on input interface %s (RPF for source %s)", + __PRETTY_FUNCTION__, ifp->name, addr_str); + } + continue; + } + } + + if (i == mod_val) + { + if (PIM_DEBUG_ZEBRA) + { + char nexthop_str[PREFIX_STRLEN]; + char addr_str[INET_ADDRSTRLEN]; + pim_addr_dump ("", &nexthop_tab[i].nexthop_addr, + nexthop_str, sizeof (nexthop_str)); + pim_inet4_dump ("", addr, addr_str, sizeof (addr_str)); + zlog_debug + ("%s %s: found nexthop %s for addr %s interface %s metric=%d pref=%d", + __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str, + ifp->name, nexthop_tab[i].route_metric, + nexthop_tab[i].protocol_distance); + } + /* update nextop data */ + nexthop->interface = ifp; + nexthop->mrib_nexthop_addr = nexthop_tab[i].nexthop_addr; + nexthop->mrib_metric_preference = nexthop_tab[i].protocol_distance; + nexthop->mrib_route_metric = nexthop_tab[i].route_metric; + nexthop->last_lookup = addr; + nexthop->last_lookup_time = pim_time_monotonic_usec(); + nexthop->nbr = nbr; + found = 1; + } + i++; + } + if (found) + return 0; + else + return -1; +} diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index 5348ec3704..b4b2d91e47 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -51,10 +51,19 @@ struct pim_nexthop_cache int pim_parse_nexthop_update (int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id); int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp); + struct rp_info *rp, struct pim_nexthop_cache *out_pnc); void pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up, struct rp_info *rp); struct pim_nexthop_cache *pim_nexthop_cache_add (struct pim_rpf *rpf_addr); struct pim_nexthop_cache *pim_nexthop_cache_find (struct pim_rpf *rpf); - +uint32_t pim_compute_ecmp_hash (struct prefix *src, struct prefix *grp); +int pim_ecmp_nexthop_search (struct pim_nexthop_cache * pnc, + struct pim_nexthop *nexthop, struct prefix *src, + struct prefix *grp, int neighbor_needed); +int pim_ecmp_nexthop_lookup (struct pim_nexthop *nexthop, struct in_addr addr, + struct prefix *src, struct prefix *grp, + int neighbor_needed); +void pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc, + int command); +void pim_resolve_upstream_nh (struct prefix *nht_p); #endif diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 2701079053..2d4aa3febc 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -289,10 +289,10 @@ pim_channel_del_oif (struct channel_oil *channel_oil, char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); - zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", + zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, - proto_mask, oif->name, pim_ifp->mroute_vif_index); + proto_mask, channel_oil->oil.mfcc_parent ,oif->name, pim_ifp->mroute_vif_index); } return 0; diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 65a3e8714f..12f8dd53f2 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -187,6 +187,15 @@ pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct return; } + if (PIM_DEBUG_PIM_REG) + { + char rp_str[INET_ADDRSTRLEN]; + strcpy (rp_str, inet_ntoa (rpg->rpf_addr.u.prefix4)); + zlog_debug ("%s: Sending %s %sRegister Packet to %s on %s", + __PRETTY_FUNCTION__, up->sg_str, + null_register ? "NULL " : "", rp_str, ifp->name); + } + memset(buffer, 0, 10000); b1 = buffer + PIM_MSG_HEADER_LEN; *b1 |= null_register << 6; diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 78bbd14405..ec31069eb5 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -30,6 +30,7 @@ #include "vty.h" #include "vrf.h" #include "plist.h" +#include "nexthop.h" #include "pimd.h" #include "pim_vty.h" @@ -280,7 +281,7 @@ pim_rp_check_interfaces (struct rp_info *rp_info) int pim_rp_new (const char *rp, const char *group_range, const char *plist) { - int result; + int result, ret = 0; struct rp_info *rp_info; struct rp_info *rp_all; struct prefix group_all; @@ -288,6 +289,7 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist) struct rp_info *tmp_rp_info; char buffer[BUFSIZ]; struct prefix nht_p; + struct pim_nexthop_cache pnc; rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info)); if (!rp_info) @@ -387,21 +389,31 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist) /* Register addr with Zebra NHT */ nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4; + nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4; //RP address if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX2STR_BUFFER]; + char buf1[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Register rp_all addr %s with NHT ", - __PRETTY_FUNCTION__, buf); + prefix2str (&rp_all->group, buf1, sizeof (buf1)); + zlog_debug ("%s: NHT Register rp_all addr %s grp %s ", + __PRETTY_FUNCTION__, buf, buf1); + } + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((ret = + pim_find_or_track_nexthop (&nht_p, NULL, rp_all, &pnc)) == 1) + { + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &rp_all->rp.source_nexthop, + &nht_p, &rp_all->group, 1); + } + else + { + if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0) + return PIM_RP_NO_PATH; } - pim_find_or_track_nexthop (&nht_p, NULL, rp_all); - - if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0) - return PIM_RP_NO_PATH; - pim_rp_check_interfaces (rp_all); - pim_rp_refresh_group_to_rp_mapping(); + pim_rp_refresh_group_to_rp_mapping (); return PIM_SUCCESS; } @@ -451,13 +463,25 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist) if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX2STR_BUFFER]; + char buf1[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: NHT Register RP addr %s with Zebra ", __PRETTY_FUNCTION__, buf); + prefix2str (&rp_info->group, buf1, sizeof (buf1)); + zlog_debug ("%s: NHT Register RP addr %s grp %s with Zebra ", + __PRETTY_FUNCTION__, buf, buf1); } - pim_find_or_track_nexthop (&nht_p, NULL, rp_info); - if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) - return PIM_RP_NO_PATH; + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1) + { + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop, + &nht_p, &rp_info->group, 1); + } + else + { + if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) + return PIM_RP_NO_PATH; + } pim_rp_check_interfaces (rp_info); pim_rp_refresh_group_to_rp_mapping (); @@ -509,7 +533,8 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist) { char buf[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: Deregister RP addr %s with NHT ", __PRETTY_FUNCTION__, buf); + zlog_debug ("%s: Deregister RP addr %s with Zebra ", __PRETTY_FUNCTION__, + buf); } pim_delete_tracked_nexthop (&nht_p, NULL, rp_info); @@ -535,17 +560,39 @@ pim_rp_setup (void) struct listnode *node; struct rp_info *rp_info; int ret = 0; + struct prefix nht_p; + struct pim_nexthop_cache pnc; for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info)) { if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) continue; - if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug ("Unable to lookup nexthop for rp specified"); - ret++; + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop, + &nht_p, &rp_info->group, 1); + } + else + { + if (PIM_DEBUG_ZEBRA) + { + char buf[PREFIX2STR_BUFFER]; + prefix2str (&nht_p, buf, sizeof (buf)); + zlog_debug ("%s: NHT Local Nexthop not found for RP %s ", + __PRETTY_FUNCTION__, buf); + } + if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) + { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug ("Unable to lookup nexthop for rp specified"); + ret++; + } } } @@ -680,7 +727,43 @@ pim_rp_g (struct in_addr group) if (rp_info) { - pim_nexthop_lookup(&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1); + int ret = 0; + struct prefix nht_p; + struct pim_nexthop_cache pnc; + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + if (PIM_DEBUG_PIM_TRACE) + { + char buf[PREFIX2STR_BUFFER]; + char buf1[PREFIX2STR_BUFFER]; + prefix2str (&nht_p, buf, sizeof (buf)); + prefix2str (&rp_info->group, buf1, sizeof (buf1)); + zlog_debug ("%s: NHT Register RP addr %s grp %s with Zebra ", + __PRETTY_FUNCTION__, buf, buf1); + } + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1) + { + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop, + &nht_p, &rp_info->group, 1); + } + else + { + if (PIM_DEBUG_ZEBRA) + { + char buf[PREFIX2STR_BUFFER]; + char buf1[PREFIX2STR_BUFFER]; + prefix2str (&nht_p, buf, sizeof (buf)); + prefix2str (&g, buf1, sizeof (buf1)); + zlog_debug ("%s: NHT nexthop cache not found for RP %s grp %s", + __PRETTY_FUNCTION__, buf, buf1); + } + pim_rpf_set_refresh_time (); + pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1); + } return (&rp_info->rp); } @@ -862,3 +945,54 @@ pim_rp_show_information (struct vty *vty, u_char uj) json_object_free(json); } } + +void +pim_resolve_rp_nh (void) +{ + struct listnode *node = NULL; + struct rp_info *rp_info = NULL; + struct nexthop *nh_node = NULL; + struct prefix nht_p; + struct pim_nexthop_cache pnc; + struct pim_neighbor *nbr = NULL; + + for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info)) + { + if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) + continue; + + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1) + { + for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) + { + if (nh_node->gate.ipv4.s_addr == 0) + { + nbr = + pim_neighbor_find_if (if_lookup_by_index + (nh_node->ifindex, VRF_DEFAULT)); + if (nbr) + { + nh_node->gate.ipv4 = nbr->source_addr; + if (PIM_DEBUG_TRACE) + { + char str[PREFIX_STRLEN]; + char str1[INET_ADDRSTRLEN]; + pim_inet4_dump ("", nbr->source_addr, + str1, sizeof (str1)); + pim_addr_dump ("", &nht_p, str, + sizeof (str)); + zlog_debug + ("%s: addr %s new nexthop addr %s ifindex %d ", + __PRETTY_FUNCTION__, str, str1, + nh_node->ifindex); + } + } + } + } + } + } +} diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 84ab9be482..df18c998d6 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -61,6 +61,6 @@ struct pim_rpf *pim_rp_g (struct in_addr group); #define RP(G) pim_rp_g ((G)) void pim_rp_show_information (struct vty *vty, u_char uj); - +void pim_resolve_rp_nh (void); int pim_rp_list_cmp (void *v1, void *v2); #endif diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 400048738a..0f5fab0d93 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -67,11 +67,14 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int nei { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); - zlog_debug ("%s: Using last lookup for %s at %lld, %lld", + char nexthop_str[PREFIX_STRLEN]; + pim_addr_dump("", &nexthop->mrib_nexthop_addr, + nexthop_str, sizeof(nexthop_str)); + zlog_debug ("%s: Using last lookup for %s at %lld, %lld addr%s", __PRETTY_FUNCTION__, addr_str, nexthop->last_lookup_time, - last_route_change_time); + last_route_change_time, nexthop_str); } nexthop_lookups_avoided++; return 0; @@ -190,32 +193,56 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, struct pim_rpf *rpf = &up->rpf; struct pim_rpf saved; struct prefix nht_p; + struct pim_nexthop_cache pnc; + int ret = 0; + struct prefix src, grp; saved.source_nexthop = rpf->source_nexthop; saved.rpf_addr = rpf->rpf_addr; - if (is_new) + if (is_new && PIM_DEBUG_ZEBRA) { - if (PIM_DEBUG_ZEBRA) - { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", up->upstream_addr, source_str, sizeof(source_str)); - zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.", - __PRETTY_FUNCTION__, up->sg_str, source_str); - } - /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; - pim_find_or_track_nexthop (&nht_p, up, NULL); + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump ("", up->upstream_addr, source_str, + sizeof (source_str)); + zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.", + __PRETTY_FUNCTION__, up->sg_str, source_str); } + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; - if (pim_nexthop_lookup(&rpf->source_nexthop, - up->upstream_addr, - !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) && - !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) { - return PIM_RPF_FAILURE; - } + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = up->upstream_addr; //RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + memset (&pnc, 0, sizeof (struct pim_nexthop_cache)); + if ((ret = pim_find_or_track_nexthop (&nht_p, up, NULL, &pnc)) == 1) + { + if (pnc.nexthop_num) + { + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&pnc, &up->rpf.source_nexthop, + &src, &grp, + !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) && + !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up-> + flags)); + } + } + else + { + if (pim_ecmp_nexthop_lookup (&rpf->source_nexthop, + up->upstream_addr, &src, &grp, + !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) && + !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up-> + flags))) + { + return PIM_RPF_FAILURE; + } + } rpf->rpf_addr.family = AF_INET; rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 172d0d21c9..c9c2795762 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -227,8 +227,8 @@ pim_upstream_del(struct pim_upstream *up, const char *name) { char buf[PREFIX2STR_BUFFER]; prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ", - __PRETTY_FUNCTION__, up->sg_str, buf); + zlog_debug ("%s: Deregister upstream %s addr %s with Zebra", + __PRETTY_FUNCTION__, up->sg_str, buf); } pim_delete_tracked_nexthop (&nht_p, up, NULL); @@ -694,10 +694,12 @@ pim_upstream_new (struct prefix_sg *sg, return NULL; } - pim_ifp = up->rpf.source_nexthop.interface->info; - if (pim_ifp) - up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index); - + if (up->rpf.source_nexthop.interface) + { + pim_ifp = up->rpf.source_nexthop.interface->info; + if (pim_ifp) + up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index); + } listnode_add_sort(pim_upstream_list, up); if (PIM_DEBUG_TRACE) @@ -768,10 +770,14 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, if (PIM_DEBUG_TRACE) { if (up) - zlog_debug("%s(%s): %s, found: %d: ref_count: %d", + { + char buf[PREFIX2STR_BUFFER]; + prefix2str (&up->rpf.rpf_addr, buf, sizeof (buf)); + zlog_debug("%s(%s): %s, iif %s found: %d: ref_count: %d", __PRETTY_FUNCTION__, name, - up->sg_str, found, + up->sg_str, buf, found, up->ref_count); + } else zlog_debug("%s(%s): (%s) failure to create", __PRETTY_FUNCTION__, name, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 4e18c478d6..80e7d77642 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -372,6 +372,12 @@ static void scan_upstream_rpf_cache() for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { enum pim_rpf_result rpf_result; struct pim_rpf old; + struct prefix nht_p; + + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + pim_resolve_upstream_nh (&nht_p); old.source_nexthop.interface = up->rpf.source_nexthop.interface; old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; @@ -574,7 +580,8 @@ static int on_rpf_cache_refresh(struct thread *t) qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); ++qpim_rpf_cache_refresh_events; - pim_rp_setup (); + //It is called as part of pim_neighbor_add + //pim_rp_setup (); return 0; } @@ -836,6 +843,7 @@ void igmp_source_forward_start(struct igmp_source *source) struct igmp_group *group; struct prefix_sg sg; int result; + int input_iface_vif_index = 0; memset (&sg, 0, sizeof (struct prefix_sg)); sg.src = source->source_addr; @@ -861,11 +869,61 @@ void igmp_source_forward_start(struct igmp_source *source) if (!source->source_channel_oil) { struct in_addr vif_source; struct pim_interface *pim_oif; + struct prefix nht_p, src, grp; + int ret = 0; + struct pim_nexthop_cache out_pnc; + struct pim_nexthop nexthop; if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp)) return; - int input_iface_vif_index = fib_lookup_if_vif_index(vif_source); + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = vif_source; + memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache)); + + if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1) + { + if (out_pnc.nexthop_num) + { + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = vif_source; //RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = sg.grp; + memset (&nexthop, 0, sizeof (nexthop)); + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&out_pnc, &nexthop, + &src, &grp, 0); + if (nexthop.interface) + input_iface_vif_index = pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex); + } + else + { + if (PIM_DEBUG_ZEBRA) + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + pim_inet4_dump("", nht_p.u.prefix4, buf1, sizeof(buf1)); + pim_inet4_dump("", grp.u.prefix4, buf2, sizeof(buf2)); + zlog_debug ("%s: NHT Nexthop not found for addr %s grp %s" , + __PRETTY_FUNCTION__, buf1, buf2); + } + } + } + else + input_iface_vif_index = fib_lookup_if_vif_index(vif_source); + + if (PIM_DEBUG_ZEBRA) + { + char buf2[INET_ADDRSTRLEN]; + pim_inet4_dump("", vif_source, buf2, sizeof(buf2)); + zlog_debug ("%s: NHT %s vif_source %s vif_index:%d ", __PRETTY_FUNCTION__, + pim_str_sg_dump (&sg), buf2, input_iface_vif_index); + } + if (input_iface_vif_index < 1) { if (PIM_DEBUG_IGMP_TRACE) { @@ -1013,49 +1071,105 @@ void pim_forward_start(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; uint32_t mask = PIM_OIF_FLAG_PROTO_PIM; + int input_iface_vif_index = 0; if (PIM_DEBUG_PIM_TRACE) { char source_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; + char group_str[INET_ADDRSTRLEN]; char upstream_str[INET_ADDRSTRLEN]; pim_inet4_dump("", ch->sg.src, source_str, sizeof(source_str)); pim_inet4_dump("", ch->sg.grp, group_str, sizeof(group_str)); pim_inet4_dump("", up->upstream_addr, upstream_str, sizeof(upstream_str)); - zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)", + zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name, upstream_str); } - if (!up->channel_oil) { - int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr); - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_PIM_TRACE) - { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", up->sg.src, source_str, sizeof(source_str)); - zlog_debug("%s %s: could not find input interface for source %s", - __FILE__, __PRETTY_FUNCTION__, - source_str); - } - return; - } + /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS, + as part of mroute_del called by pim_forward_stop. + */ + if (!up->channel_oil || + (up->channel_oil && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) + { + struct prefix nht_p, src, grp; + int ret = 0; + struct pim_nexthop_cache out_pnc; + struct pim_nexthop nexthop; - up->channel_oil = pim_channel_oil_add(&up->sg, - input_iface_vif_index); - if (!up->channel_oil) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s %s: could not create OIL for channel (S,G)=%s", - __FILE__, __PRETTY_FUNCTION__, - up->sg_str); - return; + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache)); + + if ((ret = + pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1) + { + if (out_pnc.nexthop_num) + { + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = up->upstream_addr; //RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + memset (&nexthop, 0, sizeof (nexthop)); + //Compute PIM RPF using Cached nexthop + pim_ecmp_nexthop_search (&out_pnc, &nexthop, &src, &grp, 0); + input_iface_vif_index = + pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex); + } + else + { + if (PIM_DEBUG_ZEBRA) + { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + pim_inet4_dump("", nht_p.u.prefix4, buf1, sizeof(buf1)); + pim_inet4_dump("", grp.u.prefix4, buf2, sizeof(buf2)); + zlog_debug ("%s: NHT pnc is NULL for addr %s grp %s" , + __PRETTY_FUNCTION__, buf1, buf2); + } + } + } + else + input_iface_vif_index = fib_lookup_if_vif_index (up->upstream_addr); + + if (input_iface_vif_index < 1) + { + if (PIM_DEBUG_PIM_TRACE) + { + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", up->sg.src, source_str, sizeof(source_str)); + zlog_debug("%s %s: could not find input interface for source %s", + __FILE__, __PRETTY_FUNCTION__, + source_str); + } + return; + } + if (PIM_DEBUG_TRACE) + { + zlog_debug ("%s: NHT entry %s update channel_oil vif_index %d ", + __PRETTY_FUNCTION__, up->sg_str, input_iface_vif_index); + } + up->channel_oil = pim_channel_oil_add (&up->sg, input_iface_vif_index); + if (!up->channel_oil) + { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug ("%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, __PRETTY_FUNCTION__, up->sg_str); + return; + } } - } if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) mask = PIM_OIF_FLAG_PROTO_IGMP; - pim_channel_add_oif(up->channel_oil, ch->interface, mask); + pim_channel_add_oif (up->channel_oil, ch->interface, mask); } void pim_forward_stop(struct pim_ifchannel *ch) diff --git a/pimd/pimd.c b/pimd/pimd.c index bdbd251e20..653856665c 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -75,7 +75,9 @@ unsigned int qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD; signed int qpim_rp_keep_alive_time = 0; int64_t qpim_nexthop_lookups = 0; int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS; -struct pim_instance *pimg = NULL; +uint8_t qpim_ecmp_enable = 0; +uint8_t qpim_ecmp_rebalance_enable = 0; +struct pim_instance *pimg = NULL; int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT; diff --git a/pimd/pimd.h b/pimd/pimd.h index 69aee28f8f..d1ada02203 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -155,6 +155,9 @@ struct list *qpim_static_route_list; /* list of routes added static extern unsigned int qpim_keep_alive_time; extern signed int qpim_rp_keep_alive_time; extern int qpim_packet_process; +extern uint8_t qpim_ecmp_enable; +extern uint8_t qpim_ecmp_rebalance_enable; + #define PIM_DEFAULT_PACKET_PROCESS 3 #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) From 4390fb9991e78d759c25ffc23be378c8b9242614 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 6 Apr 2017 17:57:24 -0400 Subject: [PATCH 23/34] pimd: Fix various sizeof and buffer length issues Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 12 ++++++++---- pimd/pim_tlv.c | 2 +- pimd/pim_zlookup.c | 8 ++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 627971d3f9..0478dc1b48 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -830,7 +830,9 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch sec_list = json_object_new_array(); for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) { json_object_array_add(sec_list, - json_object_new_string(prefix2str(&sec_addr->addr, pbuf, PREFIX2STR_BUFFER))); + json_object_new_string(prefix2str(&sec_addr->addr, + pbuf, + sizeof(pbuf)))); } json_object_object_add(json_row, "secondaryAddressList", sec_list); } @@ -926,7 +928,9 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch inet_ntoa(ifaddr), VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) { vty_out(vty, " %s%s", - prefix2str(&sec_addr->addr, pbuf, PREFIX2STR_BUFFER), VTY_NEWLINE); + prefix2str(&sec_addr->addr, + pbuf, + sizeof(pbuf)), VTY_NEWLINE); } } else { vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE); @@ -1611,9 +1615,9 @@ static void pim_show_neighbors_secondary(struct vty *vty) neigh_src_str, sizeof(neigh_src_str)); for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) { - char neigh_sec_str[100]; + char neigh_sec_str[PREFIX2STR_BUFFER]; - prefix2str(p, neigh_sec_str, 100); + prefix2str(p, neigh_sec_str, sizeof(neigh_sec_str)); vty_out(vty, "%-9s %-15s %-15s %-15s%s", ifp->name, diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 1d58ce3ac6..259ed44c71 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -523,7 +523,7 @@ pim_parse_addr_ucast (struct prefix *p, p->family = AF_INET6; p->prefixlen = IPV6_MAX_PREFIXLEN; - memcpy(&p->u.prefix6, addr, 16); + memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr)); addr += sizeof(struct in6_addr); break; diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 620137b33b..27bd137043 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -252,12 +252,16 @@ static int zclient_read_nexthop(struct zclient *zlookup, break; case NEXTHOP_TYPE_IPV6_IFINDEX: nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6; - stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16); + stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, + s, + sizeof(struct in6_addr)); nexthop_tab[num_ifindex].ifindex = stream_getl (s); p.family = AF_INET6; p.prefixlen = IPV6_MAX_PREFIXLEN; - memcpy (&p.u.prefix6, &nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, 16); + memcpy (&p.u.prefix6, + &nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, + sizeof(struct in6_addr)); /* * If we are sending v6 secondary assume we receive v6 secondary From 073845da5e32aa15b9636bcbe7be994e2bd7f8b4 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Fri, 7 Apr 2017 17:40:11 +0000 Subject: [PATCH 24/34] lib: add #pragma's to ignore flex sign cmp error Signed-off-by: Quentin Young --- lib/command_lex.l | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/command_lex.l b/lib/command_lex.l index deec1757c2..c020d193a1 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -23,6 +23,9 @@ */ %{ +/* ignore harmless bug in old versions of flex */ +#pragma GCC diagnostic ignored "-Wsign-compare" + #include "command_parse.h" #define YY_USER_ACTION yylloc->last_column += yyleng; From 6be4da3dfac66de52b48d8fb56e24fa35b9a24ea Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 8 Apr 2017 08:47:59 -0400 Subject: [PATCH 25/34] ospfd: Fix the 'show ip ospf int ...' command Fixed output: robot.cumulusnetworks.com# show ip ospf int enp0s3 is up ifindex 2, MTU 1500 bytes, BW 0 Mbit Internet Address 10.0.2.15/24, Broadcast 10.0.2.255, Area 0.0.0.0 MTU mismatch detection:enabled Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 Transmit Delay is 1 sec, State Waiting, Priority 1 No backup designated router on this network Multicast group memberships: OSPFAllRouters Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5 Hello due in 9.611s Neighbor Count is 0, Adjacent neighbor count is 0 enp0s10 is up ifindex 7, MTU 1500 bytes, BW 0 Mbit Internet Address 192.168.201.146/24, Broadcast 192.168.201.255, Area 0.0.0.0 MTU mismatch detection:enabled Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 Transmit Delay is 1 sec, State Waiting, Priority 1 No backup designated router on this network Multicast group memberships: OSPFAllRouters Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5 Hello due in 7.241s Neighbor Count is 0, Adjacent neighbor count is 0 robot.cumulusnetworks.com# show ip ospf int enp0s3 enp0s3 is up ifindex 2, MTU 1500 bytes, BW 0 Mbit Internet Address 10.0.2.15/24, Broadcast 10.0.2.255, Area 0.0.0.0 MTU mismatch detection:enabled Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 Transmit Delay is 1 sec, State Waiting, Priority 1 No backup designated router on this network Multicast group memberships: OSPFAllRouters Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5 Hello due in 2.915s Neighbor Count is 0, Adjacent neighbor count is 0 robot.cumulusnetworks.com# show ip ospf int enp0s10 json { "enp0s10":{ "ifUp":true, "ifIndex":7, "mtuBytes":1500, "bandwidthMbit":0, "ifFlags":"", "ospfEnabled":true, "ipAddress":"192.168.201.146", "ipAddressPrefixlen":24, "ospfIfType":"Broadcast", "localIfUsed":"192.168.201.255", "area":"0.0.0.0", "routerId":"192.168.0.1", "networkType":"BROADCAST", "cost":10, "transmitDelayMsecs":1000, "state":"Waiting", "priority":1, "mcastMemberOspfAllRouters":true, "timerMsecs":100, "timerDeadMsecs":25, "timerWaitMsecs":25, "timerRetransmit":200, "timerHelloInMsecs":2106, "nbrCount":0, "nbrAdjacentCount":0 } } robot.cumulusnetworks.com# Signed-off-by: Donald Sharp --- ospfd/ospf_vty.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 49474df826..b4c456e0aa 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3557,7 +3557,7 @@ show_ip_ospf_interface_common (struct vty *vty, struct ospf *ospf, int argc, VTY_NEWLINE, VTY_NEWLINE); } - if (argc == (iface_argv + 1)) + if (argc == iface_argv) { /* Show All Interfaces.*/ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) @@ -3570,25 +3570,6 @@ show_ip_ospf_interface_common (struct vty *vty, struct ospf *ospf, int argc, } } } - else if (argv[iface_argv] && strcmp(argv[iface_argv]->arg, "json") == 0) - { - if (!use_json) - { - json = json_object_new_object(); - json_interface_sub = json_object_new_object (); - use_json = 1; - } - /* Show All Interfaces. */ - for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) - { - if (ospf_oi_count(ifp)) - { - show_ip_ospf_interface_sub (vty, ospf, ifp, json_interface_sub, use_json); - if (use_json) - json_object_object_add(json, ifp->name, json_interface_sub); - } - } - } else { /* Interface name is specified. */ @@ -3634,7 +3615,10 @@ DEFUN (show_ip_ospf_interface, if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running) return CMD_SUCCESS; - return show_ip_ospf_interface_common(vty, ospf, argc, argv, 0, uj); + if (uj) + argc--; + + return show_ip_ospf_interface_common(vty, ospf, argc, argv, 4, uj); } DEFUN (show_ip_ospf_instance_interface, @@ -3657,7 +3641,10 @@ DEFUN (show_ip_ospf_instance_interface, if ((ospf = ospf_lookup_instance (instance)) == NULL || !ospf->oi_running) return CMD_SUCCESS; - return show_ip_ospf_interface_common(vty, ospf, argc, argv, 1, uj); + if (uj) + argc--; + + return show_ip_ospf_interface_common(vty, ospf, argc, argv, 5, uj); } static void From 08c08a35c6552e90aafcdd857ad17e9beecac61f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 8 Apr 2017 08:55:40 -0400 Subject: [PATCH 26/34] lib: Fix debugs to be guarded. Signed-off-by: Donald Sharp --- lib/zclient.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 71b95ae7db..d2a5186315 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1486,7 +1486,9 @@ lm_label_manager_connect (struct zclient *zclient) vrf_id_t vrf_id; u_int16_t cmd; - zlog_debug ("Connecting to Label Manager"); + if (zclient_debug) + zlog_debug ("Connecting to Label Manager"); + if (zclient->sock < 0) return -1; @@ -1518,7 +1520,8 @@ lm_label_manager_connect (struct zclient *zclient) zclient->sock = -1; return -1; } - zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret); + if (zclient_debug) + zlog_debug ("%s: Label manager connect request (%d bytes) sent", __func__, ret); /* read response */ s = zclient->ibuf; @@ -1532,8 +1535,9 @@ lm_label_manager_connect (struct zclient *zclient) } /* result */ result = stream_getc(s); - zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u", - __func__, size, result); + if (zclient_debug) + zlog_debug ("%s: Label Manager connect response (%d bytes) received, result %u", + __func__, size, result); return (int)result; } @@ -1564,7 +1568,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, u_int16_t cmd; u_char response_keep; - zlog_debug ("Getting Label Chunk"); + if (zclient_debug) + zlog_debug ("Getting Label Chunk"); + if (zclient->sock < 0) return -1; @@ -1594,7 +1600,8 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, zclient->sock = -1; return -1; } - zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret); + if (zclient_debug) + zlog_debug ("%s: Label chunk request (%d bytes) sent", __func__, ret); /* read response */ s = zclient->ibuf; @@ -1606,7 +1613,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, zlog_err ("%s: Invalid Get Label Chunk Message Reply Header", __func__); return -1; } - zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size); + if (zclient_debug) + zlog_debug ("%s: Label chunk response (%d bytes) received", __func__, size); + /* keep */ response_keep = stream_getc(s); /* start and end labels */ @@ -1627,8 +1636,9 @@ lm_get_label_chunk (struct zclient *zclient, u_char keep, uint32_t chunk_size, return -1; } - zlog_debug ("Label Chunk assign: %u - %u (%u) ", - *start, *end, response_keep); + if (zclient_debug) + zlog_debug ("Label Chunk assign: %u - %u (%u) ", + *start, *end, response_keep); return 0; } @@ -1647,7 +1657,9 @@ lm_release_label_chunk (struct zclient *zclient, uint32_t start, uint32_t end) int ret; struct stream *s; - zlog_debug ("Releasing Label Chunk"); + if (zclient_debug) + zlog_debug ("Releasing Label Chunk"); + if (zclient->sock < 0) return -1; From 2caafa8c6f815ae3018ce338c083fd75ff2a9102 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Sat, 8 Apr 2017 17:52:57 -0300 Subject: [PATCH 27/34] ripd: fix argv index numbers in the redistribute command Fixes Issue#350 Signed-off-by: Renato Westphal --- ripd/rip_zebra.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 7fa3baea7e..578c513c78 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -339,7 +339,7 @@ DEFUN (rip_redistribute_type, for(i = 0; redist_type[i].str; i++) { - if (strncmp (redist_type[i].str, argv[2]->arg, + if (strncmp (redist_type[i].str, argv[1]->arg, redist_type[i].str_min_len) == 0) { zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, @@ -348,7 +348,7 @@ DEFUN (rip_redistribute_type, } } - vty_out(vty, "Invalid type %s%s", argv[2]->arg, + vty_out(vty, "Invalid type %s%s", argv[1]->arg, VTY_NEWLINE); return CMD_WARNING; @@ -365,7 +365,7 @@ DEFUN (no_rip_redistribute_type, for (i = 0; redist_type[i].str; i++) { - if (strncmp(redist_type[i].str, argv[3]->arg, + if (strncmp(redist_type[i].str, argv[2]->arg, redist_type[i].str_min_len) == 0) { rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP); @@ -375,7 +375,7 @@ DEFUN (no_rip_redistribute_type, } } - vty_out(vty, "Invalid type %s%s", argv[3]->arg, + vty_out(vty, "Invalid type %s%s", argv[2]->arg, VTY_NEWLINE); return CMD_WARNING; From d536095fd34c8c14c7bd064dfb8f407256aad373 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Mon, 10 Apr 2017 12:28:45 -0300 Subject: [PATCH 28/34] bgpd: fixes for the "show bgp large-community" command * Fix a segfault when the "show bgp large-community" command is given without any optional large communities; * Fix parsing of optional large communities. Without this fix a "Large-community malformed" error is shown even for valid large communities. Signed-off-by: Renato Westphal --- bgpd/bgp_route.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 1fa3e8bc44..4e87ea1ece 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8171,7 +8171,7 @@ bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc, buffer_putc (b, ' '); else { - if (strmatch (argv[i]->text, "")) + if (strmatch (argv[i]->text, "AA:BB:CC")) { first = 1; buffer_putstr (b, argv[i]->arg); @@ -8187,7 +8187,7 @@ bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc, XFREE (MTYPE_TMP, str); if (! lcom) { - vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE); + vty_out (vty, "%% Large-community malformed%s", VTY_NEWLINE); return CMD_WARNING; } @@ -8299,8 +8299,7 @@ DEFUN (show_ip_bgp_large_community, return CMD_WARNING; } - argv_find (argv, argc, "large-community", &idx); - if (strmatch(argv[idx+1]->text, "AA:BB:CC")) + if (argv_find (argv, argc, "AA:BB:CC", &idx)) return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj); else return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj); From b6ab29296fc7dc5b0a6ad0e5345aca3c2c701cba Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 14 Apr 2017 20:13:26 -0400 Subject: [PATCH 29/34] bgpd: Fix 'set as-path prepend last-as 10' 1) Fix missing newline in help string 2) Make the ability to have 10 be consistent with the stable/2.0 branch. Signed-off-by: Donald Sharp --- bgpd/bgp_routemap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index bafc81eaf8..9b5a7a5ebb 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1437,7 +1437,7 @@ route_set_aspath_prepend_compile (const char *arg) { unsigned int num; - if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) + if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num <= 10) return (void*)(uintptr_t)num; return route_aspath_compile(arg); @@ -3677,12 +3677,12 @@ DEFUN (set_aspath_prepend_asn, DEFUN (set_aspath_prepend_lastas, set_aspath_prepend_lastas_cmd, - "set as-path prepend last-as (1-9)", + "set as-path prepend last-as (1-10)", SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "Use the peer's AS-number\n" - "Number of times to insert") + "Number of times to insert\n") { return set_aspath_prepend_asn (self, vty, argc, argv); } From 5260e25d2000dcd65b9e7f710f20482e1bb9f2df Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 14 Apr 2017 20:39:56 -0400 Subject: [PATCH 30/34] bgpd: 'show .... bgp regexp WORD' fixed The command was always just returning as part of the bgp_regexp_show function. Signed-off-by: Donald Sharp --- bgpd/bgp_route.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4e87ea1ece..32cf0bcb89 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8562,8 +8562,6 @@ static int bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi, safi_t safi, enum bgp_show_type type) { - return CMD_SUCCESS; - regex_t *regex; int rc; From 529aa94e24a39e8203efebbaf2fbc9f6de69fa52 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Sat, 15 Apr 2017 06:23:22 +0000 Subject: [PATCH 31/34] pimd: fix off-by-one in `no ip pim rp ...` Signed-off-by: Quentin Young --- pimd/pim_cmd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 0ce2525847..313414159c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -3640,10 +3640,10 @@ DEFUN (no_ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { - int idx_ipv4 = 4; + int idx_ipv4 = 4, idx_group = 0; - if (argc == (idx_ipv4 + 1)) - return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL); + if (argv_find (argv, argc, "A.B.C.D/M", &idx_group)) + return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_group]->arg, NULL); else return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, NULL, NULL); } From 6cbc63316b75e72a04e57ffca146e81ee89d645c Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 17 Apr 2017 00:06:02 +0000 Subject: [PATCH 32/34] lib: add removal by item to pqueue Signed-off-by: Quentin Young --- lib/pqueue.c | 8 ++++++++ lib/pqueue.h | 1 + 2 files changed, 9 insertions(+) diff --git a/lib/pqueue.c b/lib/pqueue.c index 0f870564da..fa502b462a 100644 --- a/lib/pqueue.c +++ b/lib/pqueue.c @@ -188,3 +188,11 @@ pqueue_remove_at (int index, struct pqueue *queue) trickle_down (index, queue); } } + +void +pqueue_remove (void *data, struct pqueue *queue) +{ + for (int i = 0; i < queue->size; i++) + if (queue->array[i] == data) + pqueue_remove_at (i, queue); +} diff --git a/lib/pqueue.h b/lib/pqueue.h index 8bb6961d86..b39fb92ee9 100644 --- a/lib/pqueue.h +++ b/lib/pqueue.h @@ -39,6 +39,7 @@ extern void pqueue_delete (struct pqueue *queue); extern void pqueue_enqueue (void *data, struct pqueue *queue); extern void *pqueue_dequeue (struct pqueue *queue); extern void pqueue_remove_at (int index, struct pqueue *queue); +extern void pqueue_remove (void *data, struct pqueue *queue); extern void trickle_down (int index, struct pqueue *queue); extern void trickle_up (int index, struct pqueue *queue); From 9ea49d61d2ea060c97066f445da65537f034772b Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 17 Apr 2017 19:21:06 +0000 Subject: [PATCH 33/34] pimd: fix 'show ip msdp sa ...' Signed-off-by: Quentin Young --- pimd/pim_cmd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 313414159c..2401991b8c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6212,13 +6212,16 @@ DEFUN (show_ip_msdp_sa_sg, "JavaScript Object Notation\n") { u_char uj = use_json(argc, argv); - if (uj) - argc--; - if (argc == 5) - ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj); - else if (argc == 4) - ip_msdp_show_sa_addr(vty, argv[4]->arg, uj); + int idx = 0; + char *src_ip = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg : NULL; + char *grp_ip = idx < argc && argv_find (argv, argc, "A.B.C.D", &idx) ? + argv[idx]->arg : NULL; + + if (src_ip && grp_ip) + ip_msdp_show_sa_sg(vty, src_ip, grp_ip, uj); + else if (src_ip) + ip_msdp_show_sa_addr(vty, src_ip, uj); else ip_msdp_show_sa(vty, uj); From d2c1e06d83d6793c1de311c099d31cc053a2826e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 12 Apr 2017 15:22:41 +0200 Subject: [PATCH 34/34] vtysh: remove deprecated HAVE_EVPN flag This flag prevents from entering into evpn address-family node, when calling command from vtysh. Signed-off-by: Philippe Guibert --- vtysh/vtysh.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index d0038ea3cf..424597c0d0 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1221,9 +1221,7 @@ DEFUNSH (VTYSH_BGPD, "Layer2 VPN Address family\n" "Ethernet Virtual Private Network Subsequent Address Family\n") { -#if defined(HAVE_EVPN) vty->node = BGP_EVPN_NODE; -#endif /* HAVE_EVPN */ return CMD_SUCCESS; }