1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Multicast traceroute for FRRouting
4 * Copyright (C) 2017 Mladen Sablic
7 /* based on draft-ietf-idmr-traceroute-ipm-07 */
12 #include "pim_instance.h"
17 #include "pim_ifchannel.h"
18 #include "pim_macro.h"
19 #include "pim_igmp_mtrace.h"
21 static struct in_addr
mtrace_primary_address(struct interface
*ifp
)
23 struct connected
*ifc
;
24 struct listnode
*node
;
26 struct pim_interface
*pim_ifp
;
30 return pim_ifp
->primary_address
;
33 any
.s_addr
= INADDR_ANY
;
35 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
36 struct prefix
*p
= ifc
->address
;
38 if (p
->family
!= AF_INET
)
41 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
43 /* in case no primary found, return a secondary */
49 static bool mtrace_fwd_info_weak(struct pim_instance
*pim
,
50 struct igmp_mtrace
*mtracep
,
51 struct igmp_mtrace_rsp
*rspp
,
52 struct interface
**ifpp
)
54 struct pim_nexthop nexthop
;
55 struct interface
*ifp_in
;
56 struct in_addr nh_addr
;
58 nh_addr
.s_addr
= INADDR_ANY
;
60 memset(&nexthop
, 0, sizeof(nexthop
));
62 if (!pim_nexthop_lookup(pim
, &nexthop
, mtracep
->src_addr
, 1)) {
64 zlog_debug("mtrace not found neighbor");
69 zlog_debug("mtrace pim_nexthop_lookup OK");
72 zlog_debug("mtrace next_hop=%pPAs", &nexthop
.mrib_nexthop_addr
);
74 nh_addr
= nexthop
.mrib_nexthop_addr
;
76 ifp_in
= nexthop
.interface
;
78 /* return interface for forwarding mtrace packets */
81 /* 6.2.2. 4. Fill in the Incoming Interface Address... */
82 rspp
->incoming
= mtrace_primary_address(ifp_in
);
83 rspp
->prev_hop
= nh_addr
;
84 rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
85 rspp
->total
= htonl(MTRACE_UNKNOWN_COUNT
);
86 rspp
->rtg_proto
= MTRACE_RTG_PROTO_PIM
;
90 static bool mtrace_fwd_info(struct pim_instance
*pim
,
91 struct igmp_mtrace
*mtracep
,
92 struct igmp_mtrace_rsp
*rspp
,
93 struct interface
**ifpp
)
96 struct pim_upstream
*up
;
97 struct interface
*ifp_in
;
98 struct in_addr nh_addr
;
101 memset(&sg
, 0, sizeof(sg
));
102 sg
.src
= mtracep
->src_addr
;
103 sg
.grp
= mtracep
->grp_addr
;
105 up
= pim_upstream_find(pim
, &sg
);
108 sg
.src
= PIMADDR_ANY
;
109 up
= pim_upstream_find(pim
, &sg
);
115 if (!up
->rpf
.source_nexthop
.interface
) {
117 zlog_debug("%s: up %s RPF is not present", __func__
,
122 ifp_in
= up
->rpf
.source_nexthop
.interface
;
123 nh_addr
= up
->rpf
.source_nexthop
.mrib_nexthop_addr
;
124 total
= htonl(MTRACE_UNKNOWN_COUNT
);
126 if (PIM_DEBUG_MTRACE
)
127 zlog_debug("fwd_info: upstream next hop=%pI4", &nh_addr
);
130 total
= up
->channel_oil
->cc
.pktcnt
;
132 /* return interface for forwarding mtrace packets */
135 /* 6.2.2. 4. Fill in the Incoming Interface Address... */
136 rspp
->incoming
= mtrace_primary_address(ifp_in
);
137 rspp
->prev_hop
= nh_addr
;
138 rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
140 rspp
->rtg_proto
= MTRACE_RTG_PROTO_PIM
;
142 /* 6.2.2. 4. Fill in ... S, and Src Mask */
143 if (!pim_addr_is_any(sg
.src
)) {
145 rspp
->src_mask
= MTRACE_SRC_MASK_SOURCE
;
148 rspp
->src_mask
= MTRACE_SRC_MASK_GROUP
;
154 static void mtrace_rsp_set_fwd_code(struct igmp_mtrace_rsp
*mtrace_rspp
,
155 enum mtrace_fwd_code fwd_code
)
157 if (mtrace_rspp
->fwd_code
== MTRACE_FWD_CODE_NO_ERROR
)
158 mtrace_rspp
->fwd_code
= fwd_code
;
161 static void mtrace_rsp_init(struct igmp_mtrace_rsp
*mtrace_rspp
)
163 mtrace_rspp
->arrival
= 0;
164 mtrace_rspp
->incoming
.s_addr
= INADDR_ANY
;
165 mtrace_rspp
->outgoing
.s_addr
= INADDR_ANY
;
166 mtrace_rspp
->prev_hop
.s_addr
= INADDR_ANY
;
167 mtrace_rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
168 mtrace_rspp
->out_count
= htonl(MTRACE_UNKNOWN_COUNT
);
169 mtrace_rspp
->total
= htonl(MTRACE_UNKNOWN_COUNT
);
170 mtrace_rspp
->rtg_proto
= 0;
171 mtrace_rspp
->fwd_ttl
= 0;
172 mtrace_rspp
->mbz
= 0;
174 mtrace_rspp
->src_mask
= 0;
175 mtrace_rspp
->fwd_code
= MTRACE_FWD_CODE_NO_ERROR
;
178 static void mtrace_rsp_debug(uint32_t qry_id
, int rsp
,
179 struct igmp_mtrace_rsp
*mrspp
)
181 struct in_addr incoming
= mrspp
->incoming
;
182 struct in_addr outgoing
= mrspp
->outgoing
;
183 struct in_addr prev_hop
= mrspp
->prev_hop
;
186 "Rx mt(%d) qid=%ud arr=%x in=%pI4 out=%pI4 prev=%pI4 proto=%d fwd=%d",
187 rsp
, ntohl(qry_id
), mrspp
->arrival
, &incoming
, &outgoing
,
188 &prev_hop
, mrspp
->rtg_proto
, mrspp
->fwd_code
);
191 static void mtrace_debug(struct pim_interface
*pim_ifp
,
192 struct igmp_mtrace
*mtracep
, int mtrace_len
)
194 struct in_addr ga
, sa
, da
, ra
;
196 ga
= mtracep
->grp_addr
;
197 sa
= mtracep
->src_addr
;
198 da
= mtracep
->dst_addr
;
199 ra
= mtracep
->rsp_addr
;
202 "Rx mtrace packet incoming on %pI4: hops=%d type=%d size=%d, grp=%pI4, src=%pI4, dst=%pI4 rsp=%pI4 ttl=%d qid=%ud",
203 &pim_ifp
->primary_address
, mtracep
->hops
, mtracep
->type
,
204 mtrace_len
, &ga
, &sa
, &da
, &ra
, mtracep
->rsp_ttl
,
205 ntohl(mtracep
->qry_id
));
206 if (mtrace_len
> (int)sizeof(struct igmp_mtrace
)) {
210 int responses
= mtrace_len
- sizeof(struct igmp_mtrace
);
212 if ((responses
% sizeof(struct igmp_mtrace_rsp
)) != 0)
213 if (PIM_DEBUG_MTRACE
)
215 "Mtrace response block of wrong length");
217 responses
= responses
/ sizeof(struct igmp_mtrace_rsp
);
219 for (i
= 0; i
< responses
; i
++)
220 mtrace_rsp_debug(mtracep
->qry_id
, i
, &mtracep
->rsp
[i
]);
224 /* 5.1 Query Arrival Time */
225 static uint32_t query_arrival_time(void)
230 if (gettimeofday(&tv
, NULL
) < 0) {
231 if (PIM_DEBUG_MTRACE
)
232 zlog_debug("Query arrival time lookup failed: errno=%d: %s",
233 errno
, safe_strerror(errno
));
236 /* not sure second offset correct, as I get different value */
237 qat
= ((tv
.tv_sec
+ 32384) << 16) + ((tv
.tv_usec
<< 10) / 15625);
242 static int mtrace_send_packet(struct interface
*ifp
,
243 struct igmp_mtrace
*mtracep
,
244 size_t mtrace_buf_len
, struct in_addr dst_addr
,
245 struct in_addr group_addr
)
247 struct sockaddr_in to
;
254 memset(&to
, 0, sizeof(to
));
255 to
.sin_family
= AF_INET
;
256 to
.sin_addr
= dst_addr
;
259 if (PIM_DEBUG_MTRACE
) {
260 struct in_addr if_addr
;
261 struct in_addr rsp_addr
= mtracep
->rsp_addr
;
263 if_addr
= mtrace_primary_address(ifp
);
264 zlog_debug("Sending mtrace packet to %pI4 on %pI4", &rsp_addr
,
268 fd
= pim_socket_raw(IPPROTO_IGMP
);
273 ret
= pim_socket_bind(fd
, ifp
);
280 if (IPV4_CLASS_DE(ntohl(dst_addr
.s_addr
))) {
281 if (IPV4_MC_LINKLOCAL(ntohl(dst_addr
.s_addr
))) {
284 if (mtracep
->type
== PIM_IGMP_MTRACE_RESPONSE
)
285 ttl
= mtracep
->rsp_ttl
;
289 ret
= setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
,
293 if (PIM_DEBUG_MTRACE
)
294 zlog_debug("Failed to set socket multicast TTL");
300 sent
= sendto(fd
, (char *)mtracep
, mtrace_buf_len
, MSG_DONTWAIT
,
301 (struct sockaddr
*)&to
, tolen
);
303 if (sent
!= (ssize_t
)mtrace_buf_len
) {
304 char dst_str
[INET_ADDRSTRLEN
];
305 char group_str
[INET_ADDRSTRLEN
];
307 pim_inet4_dump("<dst?>", dst_addr
, dst_str
, sizeof(dst_str
));
308 pim_inet4_dump("<group?>", group_addr
, group_str
,
311 if (PIM_DEBUG_MTRACE
)
313 "Send mtrace request failed for %s on%s: group=%s msg_size=%zd: errno=%d: %s",
314 dst_str
, ifp
->name
, group_str
,
315 mtrace_buf_len
, errno
,
316 safe_strerror(errno
));
318 if (PIM_DEBUG_MTRACE
)
320 "Send mtrace request failed for %s on %s: group=%s msg_size=%zd: sent=%zd",
321 dst_str
, ifp
->name
, group_str
,
322 mtrace_buf_len
, sent
);
333 static int mtrace_un_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
,
334 struct interface
*interface
)
336 struct pim_nexthop nexthop
;
337 struct sockaddr_in to
;
338 struct interface
*if_out
;
345 checksum
= ip_hdr
->ip_sum
;
349 if (checksum
!= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4))
352 if (ip_hdr
->ip_ttl
-- <= 1)
355 if (interface
== NULL
) {
356 memset(&nexthop
, 0, sizeof(nexthop
));
357 if (!pim_nexthop_lookup(pim
, &nexthop
, ip_hdr
->ip_dst
, 0)) {
358 if (PIM_DEBUG_MTRACE
)
360 "Dropping mtrace packet, no route to destination");
364 if_out
= nexthop
.interface
;
369 ip_hdr
->ip_sum
= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4);
371 fd
= pim_socket_raw(IPPROTO_RAW
);
376 pim_socket_ip_hdr(fd
);
378 ret
= pim_socket_bind(fd
, if_out
);
385 memset(&to
, 0, sizeof(to
));
386 to
.sin_family
= AF_INET
;
387 to
.sin_addr
= ip_hdr
->ip_dst
;
390 sent
= sendto(fd
, ip_hdr
, ntohs(ip_hdr
->ip_len
), 0,
391 (struct sockaddr
*)&to
, tolen
);
396 if (PIM_DEBUG_MTRACE
)
398 "Failed to forward mtrace packet: sendto errno=%d, %s",
399 errno
, safe_strerror(errno
));
403 if (PIM_DEBUG_MTRACE
) {
404 zlog_debug("Fwd mtrace packet len=%u to %pI4 ttl=%u",
405 ntohs(ip_hdr
->ip_len
), &ip_hdr
->ip_dst
,
412 static int mtrace_mc_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
415 struct channel_oil
*c_oil
;
416 struct listnode
*chnode
;
417 struct listnode
*chnextnode
;
418 struct pim_ifchannel
*ch
= NULL
;
421 memset(&sg
, 0, sizeof(sg
));
422 sg
.grp
= ip_hdr
->ip_dst
;
424 c_oil
= pim_find_channel_oil(pim
, &sg
);
427 if (PIM_DEBUG_MTRACE
) {
429 "Dropping mtrace multicast packet len=%u to %pI4 ttl=%u",
430 ntohs(ip_hdr
->ip_len
),
431 &ip_hdr
->ip_dst
, ip_hdr
->ip_ttl
);
435 if (c_oil
->up
== NULL
)
437 if (c_oil
->up
->ifchannels
== NULL
)
439 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
440 if (pim_macro_chisin_oiflist(ch
)) {
443 r
= mtrace_un_forward_packet(pim
, ip_hdr
,
453 static int mtrace_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
455 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
456 return mtrace_mc_forward_packet(pim
, ip_hdr
);
458 return mtrace_un_forward_packet(pim
, ip_hdr
, NULL
);
461 static int mtrace_send_mc_response(struct pim_instance
*pim
,
462 struct igmp_mtrace
*mtracep
,
466 struct channel_oil
*c_oil
;
467 struct listnode
*chnode
;
468 struct listnode
*chnextnode
;
469 struct pim_ifchannel
*ch
= NULL
;
472 memset(&sg
, 0, sizeof(sg
));
473 sg
.grp
= mtracep
->rsp_addr
;
475 c_oil
= pim_find_channel_oil(pim
, &sg
);
478 if (PIM_DEBUG_MTRACE
) {
479 struct in_addr rsp_addr
= mtracep
->rsp_addr
;
482 "Dropping mtrace multicast response packet len=%u to %pI4",
483 (unsigned int)mtrace_len
, &rsp_addr
);
487 if (c_oil
->up
== NULL
)
489 if (c_oil
->up
->ifchannels
== NULL
)
491 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
492 if (pim_macro_chisin_oiflist(ch
)) {
495 r
= mtrace_send_packet(ch
->interface
, mtracep
,
496 mtrace_len
, mtracep
->rsp_addr
,
505 /* 6.5 Sending Traceroute Responses */
506 static int mtrace_send_response(struct pim_instance
*pim
,
507 struct igmp_mtrace
*mtracep
, size_t mtrace_len
)
509 struct pim_nexthop nexthop
;
511 mtracep
->type
= PIM_IGMP_MTRACE_RESPONSE
;
513 mtracep
->checksum
= 0;
514 mtracep
->checksum
= in_cksum((char *)mtracep
, mtrace_len
);
516 if (IPV4_CLASS_DE(ntohl(mtracep
->rsp_addr
.s_addr
))) {
517 struct pim_rpf
*p_rpf
;
519 if (pim_rp_i_am_rp(pim
, mtracep
->rsp_addr
))
520 return mtrace_send_mc_response(pim
, mtracep
,
523 p_rpf
= pim_rp_g(pim
, mtracep
->rsp_addr
);
526 if (PIM_DEBUG_MTRACE
) {
527 struct in_addr rsp_addr
= mtracep
->rsp_addr
;
529 zlog_debug("mtrace no RP for %pI4", &rsp_addr
);
533 nexthop
= p_rpf
->source_nexthop
;
534 if (PIM_DEBUG_MTRACE
)
535 zlog_debug("mtrace response to RP");
537 memset(&nexthop
, 0, sizeof(nexthop
));
538 /* TODO: should use unicast rib lookup */
539 if (!pim_nexthop_lookup(pim
, &nexthop
, mtracep
->rsp_addr
, 1)) {
540 if (PIM_DEBUG_MTRACE
)
542 "Dropped response qid=%ud, no route to response address",
548 return mtrace_send_packet(nexthop
.interface
, mtracep
, mtrace_len
,
549 mtracep
->rsp_addr
, mtracep
->grp_addr
);
552 int igmp_mtrace_recv_qry_req(struct gm_sock
*igmp
, struct ip
*ip_hdr
,
553 struct in_addr from
, const char *from_str
,
554 char *igmp_msg
, int igmp_msg_len
)
556 static uint32_t qry_id
, qry_src
;
557 char mtrace_buf
[MTRACE_HDR_SIZE
+ MTRACE_MAX_HOPS
* MTRACE_RSP_SIZE
];
558 struct interface
*ifp
;
559 struct interface
*out_ifp
= NULL
;
560 struct pim_interface
*pim_ifp
;
561 struct pim_instance
*pim
;
562 struct igmp_mtrace
*mtracep
;
563 struct igmp_mtrace_rsp
*rspp
;
564 struct in_addr nh_addr
;
565 enum mtrace_fwd_code fwd_code
= MTRACE_FWD_CODE_NO_ERROR
;
567 int last_rsp_ind
= 0;
569 uint16_t recv_checksum
;
574 ifp
= igmp
->interface
;
579 * 6. Router Behaviour
580 * Check if mtrace packet is addressed elsewhere and forward,
583 if (!IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
584 if (!if_address_is_local(&ip_hdr
->ip_dst
, AF_INET
,
586 return mtrace_forward_packet(pim
, ip_hdr
);
588 if (igmp_msg_len
< (int)sizeof(struct igmp_mtrace
)) {
589 if (PIM_DEBUG_MTRACE
)
591 "Recv mtrace packet from %s on %s: too short, len=%d, min=%zu",
592 from_str
, ifp
->name
, igmp_msg_len
,
593 sizeof(struct igmp_mtrace
));
597 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
599 recv_checksum
= mtracep
->checksum
;
601 mtracep
->checksum
= 0;
603 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
605 if (recv_checksum
!= checksum
) {
606 if (PIM_DEBUG_MTRACE
)
608 "Recv mtrace packet from %s on %s: checksum mismatch: received=%x computed=%x",
609 from_str
, ifp
->name
, recv_checksum
, checksum
);
613 /* Collecting IGMP Rx stats */
614 igmp
->igmp_stats
.mtrace_req
++;
616 if (PIM_DEBUG_MTRACE
)
617 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
619 /* subtract header from message length */
620 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
622 /* Classify mtrace packet, check if it is a query */
624 if (PIM_DEBUG_MTRACE
)
625 zlog_debug("Received IGMP multicast traceroute query");
627 /* 6.1.1 Packet verification */
628 if (!pim_if_connected_to_source(ifp
, mtracep
->dst_addr
)) {
629 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
630 if (PIM_DEBUG_MTRACE
)
632 "Dropping multicast query on wrong interface");
635 /* Unicast query on wrong interface */
636 fwd_code
= MTRACE_FWD_CODE_WRONG_IF
;
637 if (PIM_DEBUG_MTRACE
)
638 zlog_debug("Multicast query on wrong interface");
640 if (qry_id
== mtracep
->qry_id
&& qry_src
== from
.s_addr
) {
641 if (PIM_DEBUG_MTRACE
)
643 "Dropping multicast query with duplicate source and id");
646 qry_id
= mtracep
->qry_id
;
647 qry_src
= from
.s_addr
;
649 /* if response fields length is equal to a whole number of responses */
650 else if ((r_len
% sizeof(struct igmp_mtrace_rsp
)) == 0) {
651 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
654 last_rsp_ind
= r_len
/ sizeof(struct igmp_mtrace_rsp
);
655 if (last_rsp_ind
> MTRACE_MAX_HOPS
) {
656 if (PIM_DEBUG_MTRACE
)
657 zlog_debug("Mtrace request of excessive size");
661 if (PIM_DEBUG_MTRACE
)
663 "Recv mtrace packet from %s on %s: invalid length %d",
664 from_str
, ifp
->name
, igmp_msg_len
);
668 /* 6.2.1 Packet Verification - drop not link-local multicast */
669 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))
670 && !IPV4_MC_LINKLOCAL(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
671 if (PIM_DEBUG_MTRACE
)
673 "Recv mtrace packet from %s on %s: not link-local multicast %pI4",
674 from_str
, ifp
->name
, &ip_hdr
->ip_dst
);
678 /* 6.2.2. Normal Processing */
680 /* 6.2.2. 1. If there is room in the current buffer? */
682 if (last_rsp_ind
== MTRACE_MAX_HOPS
) {
683 /* ...there was no room... */
684 mtracep
->rsp
[MTRACE_MAX_HOPS
- 1].fwd_code
=
685 MTRACE_FWD_CODE_NO_SPACE
;
686 return mtrace_send_response(pim_ifp
->pim
, mtracep
,
690 /* ...insert new response block... */
692 /* calculate new mtrace lenght with extra response */
693 mtrace_len
= igmp_msg_len
+ sizeof(struct igmp_mtrace_rsp
);
695 /* copy received query/request */
696 memcpy(mtrace_buf
, igmp_msg
, igmp_msg_len
);
698 /* repoint mtracep pointer to copy */
699 mtracep
= (struct igmp_mtrace
*)mtrace_buf
;
701 /* pointer for extra response field to be filled in */
702 rspp
= &mtracep
->rsp
[last_rsp_ind
];
704 /* initialize extra response field */
705 mtrace_rsp_init(rspp
);
707 /* carry over any error noted when receiving the query */
708 rspp
->fwd_code
= fwd_code
;
710 /* ...and fill in Query Arrival Time... */
711 rspp
->arrival
= htonl(query_arrival_time());
712 rspp
->outgoing
= pim_ifp
->primary_address
;
713 rspp
->out_count
= htonl(MTRACE_UNKNOWN_COUNT
);
716 /* 6.2.2. 2. Attempt to determine the forwarding information... */
718 if (mtracep
->grp_addr
.s_addr
!= INADDR_ANY
)
719 fwd_info
= mtrace_fwd_info(pim
, mtracep
, rspp
, &out_ifp
);
721 fwd_info
= mtrace_fwd_info_weak(pim
, mtracep
, rspp
, &out_ifp
);
723 /* 6.2.2 3. If no forwarding information... */
725 if (PIM_DEBUG_MTRACE
)
726 zlog_debug("mtrace not found multicast state");
727 mtrace_rsp_set_fwd_code(rspp
, MTRACE_FWD_CODE_NO_ROUTE
);
728 /* 6.2.2. 3. forward the packet to requester */
729 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
732 nh_addr
= rspp
->prev_hop
;
734 reached_source
= false;
736 if (nh_addr
.s_addr
== INADDR_ANY
) {
737 /* no pim? i.e. 7.5.3. No Previous Hop */
738 if (!out_ifp
->info
) {
739 if (PIM_DEBUG_MTRACE
)
740 zlog_debug("mtrace not found incoming if w/ pim");
741 mtrace_rsp_set_fwd_code(rspp
,
742 MTRACE_FWD_CODE_NO_MULTICAST
);
743 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
745 /* reached source? i.e. 7.5.1 Arriving at source */
746 if (pim_if_connected_to_source(out_ifp
, mtracep
->src_addr
)) {
747 reached_source
= true;
748 rspp
->prev_hop
= mtracep
->src_addr
;
751 * 6.4 Forwarding Traceroute Requests:
752 * Previous-hop router not known,
753 * packet is sent to an appropriate multicast address
755 (void)inet_aton(MCAST_ALL_ROUTERS
, &nh_addr
);
758 /* 6.2.2 8. If this router is the Rendez-vous Point */
759 if (mtracep
->grp_addr
.s_addr
!= INADDR_ANY
&&
760 pim_rp_i_am_rp(pim
, mtracep
->grp_addr
)) {
761 mtrace_rsp_set_fwd_code(rspp
, MTRACE_FWD_CODE_REACHED_RP
);
762 /* 7.7.1. PIM-SM ...RP has not performed source-specific join */
763 if (rspp
->src_mask
== MTRACE_SRC_MASK_GROUP
)
764 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
768 * 6.4 Forwarding Traceroute Requests: the number of response
769 * blocks exceeds number of responses, so forward to the requester.
771 if (mtracep
->hops
<= (last_rsp_ind
+ 1))
772 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
774 /* 7.5.1. Arriving at source: terminate trace */
776 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
778 mtracep
->checksum
= 0;
780 mtracep
->checksum
= in_cksum(mtrace_buf
, mtrace_len
);
782 /* 6.4 Forwarding Traceroute Requests: response blocks less than req. */
783 return mtrace_send_packet(out_ifp
, mtracep
, mtrace_len
, nh_addr
,
787 /* 6.3. Traceroute responses */
788 int igmp_mtrace_recv_response(struct gm_sock
*igmp
, struct ip
*ip_hdr
,
789 struct in_addr from
, const char *from_str
,
790 char *igmp_msg
, int igmp_msg_len
)
792 static uint32_t qry_id
, rsp_dst
;
793 struct interface
*ifp
;
794 struct pim_interface
*pim_ifp
;
795 struct pim_instance
*pim
;
796 struct igmp_mtrace
*mtracep
;
797 uint16_t recv_checksum
;
800 ifp
= igmp
->interface
;
804 if (igmp_msg_len
< (int)sizeof(struct igmp_mtrace
)) {
805 if (PIM_DEBUG_MTRACE
)
807 "Recv mtrace packet from %s on %s: too short, len=%d, min=%zu",
808 from_str
, ifp
->name
, igmp_msg_len
,
809 sizeof(struct igmp_mtrace
));
813 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
815 recv_checksum
= mtracep
->checksum
;
817 mtracep
->checksum
= 0;
819 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
821 if (recv_checksum
!= checksum
) {
822 if (PIM_DEBUG_MTRACE
)
824 "Recv mtrace response from %s on %s: checksum mismatch: received=%x computed=%x",
825 from_str
, ifp
->name
, recv_checksum
, checksum
);
829 mtracep
->checksum
= checksum
;
831 /* Collecting IGMP Rx stats */
832 igmp
->igmp_stats
.mtrace_rsp
++;
834 if (PIM_DEBUG_MTRACE
)
835 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
837 /* Drop duplicate packets */
838 if (qry_id
== mtracep
->qry_id
&& rsp_dst
== ip_hdr
->ip_dst
.s_addr
) {
839 if (PIM_DEBUG_MTRACE
)
840 zlog_debug("duplicate mtrace response packet dropped");
844 qry_id
= mtracep
->qry_id
;
845 rsp_dst
= ip_hdr
->ip_dst
.s_addr
;
847 return mtrace_forward_packet(pim
, ip_hdr
);