* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/* based on draft-ietf-idmr-traceroute-ipm-07 */
+
#include <zebra.h>
#include "pimd.h"
return any;
}
+static bool mtrace_fwd_info_weak(struct pim_instance *pim,
+ struct igmp_mtrace *mtracep,
+ struct igmp_mtrace_rsp *rspp,
+ struct interface **ifpp)
+{
+ struct pim_nexthop nexthop;
+ struct interface *ifp_in;
+ struct in_addr nh_addr;
+ char nexthop_str[INET_ADDRSTRLEN];
+
+ nh_addr.s_addr = 0;
+
+ memset(&nexthop, 0, sizeof(nexthop));
+
+ if (!pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1)) {
+ if (PIM_DEBUG_MTRACE)
+ zlog_debug("mtrace not found neighbor");
+ return false;
+ }
+
+ if (PIM_DEBUG_MTRACE)
+ zlog_debug("mtrace pim_nexthop_lookup OK");
+
+ if (PIM_DEBUG_MTRACE)
+ zlog_warn("mtrace next_hop=%s",
+ inet_ntop(nexthop.mrib_nexthop_addr.family,
+ &nexthop.mrib_nexthop_addr.u.prefix,
+ nexthop_str, sizeof(nexthop_str)));
+
+ if (nexthop.mrib_nexthop_addr.family == AF_INET)
+ nh_addr = nexthop.mrib_nexthop_addr.u.prefix4;
+
+ ifp_in = nexthop.interface;
+
+ /* return interface for forwarding mtrace packets */
+ *ifpp = ifp_in;
+
+ /* 6.2.2. 4. Fill in the Incoming Interface Address... */
+ rspp->incoming = mtrace_primary_address(ifp_in);
+ rspp->prev_hop = nh_addr;
+ rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
+ rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
+ rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
+ return true;
+}
+
+static bool mtrace_fwd_info(struct pim_instance *pim,
+ struct igmp_mtrace *mtracep,
+ struct igmp_mtrace_rsp *rspp,
+ struct interface **ifpp)
+{
+ struct prefix_sg sg;
+ struct pim_upstream *up;
+ struct interface *ifp_in;
+ struct in_addr nh_addr;
+ uint32_t total;
+ char up_str[INET_ADDRSTRLEN];
+
+ memset(&sg, 0, sizeof(struct prefix_sg));
+ sg.src = mtracep->src_addr;
+ sg.grp = mtracep->grp_addr;
+
+ up = pim_upstream_find(pim, &sg);
+
+ if (!up) {
+ sg.src.s_addr = 0;
+ up = pim_upstream_find(pim, &sg);
+ }
+
+ if (!up)
+ return false;
+
+ if (!up->rpf.source_nexthop.interface) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: up %s RPF is not present",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return false;
+ }
+
+ ifp_in = up->rpf.source_nexthop.interface;
+ nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4;
+ total = htonl(MTRACE_UNKNOWN_COUNT);
+
+ if (PIM_DEBUG_MTRACE)
+ zlog_debug("fwd_info: upstream next hop=%s",
+ inet_ntop(AF_INET, &(nh_addr), up_str,
+ sizeof(up_str)));
+
+ if (up->channel_oil)
+ total = up->channel_oil->cc.pktcnt;
+
+ /* return interface for forwarding mtrace packets */
+ *ifpp = ifp_in;
+
+ /* 6.2.2. 4. Fill in the Incoming Interface Address... */
+ rspp->incoming = mtrace_primary_address(ifp_in);
+ rspp->prev_hop = nh_addr;
+ rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
+ rspp->total = total;
+ rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
+
+ /* 6.2.2. 4. Fill in ... S, and Src Mask */
+ if (sg.src.s_addr) {
+ rspp->s = 1;
+ rspp->src_mask = MTRACE_SRC_MASK_SOURCE;
+ } else {
+ rspp->s = 0;
+ rspp->src_mask = MTRACE_SRC_MASK_GROUP;
+ }
+
+ return true;
+}
+
+static void mtrace_rsp_set_fwd_code(struct igmp_mtrace_rsp *mtrace_rspp,
+ enum mtrace_fwd_code fwd_code)
+{
+ if (mtrace_rspp->fwd_code == MTRACE_FWD_CODE_NO_ERROR)
+ mtrace_rspp->fwd_code = fwd_code;
+}
+
static void mtrace_rsp_init(struct igmp_mtrace_rsp *mtrace_rspp)
{
mtrace_rspp->arrival = 0;
mtrace_rspp->incoming.s_addr = 0;
mtrace_rspp->outgoing.s_addr = 0;
mtrace_rspp->prev_hop.s_addr = 0;
- mtrace_rspp->in_count = MTRACE_UNKNOWN_COUNT;
- mtrace_rspp->out_count = MTRACE_UNKNOWN_COUNT;
- mtrace_rspp->total = MTRACE_UNKNOWN_COUNT;
+ mtrace_rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
+ mtrace_rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
+ mtrace_rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
mtrace_rspp->rtg_proto = 0;
mtrace_rspp->fwd_ttl = 0;
mtrace_rspp->mbz = 0;
int fd;
char if_str[INET_ADDRSTRLEN];
char rsp_str[INET_ADDRSTRLEN];
- u_char ttl;
+ uint8_t ttl;
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
if (interface == NULL) {
memset(&nexthop, 0, sizeof(nexthop));
- ret = pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0);
-
- if (ret != 0) {
+ if (!pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0)) {
close(fd);
if (PIM_DEBUG_MTRACE)
zlog_warn(
return mtrace_un_forward_packet(pim, ip_hdr, NULL);
}
-/* 6.5 Sending Traceroute Responses */
static int mtrace_send_mc_response(struct pim_instance *pim,
struct igmp_mtrace *mtracep,
size_t mtrace_len)
return ret;
}
+/* 6.5 Sending Traceroute Responses */
static int mtrace_send_response(struct pim_instance *pim,
struct igmp_mtrace *mtracep, size_t mtrace_len)
{
struct pim_nexthop nexthop;
- int ret;
mtracep->type = PIM_IGMP_MTRACE_RESPONSE;
} else {
memset(&nexthop, 0, sizeof(nexthop));
/* TODO: should use unicast rib lookup */
- ret = pim_nexthop_lookup(pim, &nexthop, mtracep->rsp_addr, 1);
-
- if (ret != 0) {
+ if (!pim_nexthop_lookup(pim, &nexthop, mtracep->rsp_addr, 1)) {
if (PIM_DEBUG_MTRACE)
zlog_warn(
"Dropped response qid=%ud, no route to "
{
static uint32_t qry_id, qry_src;
char mtrace_buf[MTRACE_HDR_SIZE + MTRACE_MAX_HOPS * MTRACE_RSP_SIZE];
- struct pim_nexthop nexthop;
struct interface *ifp;
- struct interface *out_ifp;
+ struct interface *out_ifp = NULL;
struct pim_interface *pim_ifp;
struct pim_instance *pim;
struct igmp_mtrace *mtracep;
struct igmp_mtrace_rsp *rspp;
struct in_addr nh_addr;
enum mtrace_fwd_code fwd_code = MTRACE_FWD_CODE_NO_ERROR;
- int ret;
size_t r_len;
int last_rsp_ind = 0;
size_t mtrace_len;
uint16_t recv_checksum;
uint16_t checksum;
+ bool reached_source;
+ bool fwd_info;
ifp = igmp->interface;
pim_ifp = ifp->info;
return -1;
}
+ /* Collecting IGMP Rx stats */
+ igmp->rx_stats.mtrace_req++;
+
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
}
/* Unicast query on wrong interface */
fwd_code = MTRACE_FWD_CODE_WRONG_IF;
+ if (PIM_DEBUG_MTRACE)
+ zlog_debug("Multicast query on wrong interface");
}
if (qry_id == mtracep->qry_id && qry_src == from.s_addr) {
if (PIM_DEBUG_MTRACE)
/* 6.2.2. Normal Processing */
- /* 6.2.2. 1. */
+ /* 6.2.2. 1. If there is room in the current buffer? */
if (last_rsp_ind == MTRACE_MAX_HOPS) {
+ /* ...there was no room... */
mtracep->rsp[MTRACE_MAX_HOPS - 1].fwd_code =
MTRACE_FWD_CODE_NO_SPACE;
return mtrace_send_response(pim_ifp->pim, mtracep,
igmp_msg_len);
}
- /* calculate new mtrace mtrace lenght with extra response */
+ /* ...insert new response block... */
+
+ /* calculate new mtrace lenght with extra response */
mtrace_len = igmp_msg_len + sizeof(struct igmp_mtrace_rsp);
/* copy received query/request */
/* initialize extra response field */
mtrace_rsp_init(rspp);
+ /* carry over any error noted when receiving the query */
+ rspp->fwd_code = fwd_code;
+
+ /* ...and fill in Query Arrival Time... */
rspp->arrival = htonl(query_arrival_time());
rspp->outgoing = pim_ifp->primary_address;
rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
+ rspp->fwd_ttl = 1;
- /* 6.2.2. 2. Attempt to determine forwarding information */
-
- nh_addr.s_addr = 0;
-
- memset(&nexthop, 0, sizeof(nexthop));
- ret = pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1);
-
- if (ret == 0) {
- char nexthop_str[INET_ADDRSTRLEN];
-
- if (PIM_DEBUG_MTRACE)
- zlog_debug("mtrace pim_nexthop_lookup OK");
+ /* 6.2.2. 2. Attempt to determine the forwarding information... */
- if (PIM_DEBUG_MTRACE)
- zlog_warn("mtrace next_hop=%s",
- inet_ntop(nexthop.mrib_nexthop_addr.family,
- &nexthop.mrib_nexthop_addr.u.prefix,
- nexthop_str, sizeof(nexthop_str)));
+ if (mtracep->grp_addr.s_addr)
+ fwd_info = mtrace_fwd_info(pim, mtracep, rspp, &out_ifp);
+ else
+ fwd_info = mtrace_fwd_info_weak(pim, mtracep, rspp, &out_ifp);
- if (nexthop.mrib_nexthop_addr.family == AF_INET)
- nh_addr = nexthop.mrib_nexthop_addr.u.prefix4;
- }
- /* 6.4 Forwarding Traceroute Requests: ... Otherwise, ... */
- else {
+ /* 6.2.2 3. If no forwarding information... */
+ if (!fwd_info) {
if (PIM_DEBUG_MTRACE)
- zlog_debug("mtrace not found neighbor");
- if (!fwd_code)
- rspp->fwd_code = MTRACE_FWD_CODE_NO_ROUTE;
- else
- rspp->fwd_code = fwd_code;
- /* 6.5 Sending Traceroute Responses */
+ zlog_debug("mtrace not found multicast state");
+ mtrace_rsp_set_fwd_code(rspp, MTRACE_FWD_CODE_NO_ROUTE);
+ /* 6.2.2. 3. forward the packet to requester */
return mtrace_send_response(pim, mtracep, mtrace_len);
}
- out_ifp = nexthop.interface;
+ nh_addr = rspp->prev_hop;
- rspp->incoming = mtrace_primary_address(out_ifp);
- rspp->prev_hop = nh_addr;
- rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
- rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
- rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
- rspp->fwd_ttl = 1;
- rspp->s = 1;
- rspp->src_mask = 32;
+ reached_source = false;
if (nh_addr.s_addr == 0) {
- /* no pim? */
+ /* no pim? i.e. 7.5.3. No Previous Hop */
if (!out_ifp->info) {
- rspp->fwd_code = MTRACE_FWD_CODE_NO_MULTICAST;
+ if (PIM_DEBUG_MTRACE)
+ zlog_debug("mtrace not found incoming if w/ pim");
+ mtrace_rsp_set_fwd_code(rspp,
+ MTRACE_FWD_CODE_NO_MULTICAST);
return mtrace_send_response(pim, mtracep, mtrace_len);
}
- /* reached source? */
+ /* reached source? i.e. 7.5.1 Arriving at source */
if (pim_if_connected_to_source(out_ifp, mtracep->src_addr)) {
+ reached_source = true;
rspp->prev_hop = mtracep->src_addr;
- return mtrace_send_response(pim, mtracep, mtrace_len);
}
/*
* 6.4 Forwarding Traceroute Requests:
- * Previous-hop router not known
+ * Previous-hop router not known,
+ * packet is sent to an appropriate multicast address
*/
- inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
+ (void)inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
+ }
+
+ /* 6.2.2 8. If this router is the Rendez-vous Point */
+ if (pim_rp_i_am_rp(pim, mtracep->grp_addr)) {
+ mtrace_rsp_set_fwd_code(rspp, MTRACE_FWD_CODE_REACHED_RP);
+ /* 7.7.1. PIM-SM ...RP has not performed source-specific join */
+ if (rspp->src_mask == MTRACE_SRC_MASK_GROUP)
+ return mtrace_send_response(pim, mtracep, mtrace_len);
}
+ /*
+ * 6.4 Forwarding Traceroute Requests: the number of response
+ * blocks exceeds number of responses, so forward to the requester.
+ */
if (mtracep->hops <= (last_rsp_ind + 1))
return mtrace_send_response(pim, mtracep, mtrace_len);
+ /* 7.5.1. Arriving at source: terminate trace */
+ if (reached_source)
+ return mtrace_send_response(pim, mtracep, mtrace_len);
+
mtracep->checksum = 0;
mtracep->checksum = in_cksum(mtrace_buf, mtrace_len);
+ /* 6.4 Forwarding Traceroute Requests: response blocks less than req. */
return mtrace_send_packet(out_ifp, mtracep, mtrace_len, nh_addr,
mtracep->grp_addr);
}
+/* 6.3. Traceroute responses */
int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr,
struct in_addr from, const char *from_str,
char *igmp_msg, int igmp_msg_len)
mtracep->checksum = checksum;
+ /* Collecting IGMP Rx stats */
+ igmp->rx_stats.mtrace_rsp++;
+
if (PIM_DEBUG_MTRACE)
mtrace_debug(pim_ifp, mtracep, igmp_msg_len);