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
27 #include "pim_ifchannel.h"
28 #include "pim_macro.h"
29 #include "pim_igmp_mtrace.h"
31 static struct in_addr
mtrace_primary_address(struct interface
*ifp
)
33 struct connected
*ifc
;
34 struct listnode
*node
;
36 struct pim_interface
*pim_ifp
;
40 return pim_ifp
->primary_address
;
43 any
.s_addr
= INADDR_ANY
;
45 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
46 struct prefix
*p
= ifc
->address
;
48 if (p
->family
!= AF_INET
)
51 if (!CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
53 /* in case no primary found, return a secondary */
59 static void mtrace_rsp_init(struct igmp_mtrace_rsp
*mtrace_rspp
)
61 mtrace_rspp
->arrival
= 0;
62 mtrace_rspp
->incoming
.s_addr
= 0;
63 mtrace_rspp
->outgoing
.s_addr
= 0;
64 mtrace_rspp
->prev_hop
.s_addr
= 0;
65 mtrace_rspp
->in_count
= MTRACE_UNKNOWN_COUNT
;
66 mtrace_rspp
->out_count
= MTRACE_UNKNOWN_COUNT
;
67 mtrace_rspp
->total
= MTRACE_UNKNOWN_COUNT
;
68 mtrace_rspp
->rtg_proto
= 0;
69 mtrace_rspp
->fwd_ttl
= 0;
72 mtrace_rspp
->src_mask
= 0;
73 mtrace_rspp
->fwd_code
= MTRACE_FWD_CODE_NO_ERROR
;
76 static void mtrace_rsp_debug(uint32_t qry_id
, int rsp
,
77 struct igmp_mtrace_rsp
*mrspp
)
79 char inc_str
[INET_ADDRSTRLEN
];
80 char out_str
[INET_ADDRSTRLEN
];
81 char prv_str
[INET_ADDRSTRLEN
];
84 "Rx mt(%d) qid=%ud arr=%x in=%s out=%s prev=%s proto=%d fwd=%d",
85 rsp
, ntohl(qry_id
), mrspp
->arrival
,
86 inet_ntop(AF_INET
, &(mrspp
->incoming
), inc_str
,
88 inet_ntop(AF_INET
, &(mrspp
->outgoing
), out_str
,
90 inet_ntop(AF_INET
, &(mrspp
->prev_hop
), prv_str
,
92 mrspp
->rtg_proto
, mrspp
->fwd_code
);
95 static void mtrace_debug(struct pim_interface
*pim_ifp
,
96 struct igmp_mtrace
*mtracep
, int mtrace_len
)
98 char inc_str
[INET_ADDRSTRLEN
];
99 char grp_str
[INET_ADDRSTRLEN
];
100 char src_str
[INET_ADDRSTRLEN
];
101 char dst_str
[INET_ADDRSTRLEN
];
102 char rsp_str
[INET_ADDRSTRLEN
];
105 "Rx mtrace packet incoming on %s: "
106 "hops=%d type=%d size=%d, grp=%s, src=%s,"
107 " dst=%s rsp=%s ttl=%d qid=%ud",
108 inet_ntop(AF_INET
, &(pim_ifp
->primary_address
), inc_str
,
110 mtracep
->hops
, mtracep
->type
, mtrace_len
,
111 inet_ntop(AF_INET
, &(mtracep
->grp_addr
), grp_str
,
113 inet_ntop(AF_INET
, &(mtracep
->src_addr
), src_str
,
115 inet_ntop(AF_INET
, &(mtracep
->dst_addr
), dst_str
,
117 inet_ntop(AF_INET
, &(mtracep
->rsp_addr
), rsp_str
,
119 mtracep
->rsp_ttl
, ntohl(mtracep
->qry_id
));
120 if (mtrace_len
> (int)sizeof(struct igmp_mtrace
)) {
124 int responses
= mtrace_len
- sizeof(struct igmp_mtrace
);
126 if ((responses
% sizeof(struct igmp_mtrace_rsp
)) != 0)
127 if (PIM_DEBUG_MTRACE
)
129 "Mtrace response block of wrong"
132 responses
= responses
/ sizeof(struct igmp_mtrace_rsp
);
134 for (i
= 0; i
< responses
; i
++)
135 mtrace_rsp_debug(mtracep
->qry_id
, i
, &mtracep
->rsp
[i
]);
139 /* 5.1 Query Arrival Time */
140 static uint32_t query_arrival_time(void)
145 char m_qat
[] = "Query arrival time lookup failed: errno=%d: %s";
147 if (gettimeofday(&tv
, NULL
) < 0) {
148 if (PIM_DEBUG_MTRACE
)
149 zlog_warn(m_qat
, errno
, safe_strerror(errno
));
152 /* not sure second offset correct, as I get different value */
153 qat
= ((tv
.tv_sec
+ 32384) << 16) + ((tv
.tv_usec
<< 10) / 15625);
158 static int mtrace_send_packet(struct interface
*ifp
,
159 struct igmp_mtrace
*mtracep
,
160 size_t mtrace_buf_len
, struct in_addr dst_addr
,
161 struct in_addr group_addr
)
163 struct sockaddr_in to
;
168 char if_str
[INET_ADDRSTRLEN
];
169 char rsp_str
[INET_ADDRSTRLEN
];
172 memset(&to
, 0, sizeof(to
));
173 to
.sin_family
= AF_INET
;
174 to
.sin_addr
= dst_addr
;
177 if (PIM_DEBUG_MTRACE
) {
178 struct in_addr if_addr
;
180 if_addr
= mtrace_primary_address(ifp
);
182 "Sending mtrace packet to %s on %s",
183 inet_ntop(AF_INET
, &mtracep
->rsp_addr
, rsp_str
,
185 inet_ntop(AF_INET
, &if_addr
, if_str
, sizeof(if_str
)));
188 fd
= pim_socket_raw(IPPROTO_IGMP
);
193 ret
= pim_socket_bind(fd
, ifp
);
200 if (IPV4_CLASS_DE(ntohl(dst_addr
.s_addr
))) {
201 if (IPV4_MC_LINKLOCAL(ntohl(dst_addr
.s_addr
))) {
204 if (mtracep
->type
== PIM_IGMP_MTRACE_RESPONSE
)
205 ttl
= mtracep
->rsp_ttl
;
209 ret
= setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
,
213 if (PIM_DEBUG_MTRACE
)
214 zlog_warn("Failed to set socket multicast TTL");
220 sent
= sendto(fd
, (char *)mtracep
, mtrace_buf_len
, MSG_DONTWAIT
,
221 (struct sockaddr
*)&to
, tolen
);
223 if (sent
!= (ssize_t
)mtrace_buf_len
) {
224 char dst_str
[INET_ADDRSTRLEN
];
225 char group_str
[INET_ADDRSTRLEN
];
227 pim_inet4_dump("<dst?>", dst_addr
, dst_str
, sizeof(dst_str
));
228 pim_inet4_dump("<group?>", group_addr
, group_str
,
231 if (PIM_DEBUG_MTRACE
)
233 "Send mtrace request failed for %s on"
234 "%s: group=%s msg_size=%zd: errno=%d: "
236 dst_str
, ifp
->name
, group_str
,
237 mtrace_buf_len
, errno
,
238 safe_strerror(errno
));
240 if (PIM_DEBUG_MTRACE
)
242 "Send mtrace request failed for %s on"
243 " %s: group=%s msg_size=%zd: sent=%zd",
244 dst_str
, ifp
->name
, group_str
,
245 mtrace_buf_len
, sent
);
256 static int mtrace_un_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
,
257 struct interface
*interface
)
259 struct pim_nexthop nexthop
;
260 struct sockaddr_in to
;
261 struct interface
*if_out
;
268 checksum
= ip_hdr
->ip_sum
;
272 if (checksum
!= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4))
275 if (ip_hdr
->ip_ttl
-- <= 1)
278 ip_hdr
->ip_sum
= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4);
280 fd
= pim_socket_raw(IPPROTO_RAW
);
285 pim_socket_ip_hdr(fd
);
287 if (interface
== NULL
) {
288 memset(&nexthop
, 0, sizeof(nexthop
));
289 ret
= pim_nexthop_lookup(pim
, &nexthop
, ip_hdr
->ip_dst
, 0);
293 if (PIM_DEBUG_MTRACE
)
295 "Dropping mtrace packet, "
296 "no route to destination");
300 if_out
= nexthop
.interface
;
305 ret
= pim_socket_bind(fd
, if_out
);
312 memset(&to
, 0, sizeof(to
));
313 to
.sin_family
= AF_INET
;
314 to
.sin_addr
= ip_hdr
->ip_dst
;
317 sent
= sendto(fd
, ip_hdr
, ntohs(ip_hdr
->ip_len
), 0,
318 (struct sockaddr
*)&to
, tolen
);
323 if (PIM_DEBUG_MTRACE
)
325 "Failed to forward mtrace packet:"
326 " sendto errno=%d, %s",
327 errno
, safe_strerror(errno
));
331 if (PIM_DEBUG_MTRACE
) {
332 zlog_debug("Fwd mtrace packet len=%u to %s ttl=%u",
333 ntohs(ip_hdr
->ip_len
), inet_ntoa(ip_hdr
->ip_dst
),
340 static int mtrace_mc_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
343 struct channel_oil
*c_oil
;
344 struct listnode
*chnode
;
345 struct listnode
*chnextnode
;
346 struct pim_ifchannel
*ch
= NULL
;
349 memset(&sg
, 0, sizeof(struct prefix_sg
));
350 sg
.grp
= ip_hdr
->ip_dst
;
352 c_oil
= pim_find_channel_oil(pim
, &sg
);
355 if (PIM_DEBUG_MTRACE
) {
357 "Dropping mtrace multicast packet "
358 "len=%u to %s ttl=%u",
359 ntohs(ip_hdr
->ip_len
),
360 inet_ntoa(ip_hdr
->ip_dst
), ip_hdr
->ip_ttl
);
364 if (c_oil
->up
== NULL
)
366 if (c_oil
->up
->ifchannels
== NULL
)
368 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
369 if (pim_macro_chisin_oiflist(ch
)) {
372 r
= mtrace_un_forward_packet(pim
, ip_hdr
,
382 static int mtrace_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
384 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
385 return mtrace_mc_forward_packet(pim
, ip_hdr
);
387 return mtrace_un_forward_packet(pim
, ip_hdr
, NULL
);
390 /* 6.5 Sending Traceroute Responses */
391 static int mtrace_send_mc_response(struct pim_instance
*pim
,
392 struct igmp_mtrace
*mtracep
,
396 struct channel_oil
*c_oil
;
397 struct listnode
*chnode
;
398 struct listnode
*chnextnode
;
399 struct pim_ifchannel
*ch
= NULL
;
402 memset(&sg
, 0, sizeof(struct prefix_sg
));
403 sg
.grp
= mtracep
->rsp_addr
;
405 c_oil
= pim_find_channel_oil(pim
, &sg
);
408 if (PIM_DEBUG_MTRACE
) {
410 "Dropping mtrace multicast response packet "
412 (unsigned int)mtrace_len
,
413 inet_ntoa(mtracep
->rsp_addr
));
417 if (c_oil
->up
== NULL
)
419 if (c_oil
->up
->ifchannels
== NULL
)
421 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
422 if (pim_macro_chisin_oiflist(ch
)) {
425 r
= mtrace_send_packet(ch
->interface
, mtracep
,
426 mtrace_len
, mtracep
->rsp_addr
,
435 static int mtrace_send_response(struct pim_instance
*pim
,
436 struct igmp_mtrace
*mtracep
, size_t mtrace_len
)
438 struct pim_nexthop nexthop
;
441 mtracep
->type
= PIM_IGMP_MTRACE_RESPONSE
;
443 mtracep
->checksum
= 0;
444 mtracep
->checksum
= in_cksum((char *)mtracep
, mtrace_len
);
446 if (IPV4_CLASS_DE(ntohl(mtracep
->rsp_addr
.s_addr
))) {
447 struct pim_rpf
*p_rpf
;
448 char grp_str
[INET_ADDRSTRLEN
];
450 if (pim_rp_i_am_rp(pim
, mtracep
->rsp_addr
))
451 return mtrace_send_mc_response(pim
, mtracep
,
454 p_rpf
= pim_rp_g(pim
, mtracep
->rsp_addr
);
457 if (PIM_DEBUG_MTRACE
)
458 zlog_warn("mtrace no RP for %s",
460 &(mtracep
->rsp_addr
),
461 grp_str
, sizeof(grp_str
)));
464 nexthop
= p_rpf
->source_nexthop
;
465 if (PIM_DEBUG_MTRACE
)
466 zlog_debug("mtrace response to RP");
468 memset(&nexthop
, 0, sizeof(nexthop
));
469 /* TODO: should use unicast rib lookup */
470 ret
= pim_nexthop_lookup(pim
, &nexthop
, mtracep
->rsp_addr
, 1);
473 if (PIM_DEBUG_MTRACE
)
475 "Dropped response qid=%ud, no route to "
482 return mtrace_send_packet(nexthop
.interface
, mtracep
, mtrace_len
,
483 mtracep
->rsp_addr
, mtracep
->grp_addr
);
486 int igmp_mtrace_recv_qry_req(struct igmp_sock
*igmp
, struct ip
*ip_hdr
,
487 struct in_addr from
, const char *from_str
,
488 char *igmp_msg
, int igmp_msg_len
)
490 static uint32_t qry_id
, qry_src
;
491 char mtrace_buf
[MTRACE_HDR_SIZE
+ MTRACE_MAX_HOPS
* MTRACE_RSP_SIZE
];
492 struct pim_nexthop nexthop
;
493 struct interface
*ifp
;
494 struct interface
*out_ifp
;
495 struct pim_interface
*pim_ifp
;
496 struct pim_instance
*pim
;
497 struct igmp_mtrace
*mtracep
;
498 struct igmp_mtrace_rsp
*rspp
;
499 struct in_addr nh_addr
;
500 enum mtrace_fwd_code fwd_code
= MTRACE_FWD_CODE_NO_ERROR
;
503 int last_rsp_ind
= 0;
505 uint16_t recv_checksum
;
508 ifp
= igmp
->interface
;
513 * 6. Router Behaviour
514 * Check if mtrace packet is addressed elsewhere and forward,
517 if (!IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
518 if (!if_lookup_exact_address(&ip_hdr
->ip_dst
, AF_INET
,
520 return mtrace_forward_packet(pim
, ip_hdr
);
522 if (igmp_msg_len
< (int)sizeof(struct igmp_mtrace
)) {
523 if (PIM_DEBUG_MTRACE
)
525 "Recv mtrace packet from %s on %s: too short,"
527 from_str
, ifp
->name
, igmp_msg_len
,
528 sizeof(struct igmp_mtrace
));
532 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
534 recv_checksum
= mtracep
->checksum
;
536 mtracep
->checksum
= 0;
538 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
540 if (recv_checksum
!= checksum
) {
541 if (PIM_DEBUG_MTRACE
)
543 "Recv mtrace packet from %s on %s: checksum"
544 " mismatch: received=%x computed=%x",
545 from_str
, ifp
->name
, recv_checksum
, checksum
);
549 if (PIM_DEBUG_MTRACE
)
550 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
552 /* subtract header from message length */
553 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
555 /* Classify mtrace packet, check if it is a query */
557 if (PIM_DEBUG_MTRACE
)
558 zlog_debug("Received IGMP multicast traceroute query");
560 /* 6.1.1 Packet verification */
561 if (!pim_if_connected_to_source(ifp
, mtracep
->dst_addr
)) {
562 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
563 if (PIM_DEBUG_MTRACE
)
565 "Dropping multicast query "
566 "on wrong interface");
569 /* Unicast query on wrong interface */
570 fwd_code
= MTRACE_FWD_CODE_WRONG_IF
;
572 if (qry_id
== mtracep
->qry_id
&& qry_src
== from
.s_addr
) {
573 if (PIM_DEBUG_MTRACE
)
575 "Dropping multicast query with "
576 "duplicate source and id");
579 qry_id
= mtracep
->qry_id
;
580 qry_src
= from
.s_addr
;
582 /* if response fields length is equal to a whole number of responses */
583 else if ((r_len
% sizeof(struct igmp_mtrace_rsp
)) == 0) {
584 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
587 last_rsp_ind
= r_len
/ sizeof(struct igmp_mtrace_rsp
);
588 if (last_rsp_ind
> MTRACE_MAX_HOPS
) {
589 if (PIM_DEBUG_MTRACE
)
590 zlog_warn("Mtrace request of excessive size");
594 if (PIM_DEBUG_MTRACE
)
596 "Recv mtrace packet from %s on %s: "
598 from_str
, ifp
->name
, igmp_msg_len
);
602 /* 6.2.1 Packet Verification - drop not link-local multicast */
603 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))
604 && !IPV4_MC_LINKLOCAL(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
605 if (PIM_DEBUG_MTRACE
)
607 "Recv mtrace packet from %s on %s:"
608 " not link-local multicast %s",
609 from_str
, ifp
->name
, inet_ntoa(ip_hdr
->ip_dst
));
613 /* 6.2.2. Normal Processing */
617 if (last_rsp_ind
== MTRACE_MAX_HOPS
) {
618 mtracep
->rsp
[MTRACE_MAX_HOPS
- 1].fwd_code
=
619 MTRACE_FWD_CODE_NO_SPACE
;
620 return mtrace_send_response(pim_ifp
->pim
, mtracep
,
624 /* calculate new mtrace mtrace lenght with extra response */
625 mtrace_len
= igmp_msg_len
+ sizeof(struct igmp_mtrace_rsp
);
627 /* copy received query/request */
628 memcpy(mtrace_buf
, igmp_msg
, igmp_msg_len
);
630 /* repoint mtracep pointer to copy */
631 mtracep
= (struct igmp_mtrace
*)mtrace_buf
;
633 /* pointer for extra response field to be filled in */
634 rspp
= &mtracep
->rsp
[last_rsp_ind
];
636 /* initialize extra response field */
637 mtrace_rsp_init(rspp
);
639 rspp
->arrival
= htonl(query_arrival_time());
640 rspp
->outgoing
= pim_ifp
->primary_address
;
641 rspp
->out_count
= htonl(MTRACE_UNKNOWN_COUNT
);
643 /* 6.2.2. 2. Attempt to determine forwarding information */
647 memset(&nexthop
, 0, sizeof(nexthop
));
648 ret
= pim_nexthop_lookup(pim
, &nexthop
, mtracep
->src_addr
, 1);
651 char nexthop_str
[INET_ADDRSTRLEN
];
653 if (PIM_DEBUG_MTRACE
)
654 zlog_debug("mtrace pim_nexthop_lookup OK");
656 if (PIM_DEBUG_MTRACE
)
657 zlog_warn("mtrace next_hop=%s",
658 inet_ntop(nexthop
.mrib_nexthop_addr
.family
,
659 &nexthop
.mrib_nexthop_addr
.u
.prefix
,
660 nexthop_str
, sizeof(nexthop_str
)));
662 if (nexthop
.mrib_nexthop_addr
.family
== AF_INET
)
663 nh_addr
= nexthop
.mrib_nexthop_addr
.u
.prefix4
;
665 /* 6.4 Forwarding Traceroute Requests: ... Otherwise, ... */
667 if (PIM_DEBUG_MTRACE
)
668 zlog_debug("mtrace not found neighbor");
670 rspp
->fwd_code
= MTRACE_FWD_CODE_NO_ROUTE
;
672 rspp
->fwd_code
= fwd_code
;
673 /* 6.5 Sending Traceroute Responses */
674 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
677 out_ifp
= nexthop
.interface
;
679 rspp
->incoming
= mtrace_primary_address(out_ifp
);
680 rspp
->prev_hop
= nh_addr
;
681 rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
682 rspp
->total
= htonl(MTRACE_UNKNOWN_COUNT
);
683 rspp
->rtg_proto
= MTRACE_RTG_PROTO_PIM
;
688 if (nh_addr
.s_addr
== 0) {
690 if (!out_ifp
->info
) {
691 rspp
->fwd_code
= MTRACE_FWD_CODE_NO_MULTICAST
;
692 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
694 /* reached source? */
695 if (pim_if_connected_to_source(out_ifp
, mtracep
->src_addr
)) {
696 rspp
->prev_hop
= mtracep
->src_addr
;
697 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
700 * 6.4 Forwarding Traceroute Requests:
701 * Previous-hop router not known
703 inet_aton(MCAST_ALL_ROUTERS
, &nh_addr
);
706 if (mtracep
->hops
<= (last_rsp_ind
+ 1))
707 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
709 mtracep
->checksum
= 0;
711 mtracep
->checksum
= in_cksum(mtrace_buf
, mtrace_len
);
713 return mtrace_send_packet(out_ifp
, mtracep
, mtrace_len
, nh_addr
,
717 int igmp_mtrace_recv_response(struct igmp_sock
*igmp
, struct ip
*ip_hdr
,
718 struct in_addr from
, const char *from_str
,
719 char *igmp_msg
, int igmp_msg_len
)
721 static uint32_t qry_id
, rsp_dst
;
722 struct interface
*ifp
;
723 struct pim_interface
*pim_ifp
;
724 struct pim_instance
*pim
;
725 struct igmp_mtrace
*mtracep
;
726 uint16_t recv_checksum
;
729 ifp
= igmp
->interface
;
733 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
735 recv_checksum
= mtracep
->checksum
;
737 mtracep
->checksum
= 0;
739 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
741 if (recv_checksum
!= checksum
) {
742 if (PIM_DEBUG_MTRACE
)
744 "Recv mtrace response from %s on %s: checksum"
745 " mismatch: received=%x computed=%x",
746 from_str
, ifp
->name
, recv_checksum
, checksum
);
750 mtracep
->checksum
= checksum
;
752 if (PIM_DEBUG_MTRACE
)
753 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
755 /* Drop duplicate packets */
756 if (qry_id
== mtracep
->qry_id
&& rsp_dst
== ip_hdr
->ip_dst
.s_addr
) {
757 if (PIM_DEBUG_MTRACE
)
758 zlog_debug("duplicate mtrace response packet dropped");
762 qry_id
= mtracep
->qry_id
;
763 rsp_dst
= ip_hdr
->ip_dst
.s_addr
;
765 return mtrace_forward_packet(pim
, ip_hdr
);