diff options
Diffstat (limited to 'pimd/pim_join.c')
| -rw-r--r-- | pimd/pim_join.c | 886 |
1 files changed, 445 insertions, 441 deletions
diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 2da0b99353..9b2e5ec5c3 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -11,7 +11,7 @@ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, @@ -40,287 +40,281 @@ #include "pim_rp.h" #include "pim_jp_agg.h" -static void -on_trace (const char *label, - struct interface *ifp, struct in_addr src) +static void on_trace(const char *label, struct interface *ifp, + struct in_addr src) { - if (PIM_DEBUG_PIM_TRACE) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src, src_str, sizeof(src_str)); - zlog_debug("%s: from %s on %s", - label, src_str, ifp->name); - } + if (PIM_DEBUG_PIM_TRACE) { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src, src_str, sizeof(src_str)); + zlog_debug("%s: from %s on %s", label, src_str, ifp->name); + } } -static void recv_join(struct interface *ifp, - struct pim_neighbor *neigh, - uint16_t holdtime, - struct in_addr upstream, - struct prefix_sg *sg, - uint8_t source_flags) +static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, + uint16_t holdtime, struct in_addr upstream, + struct prefix_sg *sg, uint8_t source_flags) { - if (PIM_DEBUG_PIM_TRACE) { - char up_str[INET_ADDRSTRLEN]; - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); - pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str)); - zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", - __PRETTY_FUNCTION__, - pim_str_sg_dump (sg), - source_flags & PIM_RPT_BIT_MASK, - source_flags & PIM_WILDCARD_BIT_MASK, - up_str, holdtime, neigh_str, ifp->name); - } - - /* - * If the RPT and WC are set it's a (*,G) - * and the source is the RP - */ - if ((source_flags & PIM_RPT_BIT_MASK) && - (source_flags & PIM_WILDCARD_BIT_MASK)) - { - struct pim_rpf *rp = RP (sg->grp); - - /* - * If the RP sent in the message is not - * our RP for the group, drop the message - */ - if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) - return; - - sg->src.s_addr = INADDR_ANY; - } - - /* Restart join expiry timer */ - pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, - sg, source_flags, holdtime); - + if (PIM_DEBUG_PIM_TRACE) { + char up_str[INET_ADDRSTRLEN]; + char neigh_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); + pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, + sizeof(neigh_str)); + zlog_warn( + "%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), + source_flags & PIM_RPT_BIT_MASK, + source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, + neigh_str, ifp->name); + } + + /* + * If the RPT and WC are set it's a (*,G) + * and the source is the RP + */ + if ((source_flags & PIM_RPT_BIT_MASK) + && (source_flags & PIM_WILDCARD_BIT_MASK)) { + struct pim_rpf *rp = RP(sg->grp); + + /* + * If the RP sent in the message is not + * our RP for the group, drop the message + */ + if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) + return; + + sg->src.s_addr = INADDR_ANY; + } + + /* Restart join expiry timer */ + pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, sg, + source_flags, holdtime); } -static void recv_prune(struct interface *ifp, - struct pim_neighbor *neigh, - uint16_t holdtime, - struct in_addr upstream, - struct prefix_sg *sg, - uint8_t source_flags) +static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, + uint16_t holdtime, struct in_addr upstream, + struct prefix_sg *sg, uint8_t source_flags) { - if (PIM_DEBUG_PIM_TRACE) { - char up_str[INET_ADDRSTRLEN]; - char neigh_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); - pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str)); - zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", - __PRETTY_FUNCTION__, - pim_str_sg_dump (sg), - source_flags & PIM_RPT_BIT_MASK, - source_flags & PIM_WILDCARD_BIT_MASK, - up_str, holdtime, neigh_str, ifp->name); - } - - if ((source_flags & PIM_RPT_BIT_MASK) && - (source_flags & PIM_WILDCARD_BIT_MASK)) - { - struct pim_rpf *rp = RP (sg->grp); - - // Ignoring Prune *,G's at the moment. - if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) - return; - - sg->src.s_addr = INADDR_ANY; - } - - pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime); - + if (PIM_DEBUG_PIM_TRACE) { + char up_str[INET_ADDRSTRLEN]; + char neigh_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str)); + pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, + sizeof(neigh_str)); + zlog_warn( + "%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), + source_flags & PIM_RPT_BIT_MASK, + source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, + neigh_str, ifp->name); + } + + if ((source_flags & PIM_RPT_BIT_MASK) + && (source_flags & PIM_WILDCARD_BIT_MASK)) { + struct pim_rpf *rp = RP(sg->grp); + + // Ignoring Prune *,G's at the moment. + if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) + return; + + sg->src.s_addr = INADDR_ANY; + } + + pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime); } -int pim_joinprune_recv(struct interface *ifp, - struct pim_neighbor *neigh, - struct in_addr src_addr, - uint8_t *tlv_buf, int tlv_buf_size) +int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, + struct in_addr src_addr, uint8_t *tlv_buf, + int tlv_buf_size) { - struct prefix msg_upstream_addr; - uint8_t msg_num_groups; - uint16_t msg_holdtime; - int addr_offset; - uint8_t *buf; - uint8_t *pastend; - int remain; - int group; - - buf = tlv_buf; - pastend = tlv_buf + tlv_buf_size; - - /* - Parse ucast addr - */ - addr_offset = pim_parse_addr_ucast (&msg_upstream_addr, - buf, pastend - buf); - if (addr_offset < 1) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", - __PRETTY_FUNCTION__, - src_str, ifp->name); - return -1; - } - buf += addr_offset; - - /* - Check upstream address family - */ - if (msg_upstream_addr.family != AF_INET) { - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", - __PRETTY_FUNCTION__, - msg_upstream_addr.family, src_str, ifp->name); - } - return -2; - } - - remain = pastend - buf; - if (remain < 4) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", - __PRETTY_FUNCTION__, - remain, 4, src_str, ifp->name); - return -4; - } - - ++buf; /* skip reserved byte */ - msg_num_groups = *(const uint8_t *) buf; - ++buf; - msg_holdtime = ntohs(*(const uint16_t *) buf); - ++buf; - ++buf; - - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - char upstream_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, - upstream_str, sizeof(upstream_str)); - zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", - __PRETTY_FUNCTION__, - upstream_str, msg_num_groups, msg_holdtime, - src_str, ifp->name); - } - - /* Scan groups */ - for (group = 0; group < msg_num_groups; ++group) { - struct prefix_sg sg; - uint8_t msg_source_flags; - uint16_t msg_num_joined_sources; - uint16_t msg_num_pruned_sources; - int source; - struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL; - uint8_t starg_alone = 0; - - memset (&sg, 0, sizeof (struct prefix_sg)); - addr_offset = pim_parse_addr_group (&sg, - buf, pastend - buf); - if (addr_offset < 1) { - return -5; - } - buf += addr_offset; - - remain = pastend - buf; - if (remain < 4) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", - __PRETTY_FUNCTION__, - remain, 4, src_str, ifp->name); - return -6; - } - - msg_num_joined_sources = ntohs(*(const uint16_t *) buf); - buf += 2; - msg_num_pruned_sources = ntohs(*(const uint16_t *) buf); - buf += 2; - - if (PIM_DEBUG_PIM_J_P) { - char src_str[INET_ADDRSTRLEN]; - char upstream_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, - upstream_str, sizeof(upstream_str)); - pim_inet4_dump("<grp?>", sg.grp, - group_str, sizeof(group_str)); - zlog_warn("%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s", - __PRETTY_FUNCTION__, - upstream_str, group_str, - msg_num_joined_sources, msg_num_pruned_sources, - src_str, ifp->name); - } - - /* Scan joined sources */ - for (source = 0; source < msg_num_joined_sources; ++source) { - addr_offset = pim_parse_addr_source (&sg, - &msg_source_flags, - buf, pastend - buf); - if (addr_offset < 1) { - return -7; - } - - buf += addr_offset; - - recv_join(ifp, neigh, msg_holdtime, - msg_upstream_addr.u.prefix4, - &sg, - msg_source_flags); - - if (sg.src.s_addr == INADDR_ANY) - { - starg_alone = 1; - starg_ch = pim_ifchannel_find (ifp, &sg); - if (starg_ch) - pim_ifchannel_set_star_g_join_state (starg_ch, 0, msg_source_flags, 1, starg_alone); - } - } - - /* Scan pruned sources */ - for (source = 0; source < msg_num_pruned_sources; ++source) { - addr_offset = pim_parse_addr_source (&sg, - &msg_source_flags, - buf, pastend - buf); - if (addr_offset < 1) { - return -8; - } - - sg_ch = pim_ifchannel_find (ifp, &sg); - - buf += addr_offset; - starg_alone = 0; - recv_prune(ifp, neigh, msg_holdtime, - msg_upstream_addr.u.prefix4, - &sg, - msg_source_flags); - - /* Received SG-RPT Prune delete oif from specific S,G */ - if (starg_ch && sg_ch && (msg_source_flags & PIM_RPT_BIT_MASK) - && !(msg_source_flags & PIM_WILDCARD_BIT_MASK)) - { - struct pim_upstream *up = sg_ch->upstream; - PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags); - if (up) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: SGRpt flag is set, del inherit oif from up %s", - __PRETTY_FUNCTION__, up->sg_str); - pim_channel_del_oif (up->channel_oil, starg_ch->interface, PIM_OIF_FLAG_PROTO_STAR); - } - } - } - if (starg_ch) - pim_ifchannel_set_star_g_join_state (starg_ch, 1, msg_source_flags, 0, starg_alone); - starg_ch = NULL; - } /* scan groups */ - - return 0; + struct prefix msg_upstream_addr; + uint8_t msg_num_groups; + uint16_t msg_holdtime; + int addr_offset; + uint8_t *buf; + uint8_t *pastend; + int remain; + int group; + + buf = tlv_buf; + pastend = tlv_buf + tlv_buf_size; + + /* + Parse ucast addr + */ + addr_offset = + pim_parse_addr_ucast(&msg_upstream_addr, buf, pastend - buf); + if (addr_offset < 1) { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", + __PRETTY_FUNCTION__, src_str, ifp->name); + return -1; + } + buf += addr_offset; + + /* + Check upstream address family + */ + if (msg_upstream_addr.family != AF_INET) { + if (PIM_DEBUG_PIM_J_P) { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src_addr, src_str, + sizeof(src_str)); + zlog_warn( + "%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", + __PRETTY_FUNCTION__, msg_upstream_addr.family, + src_str, ifp->name); + } + return -2; + } + + remain = pastend - buf; + if (remain < 4) { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + zlog_warn( + "%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", + __PRETTY_FUNCTION__, remain, 4, src_str, ifp->name); + return -4; + } + + ++buf; /* skip reserved byte */ + msg_num_groups = *(const uint8_t *)buf; + ++buf; + msg_holdtime = ntohs(*(const uint16_t *)buf); + ++buf; + ++buf; + + if (PIM_DEBUG_PIM_J_P) { + char src_str[INET_ADDRSTRLEN]; + char upstream_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); + pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, + upstream_str, sizeof(upstream_str)); + zlog_debug( + "%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", + __PRETTY_FUNCTION__, upstream_str, msg_num_groups, + msg_holdtime, src_str, ifp->name); + } + + /* Scan groups */ + for (group = 0; group < msg_num_groups; ++group) { + struct prefix_sg sg; + uint8_t msg_source_flags; + uint16_t msg_num_joined_sources; + uint16_t msg_num_pruned_sources; + int source; + struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL; + uint8_t starg_alone = 0; + + memset(&sg, 0, sizeof(struct prefix_sg)); + addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf); + if (addr_offset < 1) { + return -5; + } + buf += addr_offset; + + remain = pastend - buf; + if (remain < 4) { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src_addr, src_str, + sizeof(src_str)); + zlog_warn( + "%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", + __PRETTY_FUNCTION__, remain, 4, src_str, + ifp->name); + return -6; + } + + msg_num_joined_sources = ntohs(*(const uint16_t *)buf); + buf += 2; + msg_num_pruned_sources = ntohs(*(const uint16_t *)buf); + buf += 2; + + if (PIM_DEBUG_PIM_J_P) { + char src_str[INET_ADDRSTRLEN]; + char upstream_str[INET_ADDRSTRLEN]; + char group_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", src_addr, src_str, + sizeof(src_str)); + pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4, + upstream_str, sizeof(upstream_str)); + pim_inet4_dump("<grp?>", sg.grp, group_str, + sizeof(group_str)); + zlog_warn( + "%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s", + __PRETTY_FUNCTION__, upstream_str, group_str, + msg_num_joined_sources, msg_num_pruned_sources, + src_str, ifp->name); + } + + /* Scan joined sources */ + for (source = 0; source < msg_num_joined_sources; ++source) { + addr_offset = pim_parse_addr_source( + &sg, &msg_source_flags, buf, pastend - buf); + if (addr_offset < 1) { + return -7; + } + + buf += addr_offset; + + recv_join(ifp, neigh, msg_holdtime, + msg_upstream_addr.u.prefix4, &sg, + msg_source_flags); + + if (sg.src.s_addr == INADDR_ANY) { + starg_alone = 1; + starg_ch = pim_ifchannel_find(ifp, &sg); + if (starg_ch) + pim_ifchannel_set_star_g_join_state( + starg_ch, 0, msg_source_flags, + 1, starg_alone); + } + } + + /* Scan pruned sources */ + for (source = 0; source < msg_num_pruned_sources; ++source) { + addr_offset = pim_parse_addr_source( + &sg, &msg_source_flags, buf, pastend - buf); + if (addr_offset < 1) { + return -8; + } + + sg_ch = pim_ifchannel_find(ifp, &sg); + + buf += addr_offset; + starg_alone = 0; + recv_prune(ifp, neigh, msg_holdtime, + msg_upstream_addr.u.prefix4, &sg, + msg_source_flags); + + /* Received SG-RPT Prune delete oif from specific S,G */ + if (starg_ch && sg_ch + && (msg_source_flags & PIM_RPT_BIT_MASK) + && !(msg_source_flags & PIM_WILDCARD_BIT_MASK)) { + struct pim_upstream *up = sg_ch->upstream; + PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags); + if (up) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: SGRpt flag is set, del inherit oif from up %s", + __PRETTY_FUNCTION__, + up->sg_str); + pim_channel_del_oif( + up->channel_oil, + starg_ch->interface, + PIM_OIF_FLAG_PROTO_STAR); + } + } + } + if (starg_ch) + pim_ifchannel_set_star_g_join_state( + starg_ch, 1, msg_source_flags, 0, starg_alone); + starg_ch = NULL; + } /* scan groups */ + + return 0; } /* @@ -389,174 +383,184 @@ int pim_joinprune_recv(struct interface *ifp, * | Pruned Source Address n (Encoded-Source format) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -int pim_joinprune_send(struct pim_rpf *rpf, - struct list *groups) +int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) { - struct pim_jp_agg_group *group; - struct pim_interface *pim_ifp = NULL; - struct pim_jp_groups *grp = NULL; - struct pim_jp *msg; - struct listnode *node, *nnode; - uint8_t pim_msg[10000]; - uint8_t *curr_ptr = pim_msg; - bool new_packet = true; - size_t packet_left = 0; - size_t packet_size = 0; - size_t group_size = 0; - - on_trace (__PRETTY_FUNCTION__, rpf->source_nexthop.interface, rpf->rpf_addr.u.prefix4); - - if (rpf->source_nexthop.interface) - pim_ifp = rpf->source_nexthop.interface->info; - else - { - zlog_warn ("%s: RPF interface is not present", __PRETTY_FUNCTION__); - return -1; - } - - if (!pim_ifp) - { - zlog_warn ("%s: multicast not enabled on interface %s", - __PRETTY_FUNCTION__, - rpf->source_nexthop.interface->name); - return -1; - } - - if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) - { - if (PIM_DEBUG_PIM_J_P) { - char dst_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str)); - zlog_debug("%s: upstream=%s is myself on interface %s", - __PRETTY_FUNCTION__, - dst_str, rpf->source_nexthop.interface->name); - } - return 0; - } - - /* - RFC 4601: 4.3.1. Sending Hello Messages - - Thus, if a router needs to send a Join/Prune or Assert message on - an interface on which it has not yet sent a Hello message with the - currently configured IP address, then it MUST immediately send the - relevant Hello message without waiting for the Hello Timer to - expire, followed by the Join/Prune or Assert message. - */ - pim_hello_require(rpf->source_nexthop.interface); - - for (ALL_LIST_ELEMENTS(groups, node, nnode, group)) - { - if (new_packet) - { - msg = (struct pim_jp *)pim_msg; - - memset(msg, 0, sizeof (*msg)); - - pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4); - msg->reserved = 0; - msg->holdtime = htons(PIM_JP_HOLDTIME); - - new_packet = false; - - grp = &msg->groups[0]; - curr_ptr = (uint8_t *)grp; - packet_size = sizeof (struct pim_msg_header); - packet_size += sizeof (struct pim_encoded_ipv4_unicast); - packet_size += 4; // reserved (1) + groups (1) + holdtime (2) - - packet_left = rpf->source_nexthop.interface->mtu - 24; - packet_left -= packet_size; - } - if (PIM_DEBUG_PIM_J_P) { - char dst_str[INET_ADDRSTRLEN]; - char grp_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str)); - pim_inet4_dump("<grp?>", group->group, grp_str, sizeof(grp_str)); - zlog_debug("%s: sending (G)=%s to upstream=%s on interface %s", - __PRETTY_FUNCTION__, - grp_str, dst_str, rpf->source_nexthop.interface->name); - } - - group_size = pim_msg_get_jp_group_size (group->sources); - if (group_size > packet_left) - { - pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE); - if (pim_msg_send(pim_ifp->pim_sock_fd, - pim_ifp->primary_address, - qpim_all_pim_routers_addr, - pim_msg, - packet_size, - rpf->source_nexthop.interface->name)) { - zlog_warn("%s: could not send PIM message on interface %s", - __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name); - } - - msg = (struct pim_jp *)pim_msg; - memset(msg, 0, sizeof (*msg)); - - pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, rpf->rpf_addr.u.prefix4); - msg->reserved = 0; - msg->holdtime = htons(PIM_JP_HOLDTIME); - - new_packet = false; - - grp = &msg->groups[0]; - curr_ptr = (uint8_t *)grp; - packet_size = sizeof (struct pim_msg_header); - packet_size += sizeof (struct pim_encoded_ipv4_unicast); - packet_size += 4; // reserved (1) + groups (1) + holdtime (2) - - packet_left = rpf->source_nexthop.interface->mtu - 24; - packet_left -= packet_size; - } - - msg->num_groups++; - /* - Build PIM message - */ - - curr_ptr += group_size; - packet_left -= group_size; - packet_size += group_size; - pim_msg_build_jp_groups (grp, group, group_size); - - if (PIM_DEBUG_PIM_TRACE) - zlog_debug ("%s: interface %s num_joins %u num_prunes %u", __PRETTY_FUNCTION__, - rpf->source_nexthop.interface->name, ntohs(grp->joins), ntohs (grp->prunes)); - - grp = (struct pim_jp_groups *)curr_ptr; - if (packet_left < sizeof (struct pim_jp_groups) || msg->num_groups == 255) - { - pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE); - if (pim_msg_send(pim_ifp->pim_sock_fd, - pim_ifp->primary_address, - qpim_all_pim_routers_addr, - pim_msg, - packet_size, - rpf->source_nexthop.interface->name)) { - zlog_warn("%s: could not send PIM message on interface %s", - __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name); - } - - new_packet = true; - } - } - - - if (!new_packet) - { - //msg->num_groups = htons (msg->num_groups); - pim_msg_build_header (pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE); - if (pim_msg_send(pim_ifp->pim_sock_fd, - pim_ifp->primary_address, - qpim_all_pim_routers_addr, - pim_msg, - packet_size, - rpf->source_nexthop.interface->name)) { - zlog_warn("%s: could not send PIM message on interface %s", - __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name); - } - } - return 0; + struct pim_jp_agg_group *group; + struct pim_interface *pim_ifp = NULL; + struct pim_jp_groups *grp = NULL; + struct pim_jp *msg; + struct listnode *node, *nnode; + uint8_t pim_msg[10000]; + uint8_t *curr_ptr = pim_msg; + bool new_packet = true; + size_t packet_left = 0; + size_t packet_size = 0; + size_t group_size = 0; + + on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface, + rpf->rpf_addr.u.prefix4); + + if (rpf->source_nexthop.interface) + pim_ifp = rpf->source_nexthop.interface->info; + else { + zlog_warn("%s: RPF interface is not present", + __PRETTY_FUNCTION__); + return -1; + } + + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", + __PRETTY_FUNCTION__, + rpf->source_nexthop.interface->name); + return -1; + } + + if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) { + if (PIM_DEBUG_PIM_J_P) { + char dst_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, + dst_str, sizeof(dst_str)); + zlog_debug("%s: upstream=%s is myself on interface %s", + __PRETTY_FUNCTION__, dst_str, + rpf->source_nexthop.interface->name); + } + return 0; + } + + /* + RFC 4601: 4.3.1. Sending Hello Messages + + Thus, if a router needs to send a Join/Prune or Assert message on + an interface on which it has not yet sent a Hello message with the + currently configured IP address, then it MUST immediately send the + relevant Hello message without waiting for the Hello Timer to + expire, followed by the Join/Prune or Assert message. + */ + pim_hello_require(rpf->source_nexthop.interface); + + for (ALL_LIST_ELEMENTS(groups, node, nnode, group)) { + if (new_packet) { + msg = (struct pim_jp *)pim_msg; + + memset(msg, 0, sizeof(*msg)); + + pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr, + rpf->rpf_addr.u.prefix4); + msg->reserved = 0; + msg->holdtime = htons(PIM_JP_HOLDTIME); + + new_packet = false; + + grp = &msg->groups[0]; + curr_ptr = (uint8_t *)grp; + packet_size = sizeof(struct pim_msg_header); + packet_size += sizeof(struct pim_encoded_ipv4_unicast); + packet_size += + 4; // reserved (1) + groups (1) + holdtime (2) + + packet_left = rpf->source_nexthop.interface->mtu - 24; + packet_left -= packet_size; + } + if (PIM_DEBUG_PIM_J_P) { + char dst_str[INET_ADDRSTRLEN]; + char grp_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<dst?>", rpf->rpf_addr.u.prefix4, + dst_str, sizeof(dst_str)); + pim_inet4_dump("<grp?>", group->group, grp_str, + sizeof(grp_str)); + zlog_debug( + "%s: sending (G)=%s to upstream=%s on interface %s", + __PRETTY_FUNCTION__, grp_str, dst_str, + rpf->source_nexthop.interface->name); + } + + group_size = pim_msg_get_jp_group_size(group->sources); + if (group_size > packet_left) { + pim_msg_build_header(pim_msg, packet_size, + PIM_MSG_TYPE_JOIN_PRUNE); + if (pim_msg_send(pim_ifp->pim_sock_fd, + pim_ifp->primary_address, + qpim_all_pim_routers_addr, pim_msg, + packet_size, + rpf->source_nexthop.interface->name)) { + zlog_warn( + "%s: could not send PIM message on interface %s", + __PRETTY_FUNCTION__, + rpf->source_nexthop.interface->name); + } + + msg = (struct pim_jp *)pim_msg; + memset(msg, 0, sizeof(*msg)); + + pim_msg_addr_encode_ipv4_ucast((uint8_t *)&msg->addr, + rpf->rpf_addr.u.prefix4); + msg->reserved = 0; + msg->holdtime = htons(PIM_JP_HOLDTIME); + + new_packet = false; + + grp = &msg->groups[0]; + curr_ptr = (uint8_t *)grp; + packet_size = sizeof(struct pim_msg_header); + packet_size += sizeof(struct pim_encoded_ipv4_unicast); + packet_size += + 4; // reserved (1) + groups (1) + holdtime (2) + + packet_left = rpf->source_nexthop.interface->mtu - 24; + packet_left -= packet_size; + } + + msg->num_groups++; + /* + Build PIM message + */ + + curr_ptr += group_size; + packet_left -= group_size; + packet_size += group_size; + pim_msg_build_jp_groups(grp, group, group_size); + + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s: interface %s num_joins %u num_prunes %u", + __PRETTY_FUNCTION__, + rpf->source_nexthop.interface->name, + ntohs(grp->joins), ntohs(grp->prunes)); + + grp = (struct pim_jp_groups *)curr_ptr; + if (packet_left < sizeof(struct pim_jp_groups) + || msg->num_groups == 255) { + pim_msg_build_header(pim_msg, packet_size, + PIM_MSG_TYPE_JOIN_PRUNE); + if (pim_msg_send(pim_ifp->pim_sock_fd, + pim_ifp->primary_address, + qpim_all_pim_routers_addr, pim_msg, + packet_size, + rpf->source_nexthop.interface->name)) { + zlog_warn( + "%s: could not send PIM message on interface %s", + __PRETTY_FUNCTION__, + rpf->source_nexthop.interface->name); + } + + new_packet = true; + } + } + + + if (!new_packet) { + // msg->num_groups = htons (msg->num_groups); + pim_msg_build_header(pim_msg, packet_size, + PIM_MSG_TYPE_JOIN_PRUNE); + if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address, + qpim_all_pim_routers_addr, pim_msg, + packet_size, + rpf->source_nexthop.interface->name)) { + zlog_warn( + "%s: could not send PIM message on interface %s", + __PRETTY_FUNCTION__, + rpf->source_nexthop.interface->name); + } + } + return 0; } |
