diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index d6f372cc44..f2bfb846dd 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -379,9 +379,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, /* Encode group */ remain = buf_pastend - pim_msg_curr; - pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, - remain, - group_addr); + pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, group_addr); if (!pim_msg_curr) { char group_str[INET_ADDRSTRLEN]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); @@ -392,9 +390,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, /* Encode source */ remain = buf_pastend - pim_msg_curr; - pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, - remain, - source_addr); + pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, source_addr); if (!pim_msg_curr) { char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index c1289a3ba7..8f7d40bb36 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -27,6 +27,7 @@ #include "vrf.h" #include "linklist.h" #include "plist.h" +#include "hash.h" #include "pimd.h" #include "pim_iface.h" @@ -86,6 +87,9 @@ static void *if_list_clean(struct pim_interface *pim_ifp) list_delete(pim_ifp->pim_ifchannel_list); } + if (pim_ifp->pim_ifchannel_hash) + hash_free (pim_ifp->pim_ifchannel_hash); + XFREE(MTYPE_PIM_INTERFACE, pim_ifp); return 0; @@ -131,6 +135,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp->igmp_socket_list = NULL; pim_ifp->pim_neighbor_list = NULL; pim_ifp->pim_ifchannel_list = NULL; + pim_ifp->pim_ifchannel_hash = NULL; pim_ifp->pim_generation_id = 0; /* list of struct igmp_sock */ @@ -161,6 +166,9 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free; pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare; + pim_ifp->pim_ifchannel_hash = hash_create (pim_ifchannel_hash_key, + pim_ifchannel_equal); + ifp->info = pim_ifp; pim_sock_reset(ifp); @@ -197,6 +205,8 @@ void pim_if_delete(struct interface *ifp) list_delete(pim_ifp->pim_neighbor_list); list_delete(pim_ifp->pim_ifchannel_list); + hash_free (pim_ifp->pim_ifchannel_hash); + XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = NULL; diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 244de598db..7c0d57a5d1 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -98,6 +98,7 @@ struct pim_interface { uint16_t pim_override_interval_msec; /* config */ struct list *pim_neighbor_list; /* list of struct pim_neighbor */ struct list *pim_ifchannel_list; /* list of struct pim_ifchannel */ + struct hash *pim_ifchannel_hash; /* neighbors without lan_delay */ int pim_number_of_nonlandelay_neighbors; diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index f0e4a3a68a..891bdc448d 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -25,6 +25,8 @@ #include "memory.h" #include "if.h" #include "vrf.h" +#include "hash.h" +#include "jhash.h" #include "pimd.h" #include "pim_str.h" @@ -193,6 +195,7 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) called by list_delete_all_node() */ listnode_delete(pim_ifp->pim_ifchannel_list, ch); + hash_release(pim_ifp->pim_ifchannel_hash, ch); listnode_delete(pim_ifchannel_list, ch); pim_ifchannel_free(ch); @@ -373,10 +376,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct prefix_sg *sg) { struct pim_interface *pim_ifp; - struct listnode *ch_node; struct pim_ifchannel *ch; - - zassert(ifp); + struct pim_ifchannel lookup; pim_ifp = ifp->info; @@ -385,19 +386,13 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, __PRETTY_FUNCTION__, pim_str_sg_dump (sg), ifp->name); - return 0; + return NULL; } - for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { - if ( - (sg->src.s_addr == ch->sg.src.s_addr) && - (sg->grp.s_addr == ch->sg.grp.s_addr) - ) { - return ch; - } - } + lookup.sg = *sg; + ch = hash_lookup (pim_ifp->pim_ifchannel_hash, &lookup); - return 0; + return ch; } static void ifmembership_set(struct pim_ifchannel *ch, @@ -553,6 +548,7 @@ pim_ifchannel_add(struct interface *ifp, /* Attach to list */ listnode_add_sort(pim_ifp->pim_ifchannel_list, ch); + ch = hash_get (pim_ifp->pim_ifchannel_hash, ch, hash_alloc_intern); listnode_add_sort(pim_ifchannel_list, ch); return ch; @@ -601,8 +597,13 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) /* from here ch may have been deleted */ if (send_prune_echo) - pim_joinprune_send (ifp, pim_ifp->primary_address, - ch->upstream, 0); + { + struct pim_rpf rpf; + + rpf.source_nexthop.interface = ifp; + rpf.rpf_addr.u.prefix4 = pim_ifp->primary_address; + pim_joinprune_send (&rpf, ch->upstream, 0); + } } else { @@ -665,28 +666,26 @@ static void check_recv_upstream(int is_join, if (source_flags & PIM_RPT_BIT_MASK) { if (source_flags & PIM_WILDCARD_BIT_MASK) { /* Prune(*,G) to RPF'(S,G) */ - pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)", - up, up->rpf.rpf_addr.u.prefix4); + pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)", up); return; } /* Prune(S,G,rpt) to RPF'(S,G) */ - pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)", - up, up->rpf.rpf_addr.u.prefix4); + pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)", up); return; } /* Prune(S,G) to RPF'(S,G) */ - pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up, - up->rpf.rpf_addr.u.prefix4); + pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up); } -static int nonlocal_upstream(int is_join, - struct interface *recv_ifp, - struct in_addr upstream, - struct prefix_sg *sg, - uint8_t source_flags, - uint16_t holdtime) +static int +nonlocal_upstream(int is_join, + struct interface *recv_ifp, + struct in_addr upstream, + struct prefix_sg *sg, + uint8_t source_flags, + uint16_t holdtime) { struct pim_interface *recv_pim_ifp; int is_local; /* boolean */ @@ -695,27 +694,26 @@ static int nonlocal_upstream(int is_join, zassert(recv_pim_ifp); is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr); - - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char up_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", upstream, up_str, sizeof(up_str)); - zlog_warn("%s: recv %s (S,G)=%s to %s upstream=%s on %s", - __PRETTY_FUNCTION__, - is_join ? "join" : "prune", - pim_str_sg_dump (sg), - is_local ? "local" : "non-local", - up_str, recv_ifp->name); - } if (is_local) return 0; + if (PIM_DEBUG_PIM_TRACE_DETAIL) { + char up_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", upstream, up_str, sizeof(up_str)); + zlog_warn("%s: recv %s (S,G)=%s to non-local upstream=%s on %s", + __PRETTY_FUNCTION__, + is_join ? "join" : "prune", + pim_str_sg_dump (sg), + up_str, recv_ifp->name); + } + /* - Since recv upstream addr was not directed to our primary - address, check if we should react to it in any way. - */ + * Since recv upstream addr was not directed to our primary + * address, check if we should react to it in any way. + */ check_recv_upstream(is_join, recv_ifp, upstream, sg, - source_flags, holdtime); + source_flags, holdtime); return 1; /* non-local */ } @@ -972,7 +970,7 @@ pim_ifchannel_local_membership_add(struct interface *ifp, __FILE__, __PRETTY_FUNCTION__, child->sg_str, ifp->name, up->sg_str); - if (pim_upstream_evaluate_join_desired (child)) + if (pim_upstream_evaluate_join_desired_interface (child, ch)) { pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_STAR); pim_upstream_switch (child, PIM_UPSTREAM_JOINED); @@ -1019,7 +1017,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, __FILE__, __PRETTY_FUNCTION__, up->sg_str, ifp->name, child->sg_str); - if (c_oil && !pim_upstream_evaluate_join_desired (child)) + if (c_oil && !pim_upstream_evaluate_join_desired_interface (child, ch)) pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR); /* @@ -1231,3 +1229,24 @@ pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom) } } } + +unsigned int +pim_ifchannel_hash_key (void *arg) +{ + struct pim_ifchannel *ch = (struct pim_ifchannel *)arg; + + return jhash_2words (ch->sg.src.s_addr, ch->sg.grp.s_addr, 0); +} + +int +pim_ifchannel_equal (const void *arg1, const void *arg2) +{ + const struct pim_ifchannel *ch1 = (const struct pim_ifchannel *)arg1; + const struct pim_ifchannel *ch2 = (const struct pim_ifchannel *)arg2; + + if ((ch1->sg.grp.s_addr == ch2->sg.grp.s_addr) && + (ch1->sg.src.s_addr == ch2->sg.src.s_addr)) + return 1; + + return 0; +} diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index a3dc0e9d83..c7084034a0 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -26,6 +26,7 @@ #include "if.h" #include "prefix.h" +struct pim_ifchannel; #include "pim_upstream.h" enum pim_ifmembership { @@ -153,4 +154,7 @@ void pim_ifchannel_scan_forward_start (struct interface *new_ifp); void pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom); int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2); + +unsigned int pim_ifchannel_hash_key (void *arg); +int pim_ifchannel_equal (const void *arg1, const void *arg2); #endif /* PIM_IFCHANNEL_H */ diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 24b9e54ea5..e6582e2b17 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -23,6 +23,8 @@ #include "memory.h" #include "prefix.h" #include "if.h" +#include "hash.h" +#include "jhash.h" #include "pimd.h" #include "pim_igmp.h" @@ -428,23 +430,6 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) from_str, to_str, igmp->interface->name, len, ip_hlen, ip_hdr->ip_p); } - if (ip_hdr->ip_p != PIM_IP_PROTO_IGMP) { - zlog_warn("IP packet protocol=%d is not IGMP=%d", - ip_hdr->ip_p, PIM_IP_PROTO_IGMP); - return -1; - } - - if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { - zlog_warn("IP packet header size=%zu shorter than minimum=%d", - ip_hlen, PIM_IP_HEADER_MIN_LEN); - return -1; - } - if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { - zlog_warn("IP packet header size=%zu greater than maximum=%d", - ip_hlen, PIM_IP_HEADER_MAX_LEN); - return -1; - } - igmp_msg = buf + ip_hlen; msg_type = *igmp_msg; igmp_msg_len = len - ip_hlen; @@ -730,6 +715,8 @@ static void igmp_group_delete(struct igmp_group *group) group_timer_off(group); listnode_delete(group->group_igmp_sock->igmp_group_list, group); + hash_release (group->group_igmp_sock->igmp_group_hash, group); + igmp_group_free(group); } @@ -750,6 +737,7 @@ void igmp_sock_free(struct igmp_sock *igmp) zassert(!listcount(igmp->igmp_group_list)); list_free(igmp->igmp_group_list); + hash_free(igmp->igmp_group_hash); XFREE(MTYPE_PIM_IGMP_SOCKET, igmp); } @@ -790,6 +778,26 @@ igmp_sock_delete_all (struct interface *ifp) } } +static unsigned int +igmp_group_hash_key (void *arg) +{ + struct igmp_group *group = (struct igmp_group *)arg; + + return jhash_1word(group->group_addr.s_addr, 0); +} + +static int +igmp_group_hash_equal (const void *arg1, const void *arg2) +{ + const struct igmp_group *g1 = (const struct igmp_group *)arg1; + const struct igmp_group *g2 = (const struct igmp_group *)arg2; + + if (g1->group_addr.s_addr == g2->group_addr.s_addr) + return 1; + + return 0; +} + static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, struct interface *ifp) @@ -819,6 +827,9 @@ static struct igmp_sock *igmp_sock_new(int fd, } igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free; + igmp->igmp_group_hash = hash_create (igmp_group_hash_key, + igmp_group_hash_equal); + igmp->fd = fd; igmp->interface = ifp; igmp->ifaddr = ifaddr; @@ -1029,14 +1040,11 @@ struct igmp_group * find_group_by_addr (struct igmp_sock *igmp, struct in_addr group_addr) { - struct igmp_group *group; - struct listnode *node; + struct igmp_group lookup; - for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, node, group)) - if (group_addr.s_addr == group->group_addr.s_addr) - return group; + lookup.group_addr.s_addr = group_addr.s_addr; - return 0; + return hash_lookup(igmp->igmp_group_hash, &lookup); } struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, @@ -1105,6 +1113,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */ listnode_add(igmp->igmp_group_list, group); + group = hash_get (igmp->igmp_group_hash, group, hash_alloc_intern); if (PIM_DEBUG_IGMP_TRACE) { char group_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index 802f1ba471..9c569bbd20 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -89,6 +89,7 @@ struct igmp_sock { int startup_query_count; struct list *igmp_group_list; /* list of struct igmp_group */ + struct hash *igmp_group_hash; }; struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, diff --git a/pimd/pim_join.c b/pimd/pim_join.c index cedce8165c..783dd75075 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -303,37 +303,33 @@ int pim_joinprune_recv(struct interface *ifp, return 0; } -int pim_joinprune_send(struct interface *ifp, - struct in_addr upstream_addr, - struct pim_upstream *up, - int send_join) +int pim_joinprune_send(struct pim_rpf *rpf, + struct pim_upstream *up, + int send_join) { struct pim_interface *pim_ifp; uint8_t pim_msg[9000]; int pim_msg_size; - on_trace (__PRETTY_FUNCTION__, ifp, upstream_addr); + on_trace (__PRETTY_FUNCTION__, rpf->source_nexthop.interface, rpf->rpf_addr.u.prefix4); - zassert(ifp); - - pim_ifp = ifp->info; + pim_ifp = rpf->source_nexthop.interface->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", - __PRETTY_FUNCTION__, - ifp->name); + __PRETTY_FUNCTION__, + rpf->source_nexthop.interface->name); return -1; } - - if (PIM_INADDR_IS_ANY(upstream_addr)) { + if (PIM_INADDR_IS_ANY(rpf->rpf_addr.u.prefix4)) { if (PIM_DEBUG_PIM_J_P) { char dst_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); + pim_inet4_dump("", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str)); zlog_debug("%s: %s(S,G)=%s: upstream=%s is myself on interface %s", __PRETTY_FUNCTION__, send_join ? "Join" : "Prune", - up->sg_str, dst_str, ifp->name); + up->sg_str, dst_str, rpf->source_nexthop.interface->name); } return 0; } @@ -347,24 +343,24 @@ int pim_joinprune_send(struct interface *ifp, relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ - pim_hello_require(ifp); + pim_hello_require(rpf->source_nexthop.interface); /* Build PIM message */ pim_msg_size = pim_msg_join_prune_encode (pim_msg, 9000, send_join, - up, upstream_addr, PIM_JP_HOLDTIME); + up, rpf->rpf_addr.u.prefix4, PIM_JP_HOLDTIME); if (pim_msg_size < 0) return pim_msg_size; if (PIM_DEBUG_PIM_J_P) { char dst_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); + pim_inet4_dump("", rpf->rpf_addr.u.prefix4, dst_str, sizeof(dst_str)); zlog_debug("%s: sending %s(S,G)=%s to upstream=%s on interface %s", __PRETTY_FUNCTION__, send_join ? "Join" : "Prune", - up->sg_str, dst_str, ifp->name); + up->sg_str, dst_str, rpf->source_nexthop.interface->name); } if (pim_msg_send(pim_ifp->pim_sock_fd, @@ -372,9 +368,9 @@ int pim_joinprune_send(struct interface *ifp, qpim_all_pim_routers_addr, pim_msg, pim_msg_size, - ifp->name)) { + rpf->source_nexthop.interface->name)) { zlog_warn("%s: could not send PIM message on interface %s", - __PRETTY_FUNCTION__, ifp->name); + __PRETTY_FUNCTION__, rpf->source_nexthop.interface->name); return -8; } diff --git a/pimd/pim_join.h b/pimd/pim_join.h index 1eeeef756f..4b76166328 100644 --- a/pimd/pim_join.h +++ b/pimd/pim_join.h @@ -32,9 +32,8 @@ int pim_joinprune_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); -int pim_joinprune_send(struct interface *ifp, - struct in_addr upstream_addr, - struct pim_upstream *up, - int send_join); +int pim_joinprune_send(struct pim_rpf *nexthop, + struct pim_upstream *up, + int send_join); #endif /* PIM_JOIN_H */ diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 4fae5b3ca5..ae5d0e9891 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -351,7 +351,7 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf) struct pim_interface *pim_ifp; struct pim_ifchannel *ch; struct pim_upstream *up; - //struct prefix_sg star_g; + struct prefix_sg star_g; struct prefix_sg sg; struct channel_oil *oil; @@ -367,9 +367,10 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf) ch->sg_str, ifp->name); return -1; } -#if 0 + star_g = sg; star_g.src.s_addr = INADDR_ANY; +#if 0 ch = pim_ifchannel_find(ifp, &star_g); if (ch) { @@ -383,11 +384,22 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf) up = pim_upstream_find (&sg); if (up) { + struct pim_upstream *parent; struct pim_nexthop source; struct pim_rpf *rpf = RP (sg.grp); if (!rpf || !rpf->source_nexthop.interface) return 0; + /* + * If we have received a WRVIFWHOLE and are at this + * point, we could be receiving the packet on the *,G + * tree, let's check and if so we can safely drop + * it. + */ + parent = pim_upstream_find (&star_g); + if (parent && parent->rpf.source_nexthop.interface == ifp) + return 0; + pim_ifp = rpf->source_nexthop.interface->info; memset (&source, 0, sizeof (source)); diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index ab14b3ae5f..e6b13f3121 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -37,163 +37,72 @@ #include "pim_rpf.h" #include "pim_register.h" -void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, - uint8_t pim_msg_type) +void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, uint8_t pim_msg_type) { - uint16_t checksum; - - zassert(pim_msg_size >= PIM_PIM_MIN_LEN); + struct pim_msg_header *header = (struct pim_msg_header *)pim_msg; /* * Write header */ + header->ver = PIM_PROTO_VERSION; + header->type = pim_msg_type; + header->reserved = 0; - *(uint8_t *) PIM_MSG_HDR_OFFSET_VERSION(pim_msg) = (PIM_PROTO_VERSION << 4) | pim_msg_type; - *(uint8_t *) PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) = 0; - /* - * Compute checksum - */ - - *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM (pim_msg) = 0; + header->checksum = 0; /* * The checksum for Registers is done only on the first 8 bytes of the packet, * including the PIM header and the next 4 bytes, excluding the data packet portion */ if (pim_msg_type == PIM_MSG_TYPE_REGISTER) - checksum = in_cksum (pim_msg, PIM_MSG_REGISTER_LEN); + header->checksum = in_cksum (pim_msg, PIM_MSG_REGISTER_LEN); else - checksum = in_cksum (pim_msg, pim_msg_size); - - *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum; + header->checksum = in_cksum (pim_msg, pim_msg_size); } -uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, - int buf_size, - struct in_addr addr) +uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr) { - const int ENCODED_IPV4_UCAST_SIZE = 6; - - if (buf_size < ENCODED_IPV4_UCAST_SIZE) { - return 0; - } - buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ memcpy(buf+2, &addr, sizeof(struct in_addr)); - return buf + ENCODED_IPV4_UCAST_SIZE; + return buf + PIM_ENCODED_IPV4_UCAST_SIZE; } -uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, - int buf_size, - struct in_addr addr) +uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr) { - const int ENCODED_IPV4_GROUP_SIZE = 8; - - if (buf_size < ENCODED_IPV4_GROUP_SIZE) { - return 0; - } - buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ buf[2] = '\0'; /* reserved */ buf[3] = 32; /* mask len */ memcpy(buf+4, &addr, sizeof(struct in_addr)); - return buf + ENCODED_IPV4_GROUP_SIZE; + return buf + PIM_ENCODED_IPV4_GROUP_SIZE; } uint8_t * -pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size, - struct in_addr addr, uint8_t bits) +pim_msg_addr_encode_ipv4_source(uint8_t *buf, + struct in_addr addr, uint8_t bits) { - const int ENCODED_IPV4_SOURCE_SIZE = 8; - - if (buf_size < ENCODED_IPV4_SOURCE_SIZE) { - return 0; - } - buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ buf[2] = bits; buf[3] = 32; /* mask len */ memcpy(buf+4, &addr, sizeof(struct in_addr)); - return buf + ENCODED_IPV4_SOURCE_SIZE; + return buf + PIM_ENCODED_IPV4_SOURCE_SIZE; } -int -pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join, - struct pim_upstream *up, - struct in_addr upstream, int holdtime) +static size_t +pim_msg_build_jp_groups (struct pim_jp_groups *grp, struct pim_upstream *up, int is_join) { - uint8_t *pim_msg = buf; - uint8_t *pim_msg_curr = buf + PIM_MSG_HEADER_LEN; - uint8_t *end = buf + buf_size; - uint16_t *prunes = NULL; - uint16_t *joins = NULL; struct in_addr stosend; uint8_t bits; - int remain; - remain = end - pim_msg_curr; - pim_msg_curr = pim_msg_addr_encode_ipv4_ucast (pim_msg_curr, buf_size - PIM_MSG_HEADER_LEN, upstream); - if (!pim_msg_curr) { - char dst_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", upstream, dst_str, sizeof(dst_str)); - zlog_warn("%s: failure encoding destination address %s: space left=%d", - __PRETTY_FUNCTION__, dst_str, remain); - return -3; - } + /* number of joined/pruned sources */ + grp->joins = htons(is_join ? 1 : 0); + grp->prunes = htons(is_join ? 0 : 1); - remain = end - pim_msg_curr; - if (remain < 4) { - zlog_warn("%s: group will not fit: space left=%d", - __PRETTY_FUNCTION__, remain); - return -4; - } - - *pim_msg_curr = 0; /* reserved */ - ++pim_msg_curr; - *pim_msg_curr = 1; /* number of groups */ - ++pim_msg_curr; - - *((uint16_t *) pim_msg_curr) = htons(holdtime); - ++pim_msg_curr; - ++pim_msg_curr; - - remain = end - pim_msg_curr; - pim_msg_curr = pim_msg_addr_encode_ipv4_group (pim_msg_curr, remain, - up->sg.grp); - if (!pim_msg_curr) { - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", up->sg.grp, group_str, sizeof(group_str)); - zlog_warn("%s: failure encoding group address %s: space left=%d", - __PRETTY_FUNCTION__, group_str, remain); - return -5; - } - - remain = end - pim_msg_curr; - if (remain < 4) { - zlog_warn("%s: sources will not fit: space left=%d", - __PRETTY_FUNCTION__, remain); - return -6; - } - - /* number of joined sources */ - joins = (uint16_t *)pim_msg_curr; - *joins = htons(is_join ? 1 : 0); - ++pim_msg_curr; - ++pim_msg_curr; - - /* number of pruned sources */ - prunes = (uint16_t *)pim_msg_curr; - *prunes = htons(is_join ? 0 : 1); - ++pim_msg_curr; - ++pim_msg_curr; - - remain = end - pim_msg_curr; if (up->sg.src.s_addr == INADDR_ANY) { struct pim_rpf *rpf = pim_rp_g (up->sg.grp); @@ -205,15 +114,14 @@ pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join, bits = PIM_ENCODE_SPARSE_BIT; stosend = up->sg.src; } - pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, stosend, bits); - if (!pim_msg_curr) { + + if (!pim_msg_addr_encode_ipv4_source ((uint8_t *)&grp->s[0], stosend, bits)) { char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("", up->sg.src, source_str, sizeof(source_str)); - zlog_warn("%s: failure encoding source address %s: space left=%d", - __PRETTY_FUNCTION__, source_str, remain); - return -7; + zlog_warn("%s: failure encoding source address %s", + __PRETTY_FUNCTION__, source_str); + return 0; } - remain = pim_msg_curr - pim_msg; /* * This is not implemented correctly at this point in time @@ -227,61 +135,162 @@ pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join, int send_prune = 0; zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune", - __PRETTY_FUNCTION__, up->sg_str); + __PRETTY_FUNCTION__, up->sg_str); for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child)) - { - if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) - { - if (!pim_rpf_is_same(&up->rpf, &child->rpf)) - { - send_prune = 1; - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message", - __PRETTY_FUNCTION__, up->sg_str, child->sg_str); - } - else - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)", - __PRETTY_FUNCTION__, up->sg_str, child->sg_str); - } - else if (pim_upstream_is_sg_rpt (child)) - { - if (pim_upstream_empty_inherited_olist (child)) - { - send_prune = 1; - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message", - __PRETTY_FUNCTION__, child->sg_str); - } - else if (!pim_rpf_is_same (&up->rpf, &child->rpf)) - { - send_prune = 1; - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message", - __PRETTY_FUNCTION__, up->sg_str, child->sg_str); - } - else - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message", - __PRETTY_FUNCTION__, up->sg_str, child->sg_str); - } - else - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug ("%s: SPT bit is not set for (%s)", - __PRETTY_FUNCTION__, child->sg_str); - if (send_prune) - { - pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, - child->sg.src, - PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT); - remain = pim_msg_curr - pim_msg; - *prunes = htons(ntohs(*prunes) + 1); - send_prune = 0; - } - } + { + if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) + { + if (!pim_rpf_is_same(&up->rpf, &child->rpf)) + { + send_prune = 1; + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message", + __PRETTY_FUNCTION__, up->sg_str, child->sg_str); + } + else + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)", + __PRETTY_FUNCTION__, up->sg_str, child->sg_str); + } + else if (pim_upstream_is_sg_rpt (child)) + { + if (pim_upstream_empty_inherited_olist (child)) + { + send_prune = 1; + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message", + __PRETTY_FUNCTION__, child->sg_str); + } + else if (!pim_rpf_is_same (&up->rpf, &child->rpf)) + { + send_prune = 1; + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message", + __PRETTY_FUNCTION__, up->sg_str, child->sg_str); + } + else + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message", + __PRETTY_FUNCTION__, up->sg_str, child->sg_str); + } + else + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug ("%s: SPT bit is not set for (%s)", + __PRETTY_FUNCTION__, child->sg_str); + if (send_prune) + { + pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, + child->sg.src, + PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT); + remain = pim_msg_curr - pim_msg; + *prunes = htons(ntohs(*prunes) + 1); + send_prune = 0; + } + } } #endif - pim_msg_build_header (pim_msg, remain, PIM_MSG_TYPE_JOIN_PRUNE); - return remain; + return sizeof (*grp); +} + +/* + * J/P Message Format + * + * While the RFC clearly states that this is 32 bits wide, it + * is cheating. These fields: + * Encoded-Unicast format (6 bytes MIN) + * Encoded-Group format (8 bytes MIN) + * Encoded-Source format (8 bytes MIN) + * are *not* 32 bits wide. + * + * Nor does the RFC explicitly call out the size for: + * Reserved (1 byte) + * Num Groups (1 byte) + * Holdtime (2 bytes) + * Number of Joined Sources (2 bytes) + * Number of Pruned Sources (2 bytes) + * + * This leads to a missleading representation from casual + * reading and making assumptions. Be careful! + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |PIM Ver| Type | Reserved | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Upstream Neighbor Address (Encoded-Unicast format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | Num groups | Holdtime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Multicast Group Address 1 (Encoded-Group format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Joined Sources | Number of Pruned Sources | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Joined Source Address 1 (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | . | + * | . | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Joined Source Address n (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Pruned Source Address 1 (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | . | + * | . | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Pruned Source Address n (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Multicast Group Address m (Encoded-Group format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Joined Sources | Number of Pruned Sources | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Joined Source Address 1 (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | . | + * | . | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Joined Source Address n (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Pruned Source Address 1 (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | . | + * | . | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Pruned Source Address n (Encoded-Source format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +int +pim_msg_join_prune_encode (uint8_t *buf, size_t buf_size, int is_join, + struct pim_upstream *up, + struct in_addr upstream, int holdtime) +{ + struct pim_jp *msg = (struct pim_jp *)buf; + + assert(buf_size > sizeof (struct pim_jp)); + + if (!pim_msg_addr_encode_ipv4_ucast ((uint8_t *)&msg->addr, upstream)) { + char dst_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", upstream, dst_str, sizeof(dst_str)); + zlog_warn("%s: failure encoding destination address %s", + __PRETTY_FUNCTION__, dst_str); + return -3; + } + + msg->reserved = 0; + msg->num_groups = 1; + msg->holdtime = htons(holdtime); + + if (!pim_msg_addr_encode_ipv4_group ((uint8_t *)&msg->groups[0].g, up->sg.grp)) { + char group_str[INET_ADDRSTRLEN]; + pim_inet4_dump("", up->sg.grp, group_str, sizeof(group_str)); + zlog_warn("%s: failure encoding group address %s", + __PRETTY_FUNCTION__, group_str); + return -5; + } + + pim_msg_build_jp_groups (&msg->groups[0], up, is_join); + + pim_msg_build_header (buf, sizeof (struct pim_jp), PIM_MSG_TYPE_JOIN_PRUNE); + + return sizeof (struct pim_jp); } diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 5229f85c72..3af8486d5d 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -35,25 +35,66 @@ */ #define PIM_MSG_ADDRESS_FAMILY_IPV4 (1) -void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, - uint8_t pim_msg_type); -uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, - int buf_size, - struct in_addr addr); -uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, - int buf_size, - struct in_addr addr); +/* + * Network Order pim_msg_hdr + */ +struct pim_msg_header { + uint8_t type:4; + uint8_t ver:4; + uint8_t reserved; + uint16_t checksum; +} __attribute__ ((packed)); + +struct pim_encoded_ipv4_unicast { + uint8_t family; + uint8_t reserved; + struct in_addr addr; +} __attribute__ ((packed)); + +struct pim_encoded_group_ipv4 { + uint8_t ne; + uint8_t family; + uint8_t reserved; + uint8_t mask; + struct in_addr addr; +} __attribute__ ((packed)); + +struct pim_encoded_source_ipv4 { + uint8_t ne; + uint8_t family; + uint8_t bits; + uint8_t mask; + struct in_addr addr; +} __attribute__ ((packed)); + +struct pim_jp_groups { + struct pim_encoded_group_ipv4 g; + uint16_t joins; + uint16_t prunes; + struct pim_encoded_source_ipv4 s[1]; +} __attribute__ ((packed)); + +struct pim_jp { + struct pim_msg_header header; + struct pim_encoded_ipv4_unicast addr; + uint8_t reserved; + uint8_t num_groups; + uint16_t holdtime; + struct pim_jp_groups groups[1]; +} __attribute__ ((packed)); + +void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, uint8_t pim_msg_type); +uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr); +uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr); #define PIM_ENCODE_SPARSE_BIT 0x04 #define PIM_ENCODE_WC_BIT 0x02 #define PIM_ENCODE_RPT_BIT 0x01 uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, - int buf_size, - struct in_addr addr, - uint8_t bits); + struct in_addr addr, uint8_t bits); -int pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join, - struct pim_upstream *up, - struct in_addr upstream, int holdtime); +int pim_msg_join_prune_encode (uint8_t *buf, size_t buf_size, int is_join, + struct pim_upstream *up, + struct in_addr upstream, int holdtime); #endif /* PIM_MSG_H */ diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 4c5eff4883..3e9d6c5a89 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -133,27 +133,40 @@ void pim_channel_oil_free(struct channel_oil *c_oil) XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil); } -static void -pim_del_channel_oil (struct channel_oil *c_oil) +static struct channel_oil * +pim_find_channel_oil(struct prefix_sg *sg) { - /* - notice that listnode_delete() can't be moved - into pim_channel_oil_free() because the later is - called by list_delete_all_node() - */ - listnode_delete(pim_channel_oil_list, c_oil); - hash_release (pim_channel_oil_hash, c_oil); + struct channel_oil *c_oil = NULL; + struct channel_oil lookup; - pim_channel_oil_free(c_oil); + lookup.oil.mfcc_mcastgrp = sg->grp; + lookup.oil.mfcc_origin = sg->src; + + c_oil = hash_lookup (pim_channel_oil_hash, &lookup); + + return c_oil; } -static struct channel_oil * -pim_add_channel_oil (struct prefix_sg *sg, - int input_vif_index) +struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg, + int input_vif_index) { struct channel_oil *c_oil; struct interface *ifp; + c_oil = pim_find_channel_oil(sg); + if (c_oil) { + if (c_oil->oil.mfcc_parent != input_vif_index) + { + c_oil->oil_inherited_rescan = 1; + if (PIM_DEBUG_MROUTE) + zlog_debug ("%s: Existing channel oil %s points to %d, modifying to point at %d", + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), c_oil->oil.mfcc_parent, input_vif_index); + } + c_oil->oil.mfcc_parent = input_vif_index; + ++c_oil->oil_ref_count; + return c_oil; + } + ifp = pim_if_find_by_vif_index(input_vif_index); if (!ifp) { /* warning only */ @@ -181,47 +194,20 @@ pim_add_channel_oil (struct prefix_sg *sg, return c_oil; } -static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg) -{ - struct channel_oil *c_oil = NULL; - struct channel_oil lookup; - - lookup.oil.mfcc_mcastgrp = sg->grp; - lookup.oil.mfcc_origin = sg->src; - - c_oil = hash_lookup (pim_channel_oil_hash, &lookup); - - return c_oil; -} - -struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg, - int input_vif_index) -{ - struct channel_oil *c_oil; - - c_oil = pim_find_channel_oil(sg); - if (c_oil) { - if (c_oil->oil.mfcc_parent != input_vif_index) - { - c_oil->oil_inherited_rescan = 1; - if (PIM_DEBUG_MROUTE) - zlog_debug ("%s: Existing channel oil %s points to %d, modifying to point at %d", - __PRETTY_FUNCTION__, pim_str_sg_dump(sg), c_oil->oil.mfcc_parent, input_vif_index); - } - c_oil->oil.mfcc_parent = input_vif_index; - ++c_oil->oil_ref_count; - return c_oil; - } - - return pim_add_channel_oil(sg, input_vif_index); -} - void pim_channel_oil_del(struct channel_oil *c_oil) { --c_oil->oil_ref_count; if (c_oil->oil_ref_count < 1) { - pim_del_channel_oil(c_oil); + /* + * notice that listnode_delete() can't be moved + * into pim_channel_oil_free() because the later is + * called by list_delete_all_node() + */ + listnode_delete(pim_channel_oil_list, c_oil); + hash_release (pim_channel_oil_hash, c_oil); + + pim_channel_oil_free(c_oil); } } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index e4c654557a..471d8aa39e 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -135,11 +135,10 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) char dst_str[INET_ADDRSTRLEN]; uint8_t *pim_msg; int pim_msg_len; - uint8_t pim_version; - enum pim_msg_type pim_type; uint16_t pim_checksum; /* received checksum */ uint16_t checksum; /* computed checksum */ struct pim_neighbor *neigh; + struct pim_msg_header *header; if (len < sizeof(*ip_hdr)) { if (PIM_DEBUG_PIM_PACKETS) @@ -151,29 +150,10 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) ip_hdr = (struct ip *) buf; ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ - if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug("IP packet protocol=%d is not PIM=%d", - ip_hdr->ip_p, PIM_IP_PROTO_PIM); - return -1; - } - - if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug("IP packet header size=%zu shorter than minimum=%d", - ip_hlen, PIM_IP_HEADER_MIN_LEN); - return -1; - } - if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug("IP packet header size=%zu greater than maximum=%d", - ip_hlen, PIM_IP_HEADER_MAX_LEN); - return -1; - } - pim_msg = buf + ip_hlen; pim_msg_len = len - ip_hlen; + header = (struct pim_msg_header *)pim_msg; if (pim_msg_len < PIM_PIM_MIN_LEN) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug("PIM message size=%d shorter than minimum=%d", @@ -181,23 +161,20 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) return -1; } - pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg); - pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg); - - if (pim_version != PIM_PROTO_VERSION) { + if (header->ver != PIM_PROTO_VERSION) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug("Ignoring PIM pkt from %s with unsupported version: %d", - ifp->name, pim_version); + ifp->name, header->ver); return -1; } /* save received checksum */ - pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg); + pim_checksum = header->checksum; /* for computing checksum */ - *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; + header->checksum = 0; - if (pim_type == PIM_MSG_TYPE_REGISTER) + if (header->type == PIM_MSG_TYPE_REGISTER) { /* First 8 byte header checksum */ checksum = in_cksum (pim_msg, PIM_MSG_REGISTER_LEN); @@ -233,14 +210,14 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) pim_inet4_dump("", ip_hdr->ip_src, src_str, sizeof(src_str)); pim_inet4_dump("", ip_hdr->ip_dst, dst_str, sizeof(dst_str)); zlog_debug("Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x", - pim_pim_msgtype2str (pim_type), src_str, dst_str, ifp->name, - ip_hdr->ip_ttl, pim_version, pim_msg_len, checksum); + pim_pim_msgtype2str (header->type), src_str, dst_str, ifp->name, + ip_hdr->ip_ttl, header->ver, pim_msg_len, checksum); if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len); } } - switch (pim_type) + switch (header->type) { case PIM_MSG_TYPE_HELLO: return pim_hello_recv (ifp, @@ -265,7 +242,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s", __FILE__, __PRETTY_FUNCTION__, - pim_type, src_str, ifp->name); + header->type, src_str, ifp->name); return -1; } pim_neighbor_timer_reset(neigh, neigh->holdtime); @@ -280,7 +257,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s", __FILE__, __PRETTY_FUNCTION__, - pim_type, src_str, ifp->name); + header->type, src_str, ifp->name); return -1; } pim_neighbor_timer_reset(neigh, neigh->holdtime); @@ -292,7 +269,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) default: if (PIM_DEBUG_PIM_PACKETS) { zlog_debug("Recv PIM packet type %d which is not currently understood", - pim_type); + header->type); } return -1; } @@ -408,7 +385,6 @@ static void pim_sock_read_on(struct interface *ifp) pim_ifp->pim_sock_fd); } pim_ifp->t_pim_sock_read = NULL; - zassert(!pim_ifp->t_pim_sock_read); THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp, pim_ifp->pim_sock_fd); } @@ -558,7 +534,7 @@ pim_msg_send(int fd, struct in_addr src, unsigned char buffer[10000]; unsigned char *msg_start; uint8_t ttl = MAXTTL; - enum pim_msg_type pim_type = PIM_MSG_TYPE_HELLO; + struct pim_msg_header *header; struct ip *ip; memset (buffer, 0, 10000); @@ -567,6 +543,7 @@ pim_msg_send(int fd, struct in_addr src, msg_start = buffer + sizeof (struct ip); memcpy (msg_start, pim_msg, pim_msg_size); + header = (struct pim_msg_header *)pim_msg; /* * Omnios apparently doesn't have a #define for IP default * ttl that is the same as all other platforms. @@ -575,8 +552,7 @@ pim_msg_send(int fd, struct in_addr src, #define IPDEFTTL 64 #endif /* TTL for packets destine to ALL-PIM-ROUTERS is 1 */ - pim_type = PIM_MSG_HDR_GET_TYPE (pim_msg); - switch (pim_type) + switch (header->type) { case PIM_MSG_TYPE_HELLO: case PIM_MSG_TYPE_JOIN_PRUNE: @@ -607,12 +583,13 @@ pim_msg_send(int fd, struct in_addr src, ip->ip_len = htons (sendlen); if (PIM_DEBUG_PIM_PACKETS) { + struct pim_msg_header *header = (struct pim_msg_header *)pim_msg; char dst_str[INET_ADDRSTRLEN]; pim_inet4_dump("", dst, dst_str, sizeof(dst_str)); zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __PRETTY_FUNCTION__, dst_str, ifname, pim_msg_size, - *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)); + header->checksum); } memset(&to, 0, sizeof(to)); @@ -671,8 +648,7 @@ static int hello_send(struct interface *ifp, zassert(pim_msg_size >= PIM_PIM_MIN_LEN); zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE); - pim_msg_build_header(pim_msg, pim_msg_size, - PIM_MSG_TYPE_HELLO); + pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO); if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address, diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index 00c5f9012e..690b6c05cd 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -48,15 +48,6 @@ enum pim_msg_type { PIM_MSG_TYPE_CANDIDATE }; -#define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg) -#define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg) -#define PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) (((char *)(pim_msg)) + 1) -#define PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) (((char *)(pim_msg)) + 2) - -#define PIM_MSG_HDR_GET_VERSION(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_VERSION(pim_msg)) >> 4) -#define PIM_MSG_HDR_GET_TYPE(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_TYPE(pim_msg)) & 0xF) -#define PIM_MSG_HDR_GET_CHECKSUM(pim_msg) (*(uint16_t*) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)) - void pim_ifstat_reset(struct interface *ifp); void pim_sock_reset(struct interface *ifp); int pim_sock_add(struct interface *ifp); diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index ae00e347b5..40e035c3f4 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -184,14 +184,13 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1, (nh1->mrib_route_metric != nh2->mrib_route_metric); } -enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr) +enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old) { - struct prefix save_rpf_addr; - struct pim_nexthop save_nexthop; struct pim_rpf *rpf = &up->rpf; + struct pim_rpf saved; - save_nexthop = rpf->source_nexthop; /* detect change in pim_nexthop */ - save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */ + saved.source_nexthop = rpf->source_nexthop; + saved.rpf_addr = rpf->rpf_addr; if (pim_nexthop_lookup(&rpf->source_nexthop, up->upstream_addr, @@ -211,7 +210,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_ } /* detect change in pim_nexthop */ - if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) { + if (nexthop_mismatch(&rpf->source_nexthop, &saved.source_nexthop)) { if (PIM_DEBUG_ZEBRA) { char nhaddr_str[PREFIX_STRLEN]; @@ -231,27 +230,29 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_ } /* detect change in RPF_interface(S) */ - if (save_nexthop.interface != rpf->source_nexthop.interface) { + if (saved.source_nexthop.interface != rpf->source_nexthop.interface) { if (PIM_DEBUG_ZEBRA) { zlog_debug("%s %s: (S,G)=%s RPF_interface(S) changed from %s to %s", __FILE__, __PRETTY_FUNCTION__, up->sg_str, - save_nexthop.interface ? save_nexthop.interface->name : "", + saved.source_nexthop.interface ? saved.source_nexthop.interface->name : "", rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""); /* warning only */ } - pim_upstream_rpf_interface_changed(up, save_nexthop.interface); + pim_upstream_rpf_interface_changed(up, saved.source_nexthop.interface); } /* detect change in RPF'(S,G) */ - if (save_rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) { + if (saved.rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) { /* return old rpf to caller ? */ - if (old_rpf_addr) - *old_rpf_addr = save_rpf_addr.u.prefix4; - + if (old) + { + old->source_nexthop = saved.source_nexthop; + old->rpf_addr = saved.rpf_addr; + } return PIM_RPF_CHANGED; } diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index bb77775324..51e84b4593 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -63,7 +63,7 @@ struct pim_upstream; extern long long nexthop_lookups_avoided; int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed); -enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr); +enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old); int pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf); int pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf); diff --git a/pimd/pim_static.c b/pimd/pim_static.c index e1ccec387a..daaa95ab57 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -316,27 +316,34 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr int pim_static_write_mroute (struct vty *vty, struct interface *ifp) { + struct pim_interface *pim_ifp = ifp->info; struct listnode *node; struct static_route *sroute; int count = 0; char sbuf[INET_ADDRSTRLEN]; char gbuf[INET_ADDRSTRLEN]; + if (!pim_ifp) + return 0; + for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute)) { pim_inet4_dump ("", sroute->group, gbuf, sizeof (gbuf)); pim_inet4_dump ("", sroute->source, sbuf, sizeof (sbuf)); - if (sroute->iif == ifp->ifindex) - { - int i; - for (i = 0; i < MAXVIFS; i++) - if (sroute->oif_ttls[i]) - { - struct interface *oifp = if_lookup_by_index (i); - vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE); - count ++; - } - } + if (sroute->iif == pim_ifp->mroute_vif_index) + { + int i; + for (i = 0; i < MAXVIFS; i++) + if (sroute->oif_ttls[i]) + { + struct interface *oifp = pim_if_find_by_vif_index (i); + if (sroute->source.s_addr == 0) + vty_out (vty, " ip mroute %s %s%s", oifp->name, gbuf, VTY_NEWLINE); + else + vty_out (vty, " ip mroute %s %s %s%s", oifp->name, gbuf, sbuf, VTY_NEWLINE); + count ++; + } + } } return count; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 4ae49c0fd4..1712acaa1e 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -171,9 +171,7 @@ pim_upstream_del(struct pim_upstream *up, const char *name) THREAD_OFF(up->t_msdp_reg_timer); if (up->join_state == PIM_UPSTREAM_JOINED) { - pim_joinprune_send (up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4, - up, 0); + pim_joinprune_send (&up->rpf, up, 0); if (up->sg.src.s_addr == INADDR_ANY) { /* if a (*, G) entry in the joined state is being deleted we * need to notify MSDP */ @@ -231,10 +229,7 @@ pim_upstream_send_join (struct pim_upstream *up) } /* send Join(S,G) to the current upstream neighbor */ - pim_joinprune_send(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4, - up, - 1 /* join */); + pim_joinprune_send(&up->rpf, up, 1 /* join */); } static int on_join_timer(struct thread *t) @@ -334,8 +329,7 @@ void pim_upstream_join_suppress(struct pim_upstream *up, } void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, - struct pim_upstream *up, - struct in_addr rpf_addr) + struct pim_upstream *up) { long join_timer_remain_msec; int t_override_msec; @@ -345,7 +339,7 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, if (PIM_DEBUG_TRACE) { char rpf_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); + pim_inet4_dump("", up->rpf.rpf_addr.u.prefix4, rpf_str, sizeof(rpf_str)); zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec", debug_label, up->sg_str, rpf_str, @@ -488,10 +482,7 @@ pim_upstream_switch(struct pim_upstream *up, forward_off(up); if (old_state == PIM_UPSTREAM_JOINED) pim_msdp_up_join_state_changed(up); - pim_joinprune_send(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4, - up, - 0 /* prune */); + pim_joinprune_send(&up->rpf, up, 0 /* prune */); if (up->t_join_timer) THREAD_OFF(up->t_join_timer); } @@ -662,7 +653,7 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, return up; } -static int +int pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up, struct pim_ifchannel *ch) { @@ -803,7 +794,7 @@ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr) continue; pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change", - up, neigh_addr); + up); } } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 1a50c0c6e3..f36b6fba8b 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -129,14 +129,17 @@ struct pim_upstream *pim_upstream_add (struct prefix_sg *sg, void pim_upstream_del(struct pim_upstream *up, const char *name); int pim_upstream_evaluate_join_desired(struct pim_upstream *up); +int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up, + struct pim_ifchannel *ch); void pim_upstream_update_join_desired(struct pim_upstream *up); void pim_upstream_join_suppress(struct pim_upstream *up, struct in_addr rpf_addr, int holdtime); + void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, - struct pim_upstream *up, - struct in_addr rpf_addr); + struct pim_upstream *up); + void pim_upstream_join_timer_restart(struct pim_upstream *up); void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr); void pim_upstream_rpf_interface_changed(struct pim_upstream *up, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 1bb4852c6b..0f92b4a7b0 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -366,12 +366,11 @@ static void scan_upstream_rpf_cache() struct pim_upstream *up; for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { - struct in_addr old_rpf_addr; - struct interface *old_interface; enum pim_rpf_result rpf_result; + struct pim_rpf old; - old_interface = up->rpf.source_nexthop.interface; - rpf_result = pim_rpf_update(up, &old_rpf_addr); + old.source_nexthop.interface = up->rpf.source_nexthop.interface; + rpf_result = pim_rpf_update(up, &old); if (rpf_result == PIM_RPF_FAILURE) continue; @@ -412,14 +411,10 @@ static void scan_upstream_rpf_cache() /* send Prune(S,G) to the old upstream neighbor */ - pim_joinprune_send(old_interface, old_rpf_addr, - up, 0 /* prune */); + pim_joinprune_send(&old, up, 0 /* prune */); /* send Join(S,G) to the current upstream neighbor */ - pim_joinprune_send(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4, - up, - 1 /* join */); + pim_joinprune_send(&up->rpf, up, 1 /* join */); pim_upstream_join_timer_restart(up); } /* up->join_state == PIM_UPSTREAM_JOINED */ diff --git a/pimd/pimd.h b/pimd/pimd.h index 1f8dcdfb29..0da8452ab5 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -31,13 +31,41 @@ #define PIMD_DEFAULT_CONFIG "pimd.conf" #define PIMD_VTY_PORT 2611 -#define PIM_IP_HEADER_MIN_LEN (20) -#define PIM_IP_HEADER_MAX_LEN (60) #define PIM_IP_PROTO_IGMP (2) #define PIM_IP_PROTO_PIM (103) #define PIM_IGMP_MIN_LEN (8) + +/* + * PIM MSG Header Format + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |PIM Ver| Type | Reserved | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ #define PIM_MSG_HEADER_LEN (4) #define PIM_PIM_MIN_LEN PIM_MSG_HEADER_LEN + +#define PIM_ENCODED_IPV4_UCAST_SIZE (6) +#define PIM_ENCODED_IPV4_GROUP_SIZE (8) +#define PIM_ENCODED_IPV4_SOURCE_SIZE (8) + +/* + * J/P Message Format, Group Header + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Upstream Neighbor Address (Encoded-Unicast format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | Num groups | Holdtime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Multicast Group Address 1 (Encoded-Group format) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Joined Sources | Number of Pruned Sources | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +#define PIM_JP_GROUP_HEADER_SIZE (PIM_ENCODED_IPV4_UCAST_SIZE + \ + 1 + 1 + 2 + \ + PIM_ENCODED_IPV4_GROUP_SIZE + \ + 2 + 2) + #define PIM_PROTO_VERSION (2) #define MCAST_ALL_SYSTEMS "224.0.0.1"