1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2008 Everton da Silva Marques
15 #include "lib_errors.h"
16 #include "lib/network.h"
20 #include "pim_mroute.h"
24 #include "pim_iface.h"
25 #include "pim_macro.h"
28 #include "pim_register.h"
29 #include "pim_ifchannel.h"
30 #include "pim_zlookup.h"
33 #include "pim_vxlan.h"
36 static void mroute_read_on(struct pim_instance
*pim
);
37 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
40 int pim_mroute_set(struct pim_instance
*pim
, int enable
)
44 socklen_t data_len
= sizeof(data
);
47 * We need to create the VRF table for the pim mroute_socket
49 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
) {
50 frr_with_privs (&pimd_privs
) {
52 data
= pim
->vrf
->data
.l
.table_id
;
53 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
,
54 MRT_TABLE
, &data
, data_len
);
57 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s",
58 __FILE__
, __func__
, pim
->mroute_socket
,
59 data
, errno
, safe_strerror(errno
));
65 frr_with_privs (&pimd_privs
) {
66 opt
= enable
? MRT_INIT
: MRT_DONE
;
68 * *BSD *cares* about what value we pass down
72 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, opt
, &data
,
76 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
77 __FILE__
, __func__
, pim
->mroute_socket
,
78 enable
? "MRT_INIT" : "MRT_DONE", data
, errno
,
79 safe_strerror(errno
));
84 #if defined(HAVE_IP_PKTINFO)
86 /* Linux and Solaris IP_PKTINFO */
88 if (setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, IP_PKTINFO
,
91 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
92 pim
->mroute_socket
, errno
,
93 safe_strerror(errno
));
100 /* Linux and Solaris IPV6_PKTINFO */
102 if (setsockopt(pim
->mroute_socket
, PIM_IPPROTO
,
103 IPV6_RECVPKTINFO
, &data
, data_len
)) {
105 "Could not set IPV6_RECVPKTINFO on socket fd=%d: errno=%d: %s",
106 pim
->mroute_socket
, errno
,
107 safe_strerror(errno
));
111 setsockopt_so_recvbuf(pim
->mroute_socket
, 1024 * 1024 * 8);
113 if (set_nonblocking(pim
->mroute_socket
) < 0) {
115 "Could not set non blocking on socket fd=%d: errno=%d: %s",
116 pim
->mroute_socket
, errno
, safe_strerror(errno
));
122 int upcalls
= GMMSG_WRVIFWHOLE
;
125 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, opt
, &upcalls
,
129 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
130 errno
, safe_strerror(errno
));
135 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
142 static const char *const gmmsgtype2str
[GMMSG_WRVIFWHOLE
+ 1] = {
143 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
146 int pim_mroute_msg_nocache(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
148 struct pim_interface
*pim_ifp
= ifp
->info
;
149 struct pim_upstream
*up
;
153 memset(&sg
, 0, sizeof(sg
));
154 sg
.src
= msg
->msg_im_src
;
155 sg
.grp
= msg
->msg_im_dst
;
158 if (PIM_DEBUG_MROUTE
)
160 "%s: PIM not enabled on interface, dropping packet to %pSG",
165 if (!pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
166 /* for ASM, check that we have enough information (i.e. path
167 * to RP) to make a decision on what to do with this packet.
169 * for SSM, this is meaningless, everything is join-driven,
170 * and for NOCACHE we need to install an empty OIL MFC entry
171 * so the kernel doesn't keep nagging us.
175 rpg
= RP(pim_ifp
->pim
, msg
->msg_im_dst
);
177 if (PIM_DEBUG_MROUTE
)
178 zlog_debug("%s: no RPF for packet to %pSG",
182 if (pim_rpf_addr_is_inaddr_any(rpg
)) {
183 if (PIM_DEBUG_MROUTE
)
184 zlog_debug("%s: null RPF for packet to %pSG",
191 * If we've received a multicast packet that isn't connected to
194 if (!pim_if_connected_to_source(ifp
, msg
->msg_im_src
)) {
195 if (PIM_DEBUG_MROUTE
)
197 "%s: incoming packet to %pSG from non-connected source",
202 if (!(PIM_I_am_DR(pim_ifp
))) {
203 /* unlike the other debug messages, this one is further in the
204 * "normal operation" category and thus under _DETAIL
206 if (PIM_DEBUG_MROUTE_DETAIL
)
208 "%s: not DR on interface, not forwarding traffic for %pSG",
212 * We are not the DR, but we are still receiving packets
213 * Let's blackhole those packets for the moment
214 * As that they will be coming up to the cpu
215 * and causing us to consider them.
217 * This *will* create a dangling channel_oil
218 * that I see no way to get rid of. Just noting
219 * this for future reference.
221 up
= pim_upstream_find_or_add(
222 &sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
, __func__
);
223 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
228 up
= pim_upstream_find_or_add(&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
,
230 if (up
->channel_oil
->installed
) {
232 "%s: NOCACHE for %pSG, MFC entry disappeared - reinstalling",
238 * I moved this debug till after the actual add because
239 * I want to take advantage of the up->sg_str being filled in.
241 if (PIM_DEBUG_MROUTE
) {
242 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
243 __func__
, up
->sg_str
);
246 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
247 pim_upstream_keep_alive_timer_start(up
, pim_ifp
->pim
->keep_alive_time
);
249 up
->channel_oil
->cc
.pktcnt
++;
250 // resolve mfcc_parent prior to mroute_add in channel_add_oif
251 if (up
->rpf
.source_nexthop
.interface
&&
252 *oil_parent(up
->channel_oil
) >= MAXVIFS
) {
253 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
255 pim_register_join(up
);
256 /* if we have receiver, inherit from parent */
257 pim_upstream_inherited_olist_decide(pim_ifp
->pim
, up
);
259 /* we just got NOCACHE from the kernel, so... MFC is not in the
260 * kernel for some reason or another. Try installing again.
263 pim_upstream_mroute_update(up
->channel_oil
, __func__
);
267 int pim_mroute_msg_wholepkt(int fd
, struct interface
*ifp
, const char *buf
,
270 struct pim_interface
*pim_ifp
;
273 const ipv_hdr
*ip_hdr
;
274 struct pim_upstream
*up
;
278 ip_hdr
= (const ipv_hdr
*)buf
;
280 memset(&sg
, 0, sizeof(sg
));
281 sg
.src
= IPV_SRC(ip_hdr
);
282 sg
.grp
= IPV_DST(ip_hdr
);
284 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
286 pim_sgaddr star
= sg
;
287 star
.src
= PIMADDR_ANY
;
289 up
= pim_upstream_find(pim_ifp
->pim
, &star
);
291 if (up
&& PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
)) {
292 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
293 PIM_UPSTREAM_FLAG_MASK_SRC_LHR
,
296 if (PIM_DEBUG_MROUTE
)
298 "%s: Unable to create upstream information for %pSG",
302 pim_upstream_keep_alive_timer_start(
303 up
, pim_ifp
->pim
->keep_alive_time
);
304 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
305 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
307 if (PIM_DEBUG_MROUTE
)
308 zlog_debug("%s: Creating %s upstream on LHR",
309 __func__
, up
->sg_str
);
312 if (PIM_DEBUG_MROUTE_DETAIL
) {
314 "%s: Unable to find upstream channel WHOLEPKT%pSG",
320 if (!up
->rpf
.source_nexthop
.interface
) {
321 if (PIM_DEBUG_PIM_TRACE
)
322 zlog_debug("%s: up %s RPF is not present", __func__
,
327 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
329 rpg
= pim_ifp
? RP(pim_ifp
->pim
, sg
.grp
) : NULL
;
331 if ((pim_rpf_addr_is_inaddr_any(rpg
)) || (!pim_ifp
) ||
332 (!(PIM_I_am_DR(pim_ifp
)))) {
333 if (PIM_DEBUG_MROUTE
) {
334 zlog_debug("%s: Failed Check send packet", __func__
);
340 * If we've received a register suppress
342 if (!up
->t_rs_timer
) {
343 if (pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
344 if (PIM_DEBUG_PIM_REG
)
346 "%pSG register forward skipped as group is SSM",
351 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
352 if (PIM_DEBUG_PIM_REG
)
354 "%s register forward skipped, not FHR",
359 pim_register_send((uint8_t *)buf
+ sizeof(ipv_hdr
),
360 len
- sizeof(ipv_hdr
),
361 pim_ifp
->primary_address
, rpg
, 0, up
);
366 int pim_mroute_msg_wrongvif(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
368 struct pim_ifchannel
*ch
;
369 struct pim_interface
*pim_ifp
;
372 memset(&sg
, 0, sizeof(sg
));
373 sg
.src
= msg
->msg_im_src
;
374 sg
.grp
= msg
->msg_im_dst
;
377 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
379 RFC 4601 4.8.2. PIM-SSM-Only Routers
381 iif is the incoming interface of the packet.
382 if (iif is in inherited_olist(S,G)) {
383 send Assert(S,G) on iif
388 if (PIM_DEBUG_MROUTE
)
390 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
391 __func__
, &sg
, msg
->msg_im_vif
);
397 if (PIM_DEBUG_MROUTE
)
399 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
400 __func__
, &sg
, ifp
->name
);
404 ch
= pim_ifchannel_find(ifp
, &sg
);
406 pim_sgaddr star_g
= sg
;
407 if (PIM_DEBUG_MROUTE
)
409 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
410 __func__
, &sg
, ifp
->name
);
412 star_g
.src
= PIMADDR_ANY
;
413 ch
= pim_ifchannel_find(ifp
, &star_g
);
415 if (PIM_DEBUG_MROUTE
)
417 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
418 __func__
, &star_g
, ifp
->name
);
424 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
426 Transitions from NoInfo State
428 An (S,G) data packet arrives on interface I, AND
429 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
430 downstream interface that is in our (S,G) outgoing interface
431 list. We optimistically assume that we will be the assert
432 winner for this (S,G), and so we transition to the "I am Assert
433 Winner" state and perform Actions A1 (below), which will
434 initiate the assert negotiation for (S,G).
437 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
438 if (PIM_DEBUG_MROUTE
) {
440 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
441 __func__
, ch
->sg_str
, ifp
->name
);
446 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
447 if (PIM_DEBUG_MROUTE
) {
449 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
450 __func__
, ch
->sg_str
, ifp
->name
);
455 if (assert_action_a1(ch
)) {
456 if (PIM_DEBUG_MROUTE
) {
458 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
459 __func__
, ch
->sg_str
, ifp
->name
);
467 int pim_mroute_msg_wrvifwhole(int fd
, struct interface
*ifp
, const char *buf
,
470 const ipv_hdr
*ip_hdr
= (const ipv_hdr
*)buf
;
471 struct pim_interface
*pim_ifp
;
472 struct pim_instance
*pim
;
473 struct pim_ifchannel
*ch
;
474 struct pim_upstream
*up
;
480 memset(&sg
, 0, sizeof(sg
));
481 sg
.src
= IPV_SRC(ip_hdr
);
482 sg
.grp
= IPV_DST(ip_hdr
);
484 ch
= pim_ifchannel_find(ifp
, &sg
);
486 if (PIM_DEBUG_MROUTE
)
488 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
489 ch
->sg_str
, ifp
->name
);
494 star_g
.src
= PIMADDR_ANY
;
498 * If the incoming interface is the pimreg, then
499 * we know the callback is associated with a pim register
500 * packet and there is nothing to do here as that
501 * normal pim processing will see the packet and allow
502 * us to do the right thing.
504 if (ifp
== pim
->regiface
) {
508 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
510 struct pim_upstream
*parent
;
511 struct pim_nexthop source
;
512 struct pim_rpf
*rpf
= RP(pim_ifp
->pim
, sg
.grp
);
514 /* No RPF or No RPF interface or No mcast on RPF interface */
515 if (!rpf
|| !rpf
->source_nexthop
.interface
||
516 !rpf
->source_nexthop
.interface
->info
)
520 * If we have received a WRVIFWHOLE and are at this
521 * point, we could be receiving the packet on the *,G
522 * tree, let's check and if so we can safely drop
525 parent
= pim_upstream_find(pim_ifp
->pim
, &star_g
);
526 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
529 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
531 memset(&source
, 0, sizeof(source
));
533 * If we are the fhr that means we are getting a callback during
534 * the pimreg period, so I believe we can ignore this packet
536 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
538 * No if channel, but upstream we are at the RP.
540 * This could be a anycast RP too and we may
541 * not have received a register packet from
542 * the source here at all. So gracefully
543 * bow out of doing a nexthop lookup and
544 * setting the SPTBIT to true
546 if (!(pim_addr_is_any(up
->upstream_register
)) &&
547 pim_nexthop_lookup(pim_ifp
->pim
, &source
,
548 up
->upstream_register
, 0)) {
549 pim_register_stop_send(source
.interface
, &sg
,
550 pim_ifp
->primary_address
,
551 up
->upstream_register
);
552 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
555 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
556 if (!up
->channel_oil
->installed
)
557 pim_upstream_mroute_add(up
->channel_oil
,
560 if (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
)) {
561 if (pim_nexthop_lookup(pim_ifp
->pim
, &source
,
562 up
->upstream_register
,
564 pim_register_stop_send(
565 source
.interface
, &sg
,
566 pim_ifp
->primary_address
,
567 up
->upstream_register
);
568 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
571 * At this point pimd is connected to
572 * the source, it has a parent, we are not
573 * the RP and the SPTBIT should be set
574 * since we know *the* S,G is on the SPT.
575 * The first time this happens, let's cause
576 * an immediate join to go out so that
577 * the RP can trim this guy immediately
578 * if necessary, instead of waiting
579 * one join/prune send cycle
581 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
&&
583 up
->rpf
.source_nexthop
.interface
!=
584 up
->parent
->rpf
.source_nexthop
586 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
587 pim_jp_agg_single_upstream_send(
588 &up
->parent
->rpf
, up
->parent
,
592 pim_upstream_keep_alive_timer_start(
593 up
, pim_ifp
->pim
->keep_alive_time
);
594 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
595 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
601 if (pim_if_connected_to_source(ifp
, sg
.src
)) {
602 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
603 PIM_UPSTREAM_FLAG_MASK_FHR
, __func__
,
606 if (PIM_DEBUG_MROUTE
)
608 "%pSG: WRONGVIF%s unable to create upstream on interface",
612 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
613 pim_upstream_keep_alive_timer_start(
614 up
, pim_ifp
->pim
->keep_alive_time
);
615 up
->channel_oil
->cc
.pktcnt
++;
616 pim_register_join(up
);
617 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
618 if (!up
->channel_oil
->installed
)
619 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
621 // Send the packet to the RP
622 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
624 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
625 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
,
627 if (!up
->channel_oil
->installed
)
628 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
635 static int process_igmp_packet(struct pim_instance
*pim
, const char *buf
,
636 size_t buf_size
, ifindex_t ifindex
)
638 struct interface
*ifp
;
639 struct pim_interface
*pim_ifp
;
640 struct in_addr ifaddr
;
641 struct gm_sock
*igmp
;
642 const struct prefix
*connected_src
;
643 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
645 /* We have the IP packet but we do not know which interface this
647 * received on. Find the interface that is on the same subnet as
651 ifp
= if_lookup_by_index(ifindex
, pim
->vrf
->vrf_id
);
653 if (!ifp
|| !ifp
->info
)
656 connected_src
= pim_if_connected_to_source(ifp
, ip_hdr
->ip_src
);
658 if (!connected_src
&& !pim_addr_is_any(ip_hdr
->ip_src
)) {
659 if (PIM_DEBUG_GM_PACKETS
) {
661 "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
662 ifp
->name
, &ip_hdr
->ip_src
);
668 ifaddr
= connected_src
? connected_src
->u
.prefix4
669 : pim_ifp
->primary_address
;
670 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
, ifaddr
);
672 if (PIM_DEBUG_GM_PACKETS
) {
674 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
675 __func__
, pim
->vrf
->name
, ifp
->name
, igmp
,
676 &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
);
679 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
680 else if (PIM_DEBUG_GM_PACKETS
)
682 "No IGMP socket on interface: %s with connected source: %pI4",
689 int pim_mroute_msg(struct pim_instance
*pim
, const char *buf
, size_t buf_size
,
692 struct interface
*ifp
;
693 const ipv_hdr
*ip_hdr
;
696 if (buf_size
< (int)sizeof(ipv_hdr
))
699 ip_hdr
= (const ipv_hdr
*)buf
;
702 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
703 process_igmp_packet(pim
, buf
, buf_size
, ifindex
);
704 } else if (ip_hdr
->ip_p
) {
705 if (PIM_DEBUG_MROUTE_DETAIL
) {
707 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
708 __func__
, ip_hdr
->ip_p
, &ip_hdr
->ip_src
,
709 &ip_hdr
->ip_dst
, (long int)buf_size
);
715 if ((ip_hdr
->ip6_vfc
& 0xf) == 0) {
717 msg
= (const kernmsg
*)buf
;
719 ifp
= pim_if_find_by_vif_index(pim
, msg
->msg_im_vif
);
723 if (PIM_DEBUG_MROUTE
) {
726 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld",
727 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
728 msg
->msg_im_msgtype
, ip_hdr
->ip_p
,
729 pim
->mroute_socket
, &msg
->msg_im_src
,
730 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
734 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld",
735 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
736 msg
->msg_im_msgtype
, ip_hdr
->ip6_nxt
,
737 pim
->mroute_socket
, &msg
->msg_im_src
,
738 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
743 switch (msg
->msg_im_msgtype
) {
745 return pim_mroute_msg_wrongvif(pim
->mroute_socket
, ifp
,
748 return pim_mroute_msg_nocache(pim
->mroute_socket
, ifp
,
751 return pim_mroute_msg_wholepkt(pim
->mroute_socket
, ifp
,
754 case GMMSG_WRVIFWHOLE
:
755 return pim_mroute_msg_wrvifwhole(pim
->mroute_socket
,
756 ifp
, (const char *)msg
,
766 static void mroute_read(struct thread
*t
)
768 struct pim_instance
*pim
;
769 static long long count
;
777 rd
= pim_socket_recvfromto(pim
->mroute_socket
, (uint8_t *)buf
,
778 sizeof(buf
), NULL
, NULL
, NULL
, NULL
,
783 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
787 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
788 __func__
, rd
, pim
->mroute_socket
, errno
,
789 safe_strerror(errno
));
793 pim_mroute_msg(pim
, buf
, rd
, ifindex
);
796 if (count
% router
->packet_process
== 0)
806 static void mroute_read_on(struct pim_instance
*pim
)
808 thread_add_read(router
->master
, mroute_read
, pim
, pim
->mroute_socket
,
812 static void mroute_read_off(struct pim_instance
*pim
)
814 THREAD_OFF(pim
->thread
);
817 int pim_mroute_socket_enable(struct pim_instance
*pim
)
821 frr_with_privs(&pimd_privs
) {
824 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
826 fd
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
829 zlog_warn("Could not create mroute socket: errno=%d: %s",
831 safe_strerror(errno
));
836 struct icmp6_filter filter
[1];
839 /* Unlike IPv4, this socket is not used for MLD, so just drop
840 * everything with an empty ICMP6 filter. Otherwise we get
841 * all kinds of garbage here, possibly even non-multicast
842 * related ICMPv6 traffic (e.g. ping)
844 * (mroute kernel upcall "packets" are injected directly on the
845 * socket, this sockopt -or any other- has no effect on them)
847 ICMP6_FILTER_SETBLOCKALL(filter
);
848 ret
= setsockopt(fd
, SOL_ICMPV6
, ICMP6_FILTER
, filter
,
852 "(VRF %s) failed to set mroute control filter: %m",
856 #ifdef SO_BINDTODEVICE
857 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
858 && setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
859 pim
->vrf
->name
, strlen(pim
->vrf
->name
))) {
860 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
861 safe_strerror(errno
));
869 pim
->mroute_socket
= fd
;
870 if (pim_mroute_set(pim
, 1)) {
872 "Could not enable mroute on socket fd=%d: errno=%d: %s",
873 fd
, errno
, safe_strerror(errno
));
875 pim
->mroute_socket
= -1;
879 pim
->mroute_socket_creation
= pim_time_monotonic_sec();
886 int pim_mroute_socket_disable(struct pim_instance
*pim
)
888 if (pim_mroute_set(pim
, 0)) {
890 "Could not disable mroute on socket fd=%d: errno=%d: %s",
891 pim
->mroute_socket
, errno
, safe_strerror(errno
));
895 if (close(pim
->mroute_socket
)) {
896 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
897 pim
->mroute_socket
, errno
, safe_strerror(errno
));
901 mroute_read_off(pim
);
902 pim
->mroute_socket
= -1;
908 For each network interface (e.g., physical or a virtual tunnel) that
909 would be used for multicast forwarding, a corresponding multicast
910 interface must be added to the kernel.
912 int pim_mroute_add_vif(struct interface
*ifp
, pim_addr ifaddr
,
915 struct pim_interface
*pim_ifp
= ifp
->info
;
919 if (PIM_DEBUG_MROUTE
)
920 zlog_debug("%s: Add Vif %d (%s[%s])", __func__
,
921 pim_ifp
->mroute_vif_index
, ifp
->name
,
922 pim_ifp
->pim
->vrf
->name
);
924 memset(&vc
, 0, sizeof(vc
));
925 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
927 #ifdef VIFF_USE_IFINDEX
928 vc
.vc_lcl_ifindex
= ifp
->ifindex
;
930 if (ifaddr
.s_addr
== INADDR_ANY
) {
932 "%s: unnumbered interfaces are not supported on this platform",
936 memcpy(&vc
.vc_lcl_addr
, &ifaddr
, sizeof(vc
.vc_lcl_addr
));
939 vc
.vc_pifi
= ifp
->ifindex
;
942 vc
.vc_threshold
= PIM_MROUTE_MIN_TTL
;
943 vc
.vc_rate_limit
= 0;
946 #ifdef PIM_DVMRP_TUNNEL
947 if (vc
.vc_flags
& VIFF_TUNNEL
) {
948 memcpy(&vc
.vc_rmt_addr
, &vif_remote_addr
,
949 sizeof(vc
.vc_rmt_addr
));
954 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_VIF
,
955 (void *)&vc
, sizeof(vc
));
958 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
959 __func__
, pim_ifp
->pim
->mroute_socket
, ifp
->ifindex
,
960 &ifaddr
, flags
, errno
, safe_strerror(errno
));
967 int pim_mroute_del_vif(struct interface
*ifp
)
969 struct pim_interface
*pim_ifp
= ifp
->info
;
973 if (PIM_DEBUG_MROUTE
)
974 zlog_debug("%s: Del Vif %d (%s[%s])", __func__
,
975 pim_ifp
->mroute_vif_index
, ifp
->name
,
976 pim_ifp
->pim
->vrf
->name
);
978 memset(&vc
, 0, sizeof(vc
));
979 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
981 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_VIF
,
982 (void *)&vc
, sizeof(vc
));
985 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
986 __FILE__
, __func__
, pim_ifp
->pim
->mroute_socket
,
987 pim_ifp
->mroute_vif_index
, errno
, safe_strerror(errno
));
995 * Prevent creating MFC entry with OIF=IIF.
997 * This is a protection against implementation mistakes.
999 * PIM protocol implicitely ensures loopfree multicast topology.
1001 * IGMP must be protected against adding looped MFC entries created
1002 * by both source and receiver attached to the same interface. See
1004 * We shall allow igmp to create upstream when it is DR for the intf.
1005 * Assume RP reachable via non DR.
1007 bool pim_mroute_allow_iif_in_oil(struct channel_oil
*c_oil
,
1010 #ifdef PIM_ENFORCE_LOOPFREE_MFC
1011 struct interface
*ifp_out
;
1012 struct pim_interface
*pim_ifp
;
1015 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil
->up
->flags
))
1018 ifp_out
= pim_if_find_by_vif_index(c_oil
->pim
, oif_index
);
1021 pim_ifp
= ifp_out
->info
;
1024 if ((c_oil
->oif_flags
[oif_index
] & PIM_OIF_FLAG_PROTO_GM
) &&
1025 PIM_I_am_DR(pim_ifp
))
1034 static inline void pim_mroute_copy(struct channel_oil
*out
,
1035 struct channel_oil
*in
)
1039 *oil_origin(out
) = *oil_origin(in
);
1040 *oil_mcastgrp(out
) = *oil_mcastgrp(in
);
1041 *oil_parent(out
) = *oil_parent(in
);
1043 for (i
= 0; i
< MAXVIFS
; ++i
) {
1044 if (*oil_parent(out
) == i
&&
1045 !pim_mroute_allow_iif_in_oil(in
, i
)) {
1046 oil_if_set(out
, i
, 0);
1050 if (in
->oif_flags
[i
] & PIM_OIF_FLAG_MUTE
)
1051 oil_if_set(out
, i
, 0);
1053 oil_if_set(out
, i
, oil_if_has(in
, i
));
1057 /* This function must not be called directly 0
1058 * use pim_upstream_mroute_add or pim_static_mroute_add instead
1060 static int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1062 struct pim_instance
*pim
= c_oil
->pim
;
1063 struct channel_oil tmp_oil
[1] = { };
1066 pim
->mroute_add_last
= pim_time_monotonic_sec();
1067 ++pim
->mroute_add_events
;
1069 /* Copy the oil to a temporary structure to fixup (without need to
1070 * later restore) before sending the mroute add to the dataplane
1072 pim_mroute_copy(tmp_oil
, c_oil
);
1074 /* The linux kernel *expects* the incoming
1075 * vif to be part of the outgoing list
1076 * in the case of a (*,G).
1078 if (pim_addr_is_any(*oil_origin(c_oil
))) {
1079 oil_if_set(tmp_oil
, *oil_parent(c_oil
), 1);
1083 * If we have an unresolved cache entry for the S,G
1084 * it is owned by the pimreg for the incoming IIF
1085 * So set pimreg as the IIF temporarily to cause
1086 * the packets to be forwarded. Then set it
1087 * to the correct IIF afterwords.
1089 if (!c_oil
->installed
&& !pim_addr_is_any(*oil_origin(c_oil
))
1090 && *oil_parent(c_oil
) != 0) {
1091 *oil_parent(tmp_oil
) = 0;
1093 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
1094 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1095 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1097 if (!err
&& !c_oil
->installed
1098 && !pim_addr_is_any(*oil_origin(c_oil
))
1099 && *oil_parent(c_oil
) != 0) {
1100 *oil_parent(tmp_oil
) = *oil_parent(c_oil
);
1101 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1102 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1107 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
1108 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1109 safe_strerror(errno
));
1113 if (PIM_DEBUG_MROUTE
) {
1115 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__
, name
,
1117 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1120 if (!c_oil
->installed
) {
1121 c_oil
->installed
= 1;
1122 c_oil
->mroute_creation
= pim_time_monotonic_sec();
1128 static int pim_upstream_get_mroute_iif(struct channel_oil
*c_oil
,
1131 vifi_t iif
= MAXVIFS
;
1132 struct interface
*ifp
= NULL
;
1133 struct pim_interface
*pim_ifp
;
1134 struct pim_upstream
*up
= c_oil
->up
;
1137 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
)) {
1139 ifp
= up
->parent
->rpf
.source_nexthop
.interface
;
1141 ifp
= up
->rpf
.source_nexthop
.interface
;
1144 pim_ifp
= (struct pim_interface
*)ifp
->info
;
1146 iif
= pim_ifp
->mroute_vif_index
;
1152 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
1157 if (*oil_parent(c_oil
) >= MAXVIFS
) {
1158 /* the c_oil cannot be installed as a mroute yet */
1159 if (PIM_DEBUG_MROUTE
)
1161 "%s(%s) %s mroute not ready to be installed; %s",
1163 pim_channel_oil_dump(c_oil
, buf
,
1166 "uninstall" : "skip");
1167 /* if already installed flush it out as we are going to stop
1168 * updates to it leaving it in a stale state
1170 if (c_oil
->installed
)
1171 pim_mroute_del(c_oil
, name
);
1172 /* return success (skipped) */
1176 return pim_mroute_add(c_oil
, name
);
1179 /* IIF associated with SGrpt entries are re-evaluated when the parent
1180 * (*,G) entries IIF changes
1182 static void pim_upstream_all_sources_iif_update(struct pim_upstream
*up
)
1184 struct listnode
*listnode
;
1185 struct pim_upstream
*child
;
1187 for (ALL_LIST_ELEMENTS_RO(up
->sources
, listnode
,
1189 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
1190 pim_upstream_mroute_iif_update(child
->channel_oil
,
1195 /* In the case of "PIM state machine" added mroutes an upstream entry
1196 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1198 int pim_upstream_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1202 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1204 if (*oil_parent(c_oil
) != iif
) {
1205 *oil_parent(c_oil
) = iif
;
1206 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1208 pim_upstream_all_sources_iif_update(c_oil
->up
);
1210 *oil_parent(c_oil
) = iif
;
1213 return pim_upstream_mroute_update(c_oil
, name
);
1216 /* Look for IIF changes and update the dateplane entry only if the IIF
1219 int pim_upstream_mroute_iif_update(struct channel_oil
*c_oil
, const char *name
)
1224 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1225 if (*oil_parent(c_oil
) == iif
) {
1229 *oil_parent(c_oil
) = iif
;
1231 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1233 pim_upstream_all_sources_iif_update(c_oil
->up
);
1235 if (PIM_DEBUG_MROUTE_DETAIL
)
1236 zlog_debug("%s(%s) %s mroute iif update %d",
1238 pim_channel_oil_dump(c_oil
, buf
,
1240 /* XXX: is this hack needed? */
1241 c_oil
->oil_inherited_rescan
= 1;
1242 return pim_upstream_mroute_update(c_oil
, name
);
1245 int pim_static_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1247 return pim_mroute_add(c_oil
, name
);
1250 void pim_static_mroute_iif_update(struct channel_oil
*c_oil
,
1251 int input_vif_index
,
1254 if (*oil_parent(c_oil
) == input_vif_index
)
1257 *oil_parent(c_oil
) = input_vif_index
;
1258 if (input_vif_index
== MAXVIFS
)
1259 pim_mroute_del(c_oil
, name
);
1261 pim_static_mroute_add(c_oil
, name
);
1264 int pim_mroute_del(struct channel_oil
*c_oil
, const char *name
)
1266 struct pim_instance
*pim
= c_oil
->pim
;
1269 pim
->mroute_del_last
= pim_time_monotonic_sec();
1270 ++pim
->mroute_del_events
;
1272 if (!c_oil
->installed
) {
1273 if (PIM_DEBUG_MROUTE
) {
1276 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1277 __FILE__
, __func__
, *oil_parent(c_oil
),
1278 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1283 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_MFC
,
1284 &c_oil
->oil
, sizeof(c_oil
->oil
));
1286 if (PIM_DEBUG_MROUTE
)
1288 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
1289 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1290 safe_strerror(errno
));
1294 if (PIM_DEBUG_MROUTE
) {
1296 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__
, name
,
1298 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1301 // Reset kernel installed flag
1302 c_oil
->installed
= 0;
1307 void pim_mroute_update_counters(struct channel_oil
*c_oil
)
1309 struct pim_instance
*pim
= c_oil
->pim
;
1310 pim_sioc_sg_req sgreq
;
1312 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
1313 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
1314 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
1316 if (!c_oil
->installed
) {
1317 c_oil
->cc
.lastused
= 100 * pim
->keep_alive_time
;
1318 if (PIM_DEBUG_MROUTE
) {
1321 sg
.src
= *oil_origin(c_oil
);
1322 sg
.grp
= *oil_mcastgrp(c_oil
);
1323 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1330 memset(&sgreq
, 0, sizeof(sgreq
));
1332 pim_zlookup_sg_statistics(c_oil
);
1335 sgreq
.src
= *oil_origin(c_oil
);
1336 sgreq
.grp
= *oil_mcastgrp(c_oil
);
1338 sgreq
.src
= c_oil
->oil
.mf6cc_origin
;
1339 sgreq
.grp
= c_oil
->oil
.mf6cc_mcastgrp
;
1341 if (ioctl(pim
->mroute_socket
, PIM_SIOCGETSGCNT
, &sgreq
)) {
1344 sg
.src
= *oil_origin(c_oil
);
1345 sg
.grp
= *oil_mcastgrp(c_oil
);
1348 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1349 (unsigned long)PIM_SIOCGETSGCNT
, &sg
, errno
,
1350 safe_strerror(errno
));
1354 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
1355 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
1356 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;