2 * Multicast traceroute for FRRouting
3 * Copyright (C) 2017 Mladen Sablic
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 /* based on draft-ietf-idmr-traceroute-ipm-07 */
25 #include "pim_instance.h"
30 #include "pim_ifchannel.h"
31 #include "pim_macro.h"
32 #include "pim_igmp_mtrace.h"
34 static struct in_addr
mtrace_primary_address(struct interface
*ifp
)
36 struct connected
*ifc
;
37 struct listnode
*node
;
39 struct pim_interface
*pim_ifp
;
43 return pim_ifp
->primary_address
;
46 any
.s_addr
= INADDR_ANY
;
48 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
49 struct prefix
*p
= ifc
->address
;
51 if (p
->family
!= AF_INET
)
54 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
56 /* in case no primary found, return a secondary */
62 static bool mtrace_fwd_info_weak(struct pim_instance
*pim
,
63 struct igmp_mtrace
*mtracep
,
64 struct igmp_mtrace_rsp
*rspp
,
65 struct interface
**ifpp
)
67 struct pim_nexthop nexthop
;
68 struct interface
*ifp_in
;
69 struct in_addr nh_addr
;
71 nh_addr
.s_addr
= INADDR_ANY
;
73 memset(&nexthop
, 0, sizeof(nexthop
));
75 if (!pim_nexthop_lookup(pim
, &nexthop
, mtracep
->src_addr
, 1)) {
77 zlog_debug("mtrace not found neighbor");
82 zlog_debug("mtrace pim_nexthop_lookup OK");
85 zlog_debug("mtrace next_hop=%pPAs", &nexthop
.mrib_nexthop_addr
);
87 nh_addr
= nexthop
.mrib_nexthop_addr
;
89 ifp_in
= nexthop
.interface
;
91 /* return interface for forwarding mtrace packets */
94 /* 6.2.2. 4. Fill in the Incoming Interface Address... */
95 rspp
->incoming
= mtrace_primary_address(ifp_in
);
96 rspp
->prev_hop
= nh_addr
;
97 rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
98 rspp
->total
= htonl(MTRACE_UNKNOWN_COUNT
);
99 rspp
->rtg_proto
= MTRACE_RTG_PROTO_PIM
;
103 static bool mtrace_fwd_info(struct pim_instance
*pim
,
104 struct igmp_mtrace
*mtracep
,
105 struct igmp_mtrace_rsp
*rspp
,
106 struct interface
**ifpp
)
109 struct pim_upstream
*up
;
110 struct interface
*ifp_in
;
111 struct in_addr nh_addr
;
114 memset(&sg
, 0, sizeof(sg
));
115 sg
.src
= mtracep
->src_addr
;
116 sg
.grp
= mtracep
->grp_addr
;
118 up
= pim_upstream_find(pim
, &sg
);
121 sg
.src
= PIMADDR_ANY
;
122 up
= pim_upstream_find(pim
, &sg
);
128 if (!up
->rpf
.source_nexthop
.interface
) {
130 zlog_debug("%s: up %s RPF is not present", __func__
,
135 ifp_in
= up
->rpf
.source_nexthop
.interface
;
136 nh_addr
= up
->rpf
.source_nexthop
.mrib_nexthop_addr
;
137 total
= htonl(MTRACE_UNKNOWN_COUNT
);
139 if (PIM_DEBUG_MTRACE
)
140 zlog_debug("fwd_info: upstream next hop=%pI4", &nh_addr
);
143 total
= up
->channel_oil
->cc
.pktcnt
;
145 /* return interface for forwarding mtrace packets */
148 /* 6.2.2. 4. Fill in the Incoming Interface Address... */
149 rspp
->incoming
= mtrace_primary_address(ifp_in
);
150 rspp
->prev_hop
= nh_addr
;
151 rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
153 rspp
->rtg_proto
= MTRACE_RTG_PROTO_PIM
;
155 /* 6.2.2. 4. Fill in ... S, and Src Mask */
156 if (!pim_addr_is_any(sg
.src
)) {
158 rspp
->src_mask
= MTRACE_SRC_MASK_SOURCE
;
161 rspp
->src_mask
= MTRACE_SRC_MASK_GROUP
;
167 static void mtrace_rsp_set_fwd_code(struct igmp_mtrace_rsp
*mtrace_rspp
,
168 enum mtrace_fwd_code fwd_code
)
170 if (mtrace_rspp
->fwd_code
== MTRACE_FWD_CODE_NO_ERROR
)
171 mtrace_rspp
->fwd_code
= fwd_code
;
174 static void mtrace_rsp_init(struct igmp_mtrace_rsp
*mtrace_rspp
)
176 mtrace_rspp
->arrival
= 0;
177 mtrace_rspp
->incoming
.s_addr
= INADDR_ANY
;
178 mtrace_rspp
->outgoing
.s_addr
= INADDR_ANY
;
179 mtrace_rspp
->prev_hop
.s_addr
= INADDR_ANY
;
180 mtrace_rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
181 mtrace_rspp
->out_count
= htonl(MTRACE_UNKNOWN_COUNT
);
182 mtrace_rspp
->total
= htonl(MTRACE_UNKNOWN_COUNT
);
183 mtrace_rspp
->rtg_proto
= 0;
184 mtrace_rspp
->fwd_ttl
= 0;
185 mtrace_rspp
->mbz
= 0;
187 mtrace_rspp
->src_mask
= 0;
188 mtrace_rspp
->fwd_code
= MTRACE_FWD_CODE_NO_ERROR
;
191 static void mtrace_rsp_debug(uint32_t qry_id
, int rsp
,
192 struct igmp_mtrace_rsp
*mrspp
)
194 struct in_addr incoming
= mrspp
->incoming
;
195 struct in_addr outgoing
= mrspp
->outgoing
;
196 struct in_addr prev_hop
= mrspp
->prev_hop
;
199 "Rx mt(%d) qid=%ud arr=%x in=%pI4 out=%pI4 prev=%pI4 proto=%d fwd=%d",
200 rsp
, ntohl(qry_id
), mrspp
->arrival
, &incoming
, &outgoing
,
201 &prev_hop
, mrspp
->rtg_proto
, mrspp
->fwd_code
);
204 static void mtrace_debug(struct pim_interface
*pim_ifp
,
205 struct igmp_mtrace
*mtracep
, int mtrace_len
)
207 struct in_addr ga
, sa
, da
, ra
;
209 ga
= mtracep
->grp_addr
;
210 sa
= mtracep
->src_addr
;
211 da
= mtracep
->dst_addr
;
212 ra
= mtracep
->rsp_addr
;
215 "Rx mtrace packet incoming on %pI4: hops=%d type=%d size=%d, grp=%pI4, src=%pI4, dst=%pI4 rsp=%pI4 ttl=%d qid=%ud",
216 &pim_ifp
->primary_address
, mtracep
->hops
, mtracep
->type
,
217 mtrace_len
, &ga
, &sa
, &da
, &ra
, mtracep
->rsp_ttl
,
218 ntohl(mtracep
->qry_id
));
219 if (mtrace_len
> (int)sizeof(struct igmp_mtrace
)) {
223 int responses
= mtrace_len
- sizeof(struct igmp_mtrace
);
225 if ((responses
% sizeof(struct igmp_mtrace_rsp
)) != 0)
226 if (PIM_DEBUG_MTRACE
)
228 "Mtrace response block of wrong length");
230 responses
= responses
/ sizeof(struct igmp_mtrace_rsp
);
232 for (i
= 0; i
< responses
; i
++)
233 mtrace_rsp_debug(mtracep
->qry_id
, i
, &mtracep
->rsp
[i
]);
237 /* 5.1 Query Arrival Time */
238 static uint32_t query_arrival_time(void)
243 if (gettimeofday(&tv
, NULL
) < 0) {
244 if (PIM_DEBUG_MTRACE
)
245 zlog_debug("Query arrival time lookup failed: errno=%d: %s",
246 errno
, safe_strerror(errno
));
249 /* not sure second offset correct, as I get different value */
250 qat
= ((tv
.tv_sec
+ 32384) << 16) + ((tv
.tv_usec
<< 10) / 15625);
255 static int mtrace_send_packet(struct interface
*ifp
,
256 struct igmp_mtrace
*mtracep
,
257 size_t mtrace_buf_len
, struct in_addr dst_addr
,
258 struct in_addr group_addr
)
260 struct sockaddr_in to
;
267 memset(&to
, 0, sizeof(to
));
268 to
.sin_family
= AF_INET
;
269 to
.sin_addr
= dst_addr
;
272 if (PIM_DEBUG_MTRACE
) {
273 struct in_addr if_addr
;
274 struct in_addr rsp_addr
= mtracep
->rsp_addr
;
276 if_addr
= mtrace_primary_address(ifp
);
277 zlog_debug("Sending mtrace packet to %pI4 on %pI4", &rsp_addr
,
281 fd
= pim_socket_raw(IPPROTO_IGMP
);
286 ret
= pim_socket_bind(fd
, ifp
);
293 if (IPV4_CLASS_DE(ntohl(dst_addr
.s_addr
))) {
294 if (IPV4_MC_LINKLOCAL(ntohl(dst_addr
.s_addr
))) {
297 if (mtracep
->type
== PIM_IGMP_MTRACE_RESPONSE
)
298 ttl
= mtracep
->rsp_ttl
;
302 ret
= setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
,
306 if (PIM_DEBUG_MTRACE
)
307 zlog_debug("Failed to set socket multicast TTL");
313 sent
= sendto(fd
, (char *)mtracep
, mtrace_buf_len
, MSG_DONTWAIT
,
314 (struct sockaddr
*)&to
, tolen
);
316 if (sent
!= (ssize_t
)mtrace_buf_len
) {
317 char dst_str
[INET_ADDRSTRLEN
];
318 char group_str
[INET_ADDRSTRLEN
];
320 pim_inet4_dump("<dst?>", dst_addr
, dst_str
, sizeof(dst_str
));
321 pim_inet4_dump("<group?>", group_addr
, group_str
,
324 if (PIM_DEBUG_MTRACE
)
326 "Send mtrace request failed for %s on%s: group=%s msg_size=%zd: errno=%d: %s",
327 dst_str
, ifp
->name
, group_str
,
328 mtrace_buf_len
, errno
,
329 safe_strerror(errno
));
331 if (PIM_DEBUG_MTRACE
)
333 "Send mtrace request failed for %s on %s: group=%s msg_size=%zd: sent=%zd",
334 dst_str
, ifp
->name
, group_str
,
335 mtrace_buf_len
, sent
);
346 static int mtrace_un_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
,
347 struct interface
*interface
)
349 struct pim_nexthop nexthop
;
350 struct sockaddr_in to
;
351 struct interface
*if_out
;
358 checksum
= ip_hdr
->ip_sum
;
362 if (checksum
!= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4))
365 if (ip_hdr
->ip_ttl
-- <= 1)
368 ip_hdr
->ip_sum
= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4);
370 fd
= pim_socket_raw(IPPROTO_RAW
);
375 pim_socket_ip_hdr(fd
);
377 if (interface
== NULL
) {
378 memset(&nexthop
, 0, sizeof(nexthop
));
379 if (!pim_nexthop_lookup(pim
, &nexthop
, ip_hdr
->ip_dst
, 0)) {
381 if (PIM_DEBUG_MTRACE
)
383 "Dropping mtrace packet, no route to destination");
387 if_out
= nexthop
.interface
;
392 ret
= pim_socket_bind(fd
, if_out
);
399 memset(&to
, 0, sizeof(to
));
400 to
.sin_family
= AF_INET
;
401 to
.sin_addr
= ip_hdr
->ip_dst
;
404 sent
= sendto(fd
, ip_hdr
, ntohs(ip_hdr
->ip_len
), 0,
405 (struct sockaddr
*)&to
, tolen
);
410 if (PIM_DEBUG_MTRACE
)
412 "Failed to forward mtrace packet: sendto errno=%d, %s",
413 errno
, safe_strerror(errno
));
417 if (PIM_DEBUG_MTRACE
) {
418 zlog_debug("Fwd mtrace packet len=%u to %pI4 ttl=%u",
419 ntohs(ip_hdr
->ip_len
), &ip_hdr
->ip_dst
,
426 static int mtrace_mc_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
429 struct channel_oil
*c_oil
;
430 struct listnode
*chnode
;
431 struct listnode
*chnextnode
;
432 struct pim_ifchannel
*ch
= NULL
;
435 memset(&sg
, 0, sizeof(sg
));
436 sg
.grp
= ip_hdr
->ip_dst
;
438 c_oil
= pim_find_channel_oil(pim
, &sg
);
441 if (PIM_DEBUG_MTRACE
) {
443 "Dropping mtrace multicast packet len=%u to %pI4 ttl=%u",
444 ntohs(ip_hdr
->ip_len
),
445 &ip_hdr
->ip_dst
, ip_hdr
->ip_ttl
);
449 if (c_oil
->up
== NULL
)
451 if (c_oil
->up
->ifchannels
== NULL
)
453 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
454 if (pim_macro_chisin_oiflist(ch
)) {
457 r
= mtrace_un_forward_packet(pim
, ip_hdr
,
467 static int mtrace_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
469 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
470 return mtrace_mc_forward_packet(pim
, ip_hdr
);
472 return mtrace_un_forward_packet(pim
, ip_hdr
, NULL
);
475 static int mtrace_send_mc_response(struct pim_instance
*pim
,
476 struct igmp_mtrace
*mtracep
,
480 struct channel_oil
*c_oil
;
481 struct listnode
*chnode
;
482 struct listnode
*chnextnode
;
483 struct pim_ifchannel
*ch
= NULL
;
486 memset(&sg
, 0, sizeof(sg
));
487 sg
.grp
= mtracep
->rsp_addr
;
489 c_oil
= pim_find_channel_oil(pim
, &sg
);
492 if (PIM_DEBUG_MTRACE
) {
493 struct in_addr rsp_addr
= mtracep
->rsp_addr
;
496 "Dropping mtrace multicast response packet len=%u to %pI4",
497 (unsigned int)mtrace_len
, &rsp_addr
);
501 if (c_oil
->up
== NULL
)
503 if (c_oil
->up
->ifchannels
== NULL
)
505 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
506 if (pim_macro_chisin_oiflist(ch
)) {
509 r
= mtrace_send_packet(ch
->interface
, mtracep
,
510 mtrace_len
, mtracep
->rsp_addr
,
519 /* 6.5 Sending Traceroute Responses */
520 static int mtrace_send_response(struct pim_instance
*pim
,
521 struct igmp_mtrace
*mtracep
, size_t mtrace_len
)
523 struct pim_nexthop nexthop
;
525 mtracep
->type
= PIM_IGMP_MTRACE_RESPONSE
;
527 mtracep
->checksum
= 0;
528 mtracep
->checksum
= in_cksum((char *)mtracep
, mtrace_len
);
530 if (IPV4_CLASS_DE(ntohl(mtracep
->rsp_addr
.s_addr
))) {
531 struct pim_rpf
*p_rpf
;
533 if (pim_rp_i_am_rp(pim
, mtracep
->rsp_addr
))
534 return mtrace_send_mc_response(pim
, mtracep
,
537 p_rpf
= pim_rp_g(pim
, mtracep
->rsp_addr
);
540 if (PIM_DEBUG_MTRACE
) {
541 struct in_addr rsp_addr
= mtracep
->rsp_addr
;
543 zlog_debug("mtrace no RP for %pI4", &rsp_addr
);
547 nexthop
= p_rpf
->source_nexthop
;
548 if (PIM_DEBUG_MTRACE
)
549 zlog_debug("mtrace response to RP");
551 memset(&nexthop
, 0, sizeof(nexthop
));
552 /* TODO: should use unicast rib lookup */
553 if (!pim_nexthop_lookup(pim
, &nexthop
, mtracep
->rsp_addr
, 1)) {
554 if (PIM_DEBUG_MTRACE
)
556 "Dropped response qid=%ud, no route to response address",
562 return mtrace_send_packet(nexthop
.interface
, mtracep
, mtrace_len
,
563 mtracep
->rsp_addr
, mtracep
->grp_addr
);
566 int igmp_mtrace_recv_qry_req(struct gm_sock
*igmp
, struct ip
*ip_hdr
,
567 struct in_addr from
, const char *from_str
,
568 char *igmp_msg
, int igmp_msg_len
)
570 static uint32_t qry_id
, qry_src
;
571 char mtrace_buf
[MTRACE_HDR_SIZE
+ MTRACE_MAX_HOPS
* MTRACE_RSP_SIZE
];
572 struct interface
*ifp
;
573 struct interface
*out_ifp
= NULL
;
574 struct pim_interface
*pim_ifp
;
575 struct pim_instance
*pim
;
576 struct igmp_mtrace
*mtracep
;
577 struct igmp_mtrace_rsp
*rspp
;
578 struct in_addr nh_addr
;
579 enum mtrace_fwd_code fwd_code
= MTRACE_FWD_CODE_NO_ERROR
;
581 int last_rsp_ind
= 0;
583 uint16_t recv_checksum
;
588 ifp
= igmp
->interface
;
593 * 6. Router Behaviour
594 * Check if mtrace packet is addressed elsewhere and forward,
597 if (!IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
598 if (!if_address_is_local(&ip_hdr
->ip_dst
, AF_INET
,
600 return mtrace_forward_packet(pim
, ip_hdr
);
602 if (igmp_msg_len
< (int)sizeof(struct igmp_mtrace
)) {
603 if (PIM_DEBUG_MTRACE
)
605 "Recv mtrace packet from %s on %s: too short, len=%d, min=%zu",
606 from_str
, ifp
->name
, igmp_msg_len
,
607 sizeof(struct igmp_mtrace
));
611 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
613 recv_checksum
= mtracep
->checksum
;
615 mtracep
->checksum
= 0;
617 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
619 if (recv_checksum
!= checksum
) {
620 if (PIM_DEBUG_MTRACE
)
622 "Recv mtrace packet from %s on %s: checksum mismatch: received=%x computed=%x",
623 from_str
, ifp
->name
, recv_checksum
, checksum
);
627 /* Collecting IGMP Rx stats */
628 igmp
->igmp_stats
.mtrace_req
++;
630 if (PIM_DEBUG_MTRACE
)
631 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
633 /* subtract header from message length */
634 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
636 /* Classify mtrace packet, check if it is a query */
638 if (PIM_DEBUG_MTRACE
)
639 zlog_debug("Received IGMP multicast traceroute query");
641 /* 6.1.1 Packet verification */
642 if (!pim_if_connected_to_source(ifp
, mtracep
->dst_addr
)) {
643 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
644 if (PIM_DEBUG_MTRACE
)
646 "Dropping multicast query on wrong interface");
649 /* Unicast query on wrong interface */
650 fwd_code
= MTRACE_FWD_CODE_WRONG_IF
;
651 if (PIM_DEBUG_MTRACE
)
652 zlog_debug("Multicast query on wrong interface");
654 if (qry_id
== mtracep
->qry_id
&& qry_src
== from
.s_addr
) {
655 if (PIM_DEBUG_MTRACE
)
657 "Dropping multicast query with duplicate source and id");
660 qry_id
= mtracep
->qry_id
;
661 qry_src
= from
.s_addr
;
663 /* if response fields length is equal to a whole number of responses */
664 else if ((r_len
% sizeof(struct igmp_mtrace_rsp
)) == 0) {
665 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
668 last_rsp_ind
= r_len
/ sizeof(struct igmp_mtrace_rsp
);
669 if (last_rsp_ind
> MTRACE_MAX_HOPS
) {
670 if (PIM_DEBUG_MTRACE
)
671 zlog_debug("Mtrace request of excessive size");
675 if (PIM_DEBUG_MTRACE
)
677 "Recv mtrace packet from %s on %s: invalid length %d",
678 from_str
, ifp
->name
, igmp_msg_len
);
682 /* 6.2.1 Packet Verification - drop not link-local multicast */
683 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))
684 && !IPV4_MC_LINKLOCAL(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
685 if (PIM_DEBUG_MTRACE
)
687 "Recv mtrace packet from %s on %s: not link-local multicast %pI4",
688 from_str
, ifp
->name
, &ip_hdr
->ip_dst
);
692 /* 6.2.2. Normal Processing */
694 /* 6.2.2. 1. If there is room in the current buffer? */
696 if (last_rsp_ind
== MTRACE_MAX_HOPS
) {
697 /* ...there was no room... */
698 mtracep
->rsp
[MTRACE_MAX_HOPS
- 1].fwd_code
=
699 MTRACE_FWD_CODE_NO_SPACE
;
700 return mtrace_send_response(pim_ifp
->pim
, mtracep
,
704 /* ...insert new response block... */
706 /* calculate new mtrace lenght with extra response */
707 mtrace_len
= igmp_msg_len
+ sizeof(struct igmp_mtrace_rsp
);
709 /* copy received query/request */
710 memcpy(mtrace_buf
, igmp_msg
, igmp_msg_len
);
712 /* repoint mtracep pointer to copy */
713 mtracep
= (struct igmp_mtrace
*)mtrace_buf
;
715 /* pointer for extra response field to be filled in */
716 rspp
= &mtracep
->rsp
[last_rsp_ind
];
718 /* initialize extra response field */
719 mtrace_rsp_init(rspp
);
721 /* carry over any error noted when receiving the query */
722 rspp
->fwd_code
= fwd_code
;
724 /* ...and fill in Query Arrival Time... */
725 rspp
->arrival
= htonl(query_arrival_time());
726 rspp
->outgoing
= pim_ifp
->primary_address
;
727 rspp
->out_count
= htonl(MTRACE_UNKNOWN_COUNT
);
730 /* 6.2.2. 2. Attempt to determine the forwarding information... */
732 if (mtracep
->grp_addr
.s_addr
!= INADDR_ANY
)
733 fwd_info
= mtrace_fwd_info(pim
, mtracep
, rspp
, &out_ifp
);
735 fwd_info
= mtrace_fwd_info_weak(pim
, mtracep
, rspp
, &out_ifp
);
737 /* 6.2.2 3. If no forwarding information... */
739 if (PIM_DEBUG_MTRACE
)
740 zlog_debug("mtrace not found multicast state");
741 mtrace_rsp_set_fwd_code(rspp
, MTRACE_FWD_CODE_NO_ROUTE
);
742 /* 6.2.2. 3. forward the packet to requester */
743 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
746 nh_addr
= rspp
->prev_hop
;
748 reached_source
= false;
750 if (nh_addr
.s_addr
== INADDR_ANY
) {
751 /* no pim? i.e. 7.5.3. No Previous Hop */
752 if (!out_ifp
->info
) {
753 if (PIM_DEBUG_MTRACE
)
754 zlog_debug("mtrace not found incoming if w/ pim");
755 mtrace_rsp_set_fwd_code(rspp
,
756 MTRACE_FWD_CODE_NO_MULTICAST
);
757 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
759 /* reached source? i.e. 7.5.1 Arriving at source */
760 if (pim_if_connected_to_source(out_ifp
, mtracep
->src_addr
)) {
761 reached_source
= true;
762 rspp
->prev_hop
= mtracep
->src_addr
;
765 * 6.4 Forwarding Traceroute Requests:
766 * Previous-hop router not known,
767 * packet is sent to an appropriate multicast address
769 (void)inet_aton(MCAST_ALL_ROUTERS
, &nh_addr
);
772 /* 6.2.2 8. If this router is the Rendez-vous Point */
773 if (mtracep
->grp_addr
.s_addr
!= INADDR_ANY
&&
774 pim_rp_i_am_rp(pim
, mtracep
->grp_addr
)) {
775 mtrace_rsp_set_fwd_code(rspp
, MTRACE_FWD_CODE_REACHED_RP
);
776 /* 7.7.1. PIM-SM ...RP has not performed source-specific join */
777 if (rspp
->src_mask
== MTRACE_SRC_MASK_GROUP
)
778 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
782 * 6.4 Forwarding Traceroute Requests: the number of response
783 * blocks exceeds number of responses, so forward to the requester.
785 if (mtracep
->hops
<= (last_rsp_ind
+ 1))
786 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
788 /* 7.5.1. Arriving at source: terminate trace */
790 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
792 mtracep
->checksum
= 0;
794 mtracep
->checksum
= in_cksum(mtrace_buf
, mtrace_len
);
796 /* 6.4 Forwarding Traceroute Requests: response blocks less than req. */
797 return mtrace_send_packet(out_ifp
, mtracep
, mtrace_len
, nh_addr
,
801 /* 6.3. Traceroute responses */
802 int igmp_mtrace_recv_response(struct gm_sock
*igmp
, struct ip
*ip_hdr
,
803 struct in_addr from
, const char *from_str
,
804 char *igmp_msg
, int igmp_msg_len
)
806 static uint32_t qry_id
, rsp_dst
;
807 struct interface
*ifp
;
808 struct pim_interface
*pim_ifp
;
809 struct pim_instance
*pim
;
810 struct igmp_mtrace
*mtracep
;
811 uint16_t recv_checksum
;
814 ifp
= igmp
->interface
;
818 if (igmp_msg_len
< (int)sizeof(struct igmp_mtrace
)) {
819 if (PIM_DEBUG_MTRACE
)
821 "Recv mtrace packet from %s on %s: too short, len=%d, min=%zu",
822 from_str
, ifp
->name
, igmp_msg_len
,
823 sizeof(struct igmp_mtrace
));
827 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
829 recv_checksum
= mtracep
->checksum
;
831 mtracep
->checksum
= 0;
833 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
835 if (recv_checksum
!= checksum
) {
836 if (PIM_DEBUG_MTRACE
)
838 "Recv mtrace response from %s on %s: checksum mismatch: received=%x computed=%x",
839 from_str
, ifp
->name
, recv_checksum
, checksum
);
843 mtracep
->checksum
= checksum
;
845 /* Collecting IGMP Rx stats */
846 igmp
->igmp_stats
.mtrace_rsp
++;
848 if (PIM_DEBUG_MTRACE
)
849 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
851 /* Drop duplicate packets */
852 if (qry_id
== mtracep
->qry_id
&& rsp_dst
== ip_hdr
->ip_dst
.s_addr
) {
853 if (PIM_DEBUG_MTRACE
)
854 zlog_debug("duplicate mtrace response packet dropped");
858 qry_id
= mtracep
->qry_id
;
859 rsp_dst
= ip_hdr
->ip_dst
.s_addr
;
861 return mtrace_forward_packet(pim
, ip_hdr
);