123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /*
- PIM for Quagga
- Copyright (C) 2008 Everton da Silva Marques
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING; if not, write to the
- Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- MA 02110-1301 USA
-
- $QuaggaId: $Format:%an, %ai, %h$ $
- */
- #include <zebra.h>
- #include "log.h"
- #include "prefix.h"
- #include "pimd.h"
- #include "pim_str.h"
- #include "pim_tlv.h"
- #include "pim_msg.h"
- #include "pim_pim.h"
- #include "pim_join.h"
- #include "pim_iface.h"
- #include "pim_hello.h"
- #include "pim_ifchannel.h"
- static void on_trace(const char *label,
- struct interface *ifp, struct in_addr src)
- {
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- 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 in_addr group,
- struct in_addr source,
- uint8_t source_flags)
- {
- if (PIM_DEBUG_PIM_TRACE) {
- char up_str[100];
- char src_str[100];
- char grp_str[100];
- char neigh_str[100];
- pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
- pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
- zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- source_flags & PIM_RPT_BIT_MASK,
- source_flags & PIM_WILDCARD_BIT_MASK,
- up_str, holdtime, neigh_str, ifp->name);
- }
-
- /* Restart join expiry timer */
- pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
- source, group, source_flags, holdtime);
- }
- static void recv_prune(struct interface *ifp,
- struct pim_neighbor *neigh,
- uint16_t holdtime,
- struct in_addr upstream,
- struct in_addr group,
- struct in_addr source,
- uint8_t source_flags)
- {
- if (PIM_DEBUG_PIM_TRACE) {
- char up_str[100];
- char src_str[100];
- char grp_str[100];
- char neigh_str[100];
- pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
- pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
- zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- source_flags & PIM_RPT_BIT_MASK,
- source_flags & PIM_WILDCARD_BIT_MASK,
- up_str, holdtime, neigh_str, ifp->name);
- }
-
- pim_ifchannel_prune(ifp, upstream, source, group, 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)
- {
- 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;
- on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
- buf = tlv_buf;
- pastend = tlv_buf + tlv_buf_size;
- /*
- Parse ucast addr
- */
- addr_offset = pim_parse_addr_ucast(ifp->name, src_addr,
- &msg_upstream_addr,
- buf, pastend - buf);
- #if 0
- zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d",
- __PRETTY_FUNCTION__,
- addr_offset);
- #endif
- if (addr_offset < 1) {
- char src_str[100];
- 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_TRACE) {
- char src_str[100];
- 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[100];
- 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_TRACE) {
- char src_str[100];
- char upstream_str[100];
- 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_warn("%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 msg_group_addr;
- struct prefix msg_source_addr;
- uint8_t msg_source_flags;
- uint16_t msg_num_joined_sources;
- uint16_t msg_num_pruned_sources;
- int source;
- addr_offset = pim_parse_addr_group(ifp->name, src_addr,
- &msg_group_addr,
- buf, pastend - buf);
- #if 0
- zlog_warn("%s: pim_parse_addr_group addr_offset=%d",
- __PRETTY_FUNCTION__,
- addr_offset);
- #endif
- if (addr_offset < 1) {
- return -5;
- }
- buf += addr_offset;
- remain = pastend - buf;
- if (remain < 4) {
- char src_str[100];
- 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_TRACE) {
- char src_str[100];
- char upstream_str[100];
- char group_str[100];
- 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?>", msg_group_addr.u.prefix4,
- group_str, sizeof(group_str));
- zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
- __PRETTY_FUNCTION__,
- upstream_str, group_str, msg_group_addr.prefixlen,
- 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(ifp->name, src_addr,
- &msg_source_addr,
- &msg_source_flags,
- buf, pastend - buf);
- #if 0
- zlog_warn("%s: pim_parse_addr_source addr_offset=%d",
- __PRETTY_FUNCTION__,
- addr_offset);
- #endif
- if (addr_offset < 1) {
- return -7;
- }
- buf += addr_offset;
- recv_join(ifp, neigh, msg_holdtime,
- msg_upstream_addr.u.prefix4,
- msg_group_addr.u.prefix4,
- msg_source_addr.u.prefix4,
- msg_source_flags);
- }
- /* Scan pruned sources */
- for (source = 0; source < msg_num_pruned_sources; ++source) {
- addr_offset = pim_parse_addr_source(ifp->name, src_addr,
- &msg_source_addr,
- &msg_source_flags,
- buf, pastend - buf);
- if (addr_offset < 1) {
- return -8;
- }
- buf += addr_offset;
- recv_prune(ifp, neigh, msg_holdtime,
- msg_upstream_addr.u.prefix4,
- msg_group_addr.u.prefix4,
- msg_source_addr.u.prefix4,
- msg_source_flags);
- }
- } /* scan groups */
- return 0;
- }
- int pim_joinprune_send(struct interface *ifp,
- struct in_addr upstream_addr,
- struct in_addr source_addr,
- struct in_addr group_addr,
- int send_join)
- {
- struct pim_interface *pim_ifp;
- uint8_t pim_msg[1000];
- const uint8_t *pastend = pim_msg + sizeof(pim_msg);
- uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
- int pim_msg_size;
- int remain;
- zassert(ifp);
- pim_ifp = ifp->info;
- if (!pim_ifp) {
- zlog_warn("%s: multicast not enabled on interface %s",
- __PRETTY_FUNCTION__,
- ifp->name);
- return -1;
- }
- if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- char dst_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
- zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
- __PRETTY_FUNCTION__,
- send_join ? "Join" : "Prune",
- source_str, group_str, dst_str, ifp->name);
- }
- if (PIM_INADDR_IS_ANY(upstream_addr)) {
- if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- char dst_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
- zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
- __PRETTY_FUNCTION__,
- send_join ? "Join" : "Prune",
- source_str, group_str, dst_str, ifp->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(ifp);
- /*
- Build PIM message
- */
- remain = pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
- remain,
- upstream_addr);
- if (!pim_msg_curr) {
- char dst_str[100];
- pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
- zlog_warn("%s: failure encoding destination address %s: space left=%d",
- __PRETTY_FUNCTION__, dst_str, remain);
- return -3;
- }
- remain = pastend - 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(PIM_JP_HOLDTIME);
- ++pim_msg_curr;
- ++pim_msg_curr;
- remain = pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
- remain,
- group_addr);
- if (!pim_msg_curr) {
- char group_str[100];
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: failure encoding group address %s: space left=%d",
- __PRETTY_FUNCTION__, group_str, remain);
- return -5;
- }
- remain = pastend - 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 */
- *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
- ++pim_msg_curr;
- ++pim_msg_curr;
- /* number of pruned sources */
- *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
- ++pim_msg_curr;
- ++pim_msg_curr;
- remain = pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
- remain,
- source_addr);
- if (!pim_msg_curr) {
- char source_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- zlog_warn("%s: failure encoding source address %s: space left=%d",
- __PRETTY_FUNCTION__, source_str, remain);
- return -7;
- }
- /* Add PIM header */
- pim_msg_size = pim_msg_curr - pim_msg;
- pim_msg_build_header(pim_msg, pim_msg_size,
- PIM_MSG_TYPE_JOIN_PRUNE);
- if (pim_msg_send(pim_ifp->pim_sock_fd,
- qpim_all_pim_routers_addr,
- pim_msg,
- pim_msg_size,
- ifp->name)) {
- zlog_warn("%s: could not send PIM message on interface %s",
- __PRETTY_FUNCTION__, ifp->name);
- return -8;
- }
- return 0;
- }
|