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
];
104 struct in_addr ga
, sa
, da
, ra
;
106 ga
= mtracep
->grp_addr
;
107 sa
= mtracep
->src_addr
;
108 da
= mtracep
->dst_addr
;
109 ra
= mtracep
->rsp_addr
;
112 "Rx mtrace packet incoming on %s: "
113 "hops=%d type=%d size=%d, grp=%s, src=%s,"
114 " dst=%s rsp=%s ttl=%d qid=%ud",
115 inet_ntop(AF_INET
, &(pim_ifp
->primary_address
), inc_str
,
117 mtracep
->hops
, mtracep
->type
, mtrace_len
,
118 inet_ntop(AF_INET
, &ga
, grp_str
,
120 inet_ntop(AF_INET
, &sa
, src_str
,
122 inet_ntop(AF_INET
, &da
, dst_str
,
124 inet_ntop(AF_INET
, &ra
, rsp_str
,
126 mtracep
->rsp_ttl
, ntohl(mtracep
->qry_id
));
127 if (mtrace_len
> (int)sizeof(struct igmp_mtrace
)) {
131 int responses
= mtrace_len
- sizeof(struct igmp_mtrace
);
133 if ((responses
% sizeof(struct igmp_mtrace_rsp
)) != 0)
134 if (PIM_DEBUG_MTRACE
)
136 "Mtrace response block of wrong"
139 responses
= responses
/ sizeof(struct igmp_mtrace_rsp
);
141 for (i
= 0; i
< responses
; i
++)
142 mtrace_rsp_debug(mtracep
->qry_id
, i
, &mtracep
->rsp
[i
]);
146 /* 5.1 Query Arrival Time */
147 static uint32_t query_arrival_time(void)
152 char m_qat
[] = "Query arrival time lookup failed: errno=%d: %s";
154 if (gettimeofday(&tv
, NULL
) < 0) {
155 if (PIM_DEBUG_MTRACE
)
156 zlog_warn(m_qat
, errno
, safe_strerror(errno
));
159 /* not sure second offset correct, as I get different value */
160 qat
= ((tv
.tv_sec
+ 32384) << 16) + ((tv
.tv_usec
<< 10) / 15625);
165 static int mtrace_send_packet(struct interface
*ifp
,
166 struct igmp_mtrace
*mtracep
,
167 size_t mtrace_buf_len
, struct in_addr dst_addr
,
168 struct in_addr group_addr
)
170 struct sockaddr_in to
;
175 char if_str
[INET_ADDRSTRLEN
];
176 char rsp_str
[INET_ADDRSTRLEN
];
179 memset(&to
, 0, sizeof(to
));
180 to
.sin_family
= AF_INET
;
181 to
.sin_addr
= dst_addr
;
184 if (PIM_DEBUG_MTRACE
) {
185 struct in_addr if_addr
;
187 if_addr
= mtrace_primary_address(ifp
);
189 "Sending mtrace packet to %s on %s",
190 inet_ntop(AF_INET
, &mtracep
->rsp_addr
, rsp_str
,
192 inet_ntop(AF_INET
, &if_addr
, if_str
, sizeof(if_str
)));
195 fd
= pim_socket_raw(IPPROTO_IGMP
);
200 ret
= pim_socket_bind(fd
, ifp
);
207 if (IPV4_CLASS_DE(ntohl(dst_addr
.s_addr
))) {
208 if (IPV4_MC_LINKLOCAL(ntohl(dst_addr
.s_addr
))) {
211 if (mtracep
->type
== PIM_IGMP_MTRACE_RESPONSE
)
212 ttl
= mtracep
->rsp_ttl
;
216 ret
= setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
,
220 if (PIM_DEBUG_MTRACE
)
221 zlog_warn("Failed to set socket multicast TTL");
227 sent
= sendto(fd
, (char *)mtracep
, mtrace_buf_len
, MSG_DONTWAIT
,
228 (struct sockaddr
*)&to
, tolen
);
230 if (sent
!= (ssize_t
)mtrace_buf_len
) {
231 char dst_str
[INET_ADDRSTRLEN
];
232 char group_str
[INET_ADDRSTRLEN
];
234 pim_inet4_dump("<dst?>", dst_addr
, dst_str
, sizeof(dst_str
));
235 pim_inet4_dump("<group?>", group_addr
, group_str
,
238 if (PIM_DEBUG_MTRACE
)
240 "Send mtrace request failed for %s on"
241 "%s: group=%s msg_size=%zd: errno=%d: "
243 dst_str
, ifp
->name
, group_str
,
244 mtrace_buf_len
, errno
,
245 safe_strerror(errno
));
247 if (PIM_DEBUG_MTRACE
)
249 "Send mtrace request failed for %s on"
250 " %s: group=%s msg_size=%zd: sent=%zd",
251 dst_str
, ifp
->name
, group_str
,
252 mtrace_buf_len
, sent
);
263 static int mtrace_un_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
,
264 struct interface
*interface
)
266 struct pim_nexthop nexthop
;
267 struct sockaddr_in to
;
268 struct interface
*if_out
;
275 checksum
= ip_hdr
->ip_sum
;
279 if (checksum
!= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4))
282 if (ip_hdr
->ip_ttl
-- <= 1)
285 ip_hdr
->ip_sum
= in_cksum(ip_hdr
, ip_hdr
->ip_hl
* 4);
287 fd
= pim_socket_raw(IPPROTO_RAW
);
292 pim_socket_ip_hdr(fd
);
294 if (interface
== NULL
) {
295 memset(&nexthop
, 0, sizeof(nexthop
));
296 ret
= pim_nexthop_lookup(pim
, &nexthop
, ip_hdr
->ip_dst
, 0);
300 if (PIM_DEBUG_MTRACE
)
302 "Dropping mtrace packet, "
303 "no route to destination");
307 if_out
= nexthop
.interface
;
312 ret
= pim_socket_bind(fd
, if_out
);
319 memset(&to
, 0, sizeof(to
));
320 to
.sin_family
= AF_INET
;
321 to
.sin_addr
= ip_hdr
->ip_dst
;
324 sent
= sendto(fd
, ip_hdr
, ntohs(ip_hdr
->ip_len
), 0,
325 (struct sockaddr
*)&to
, tolen
);
330 if (PIM_DEBUG_MTRACE
)
332 "Failed to forward mtrace packet:"
333 " sendto errno=%d, %s",
334 errno
, safe_strerror(errno
));
338 if (PIM_DEBUG_MTRACE
) {
339 zlog_debug("Fwd mtrace packet len=%u to %s ttl=%u",
340 ntohs(ip_hdr
->ip_len
), inet_ntoa(ip_hdr
->ip_dst
),
347 static int mtrace_mc_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
350 struct channel_oil
*c_oil
;
351 struct listnode
*chnode
;
352 struct listnode
*chnextnode
;
353 struct pim_ifchannel
*ch
= NULL
;
356 memset(&sg
, 0, sizeof(struct prefix_sg
));
357 sg
.grp
= ip_hdr
->ip_dst
;
359 c_oil
= pim_find_channel_oil(pim
, &sg
);
362 if (PIM_DEBUG_MTRACE
) {
364 "Dropping mtrace multicast packet "
365 "len=%u to %s ttl=%u",
366 ntohs(ip_hdr
->ip_len
),
367 inet_ntoa(ip_hdr
->ip_dst
), ip_hdr
->ip_ttl
);
371 if (c_oil
->up
== NULL
)
373 if (c_oil
->up
->ifchannels
== NULL
)
375 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
376 if (pim_macro_chisin_oiflist(ch
)) {
379 r
= mtrace_un_forward_packet(pim
, ip_hdr
,
389 static int mtrace_forward_packet(struct pim_instance
*pim
, struct ip
*ip_hdr
)
391 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
392 return mtrace_mc_forward_packet(pim
, ip_hdr
);
394 return mtrace_un_forward_packet(pim
, ip_hdr
, NULL
);
397 /* 6.5 Sending Traceroute Responses */
398 static int mtrace_send_mc_response(struct pim_instance
*pim
,
399 struct igmp_mtrace
*mtracep
,
403 struct channel_oil
*c_oil
;
404 struct listnode
*chnode
;
405 struct listnode
*chnextnode
;
406 struct pim_ifchannel
*ch
= NULL
;
409 memset(&sg
, 0, sizeof(struct prefix_sg
));
410 sg
.grp
= mtracep
->rsp_addr
;
412 c_oil
= pim_find_channel_oil(pim
, &sg
);
415 if (PIM_DEBUG_MTRACE
) {
417 "Dropping mtrace multicast response packet "
419 (unsigned int)mtrace_len
,
420 inet_ntoa(mtracep
->rsp_addr
));
424 if (c_oil
->up
== NULL
)
426 if (c_oil
->up
->ifchannels
== NULL
)
428 for (ALL_LIST_ELEMENTS(c_oil
->up
->ifchannels
, chnode
, chnextnode
, ch
)) {
429 if (pim_macro_chisin_oiflist(ch
)) {
432 r
= mtrace_send_packet(ch
->interface
, mtracep
,
433 mtrace_len
, mtracep
->rsp_addr
,
442 static int mtrace_send_response(struct pim_instance
*pim
,
443 struct igmp_mtrace
*mtracep
, size_t mtrace_len
)
445 struct pim_nexthop nexthop
;
448 mtracep
->type
= PIM_IGMP_MTRACE_RESPONSE
;
450 mtracep
->checksum
= 0;
451 mtracep
->checksum
= in_cksum((char *)mtracep
, mtrace_len
);
453 if (IPV4_CLASS_DE(ntohl(mtracep
->rsp_addr
.s_addr
))) {
454 struct pim_rpf
*p_rpf
;
455 char grp_str
[INET_ADDRSTRLEN
];
457 if (pim_rp_i_am_rp(pim
, mtracep
->rsp_addr
))
458 return mtrace_send_mc_response(pim
, mtracep
,
461 p_rpf
= pim_rp_g(pim
, mtracep
->rsp_addr
);
464 if (PIM_DEBUG_MTRACE
)
465 zlog_warn("mtrace no RP for %s",
467 &(mtracep
->rsp_addr
),
468 grp_str
, sizeof(grp_str
)));
471 nexthop
= p_rpf
->source_nexthop
;
472 if (PIM_DEBUG_MTRACE
)
473 zlog_debug("mtrace response to RP");
475 memset(&nexthop
, 0, sizeof(nexthop
));
476 /* TODO: should use unicast rib lookup */
477 ret
= pim_nexthop_lookup(pim
, &nexthop
, mtracep
->rsp_addr
, 1);
480 if (PIM_DEBUG_MTRACE
)
482 "Dropped response qid=%ud, no route to "
489 return mtrace_send_packet(nexthop
.interface
, mtracep
, mtrace_len
,
490 mtracep
->rsp_addr
, mtracep
->grp_addr
);
493 int igmp_mtrace_recv_qry_req(struct igmp_sock
*igmp
, struct ip
*ip_hdr
,
494 struct in_addr from
, const char *from_str
,
495 char *igmp_msg
, int igmp_msg_len
)
497 static uint32_t qry_id
, qry_src
;
498 char mtrace_buf
[MTRACE_HDR_SIZE
+ MTRACE_MAX_HOPS
* MTRACE_RSP_SIZE
];
499 struct pim_nexthop nexthop
;
500 struct interface
*ifp
;
501 struct interface
*out_ifp
;
502 struct pim_interface
*pim_ifp
;
503 struct pim_instance
*pim
;
504 struct igmp_mtrace
*mtracep
;
505 struct igmp_mtrace_rsp
*rspp
;
506 struct in_addr nh_addr
;
507 enum mtrace_fwd_code fwd_code
= MTRACE_FWD_CODE_NO_ERROR
;
510 int last_rsp_ind
= 0;
512 uint16_t recv_checksum
;
515 ifp
= igmp
->interface
;
520 * 6. Router Behaviour
521 * Check if mtrace packet is addressed elsewhere and forward,
524 if (!IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
)))
525 if (!if_lookup_exact_address(&ip_hdr
->ip_dst
, AF_INET
,
527 return mtrace_forward_packet(pim
, ip_hdr
);
529 if (igmp_msg_len
< (int)sizeof(struct igmp_mtrace
)) {
530 if (PIM_DEBUG_MTRACE
)
532 "Recv mtrace packet from %s on %s: too short,"
534 from_str
, ifp
->name
, igmp_msg_len
,
535 sizeof(struct igmp_mtrace
));
539 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
541 recv_checksum
= mtracep
->checksum
;
543 mtracep
->checksum
= 0;
545 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
547 if (recv_checksum
!= checksum
) {
548 if (PIM_DEBUG_MTRACE
)
550 "Recv mtrace packet from %s on %s: checksum"
551 " mismatch: received=%x computed=%x",
552 from_str
, ifp
->name
, recv_checksum
, checksum
);
556 if (PIM_DEBUG_MTRACE
)
557 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
559 /* subtract header from message length */
560 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
562 /* Classify mtrace packet, check if it is a query */
564 if (PIM_DEBUG_MTRACE
)
565 zlog_debug("Received IGMP multicast traceroute query");
567 /* 6.1.1 Packet verification */
568 if (!pim_if_connected_to_source(ifp
, mtracep
->dst_addr
)) {
569 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
570 if (PIM_DEBUG_MTRACE
)
572 "Dropping multicast query "
573 "on wrong interface");
576 /* Unicast query on wrong interface */
577 fwd_code
= MTRACE_FWD_CODE_WRONG_IF
;
579 if (qry_id
== mtracep
->qry_id
&& qry_src
== from
.s_addr
) {
580 if (PIM_DEBUG_MTRACE
)
582 "Dropping multicast query with "
583 "duplicate source and id");
586 qry_id
= mtracep
->qry_id
;
587 qry_src
= from
.s_addr
;
589 /* if response fields length is equal to a whole number of responses */
590 else if ((r_len
% sizeof(struct igmp_mtrace_rsp
)) == 0) {
591 r_len
= igmp_msg_len
- sizeof(struct igmp_mtrace
);
594 last_rsp_ind
= r_len
/ sizeof(struct igmp_mtrace_rsp
);
595 if (last_rsp_ind
> MTRACE_MAX_HOPS
) {
596 if (PIM_DEBUG_MTRACE
)
597 zlog_warn("Mtrace request of excessive size");
601 if (PIM_DEBUG_MTRACE
)
603 "Recv mtrace packet from %s on %s: "
605 from_str
, ifp
->name
, igmp_msg_len
);
609 /* 6.2.1 Packet Verification - drop not link-local multicast */
610 if (IPV4_CLASS_DE(ntohl(ip_hdr
->ip_dst
.s_addr
))
611 && !IPV4_MC_LINKLOCAL(ntohl(ip_hdr
->ip_dst
.s_addr
))) {
612 if (PIM_DEBUG_MTRACE
)
614 "Recv mtrace packet from %s on %s:"
615 " not link-local multicast %s",
616 from_str
, ifp
->name
, inet_ntoa(ip_hdr
->ip_dst
));
620 /* 6.2.2. Normal Processing */
624 if (last_rsp_ind
== MTRACE_MAX_HOPS
) {
625 mtracep
->rsp
[MTRACE_MAX_HOPS
- 1].fwd_code
=
626 MTRACE_FWD_CODE_NO_SPACE
;
627 return mtrace_send_response(pim_ifp
->pim
, mtracep
,
631 /* calculate new mtrace mtrace lenght with extra response */
632 mtrace_len
= igmp_msg_len
+ sizeof(struct igmp_mtrace_rsp
);
634 /* copy received query/request */
635 memcpy(mtrace_buf
, igmp_msg
, igmp_msg_len
);
637 /* repoint mtracep pointer to copy */
638 mtracep
= (struct igmp_mtrace
*)mtrace_buf
;
640 /* pointer for extra response field to be filled in */
641 rspp
= &mtracep
->rsp
[last_rsp_ind
];
643 /* initialize extra response field */
644 mtrace_rsp_init(rspp
);
646 rspp
->arrival
= htonl(query_arrival_time());
647 rspp
->outgoing
= pim_ifp
->primary_address
;
648 rspp
->out_count
= htonl(MTRACE_UNKNOWN_COUNT
);
650 /* 6.2.2. 2. Attempt to determine forwarding information */
654 memset(&nexthop
, 0, sizeof(nexthop
));
655 ret
= pim_nexthop_lookup(pim
, &nexthop
, mtracep
->src_addr
, 1);
658 char nexthop_str
[INET_ADDRSTRLEN
];
660 if (PIM_DEBUG_MTRACE
)
661 zlog_debug("mtrace pim_nexthop_lookup OK");
663 if (PIM_DEBUG_MTRACE
)
664 zlog_warn("mtrace next_hop=%s",
665 inet_ntop(nexthop
.mrib_nexthop_addr
.family
,
666 &nexthop
.mrib_nexthop_addr
.u
.prefix
,
667 nexthop_str
, sizeof(nexthop_str
)));
669 if (nexthop
.mrib_nexthop_addr
.family
== AF_INET
)
670 nh_addr
= nexthop
.mrib_nexthop_addr
.u
.prefix4
;
672 /* 6.4 Forwarding Traceroute Requests: ... Otherwise, ... */
674 if (PIM_DEBUG_MTRACE
)
675 zlog_debug("mtrace not found neighbor");
677 rspp
->fwd_code
= MTRACE_FWD_CODE_NO_ROUTE
;
679 rspp
->fwd_code
= fwd_code
;
680 /* 6.5 Sending Traceroute Responses */
681 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
684 out_ifp
= nexthop
.interface
;
686 rspp
->incoming
= mtrace_primary_address(out_ifp
);
687 rspp
->prev_hop
= nh_addr
;
688 rspp
->in_count
= htonl(MTRACE_UNKNOWN_COUNT
);
689 rspp
->total
= htonl(MTRACE_UNKNOWN_COUNT
);
690 rspp
->rtg_proto
= MTRACE_RTG_PROTO_PIM
;
695 if (nh_addr
.s_addr
== 0) {
697 if (!out_ifp
->info
) {
698 rspp
->fwd_code
= MTRACE_FWD_CODE_NO_MULTICAST
;
699 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
701 /* reached source? */
702 if (pim_if_connected_to_source(out_ifp
, mtracep
->src_addr
)) {
703 rspp
->prev_hop
= mtracep
->src_addr
;
704 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
707 * 6.4 Forwarding Traceroute Requests:
708 * Previous-hop router not known
710 inet_aton(MCAST_ALL_ROUTERS
, &nh_addr
);
713 if (mtracep
->hops
<= (last_rsp_ind
+ 1))
714 return mtrace_send_response(pim
, mtracep
, mtrace_len
);
716 mtracep
->checksum
= 0;
718 mtracep
->checksum
= in_cksum(mtrace_buf
, mtrace_len
);
720 return mtrace_send_packet(out_ifp
, mtracep
, mtrace_len
, nh_addr
,
724 int igmp_mtrace_recv_response(struct igmp_sock
*igmp
, struct ip
*ip_hdr
,
725 struct in_addr from
, const char *from_str
,
726 char *igmp_msg
, int igmp_msg_len
)
728 static uint32_t qry_id
, rsp_dst
;
729 struct interface
*ifp
;
730 struct pim_interface
*pim_ifp
;
731 struct pim_instance
*pim
;
732 struct igmp_mtrace
*mtracep
;
733 uint16_t recv_checksum
;
736 ifp
= igmp
->interface
;
740 mtracep
= (struct igmp_mtrace
*)igmp_msg
;
742 recv_checksum
= mtracep
->checksum
;
744 mtracep
->checksum
= 0;
746 checksum
= in_cksum(igmp_msg
, igmp_msg_len
);
748 if (recv_checksum
!= checksum
) {
749 if (PIM_DEBUG_MTRACE
)
751 "Recv mtrace response from %s on %s: checksum"
752 " mismatch: received=%x computed=%x",
753 from_str
, ifp
->name
, recv_checksum
, checksum
);
757 mtracep
->checksum
= checksum
;
759 if (PIM_DEBUG_MTRACE
)
760 mtrace_debug(pim_ifp
, mtracep
, igmp_msg_len
);
762 /* Drop duplicate packets */
763 if (qry_id
== mtracep
->qry_id
&& rsp_dst
== ip_hdr
->ip_dst
.s_addr
) {
764 if (PIM_DEBUG_MTRACE
)
765 zlog_debug("duplicate mtrace response packet dropped");
769 qry_id
= mtracep
->qry_id
;
770 rsp_dst
= ip_hdr
->ip_dst
.s_addr
;
772 return mtrace_forward_packet(pim
, ip_hdr
);