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 (enable
&& 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_ifp
|| !pim_ifp
->pim_enable
) {
159 if (PIM_DEBUG_MROUTE
)
161 "%s: %s on interface, dropping packet to %pSG",
163 !pim_ifp
? "Multicast not enabled"
169 if (!pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
170 /* for ASM, check that we have enough information (i.e. path
171 * to RP) to make a decision on what to do with this packet.
173 * for SSM, this is meaningless, everything is join-driven,
174 * and for NOCACHE we need to install an empty OIL MFC entry
175 * so the kernel doesn't keep nagging us.
179 rpg
= RP(pim_ifp
->pim
, msg
->msg_im_dst
);
181 if (PIM_DEBUG_MROUTE
)
182 zlog_debug("%s: no RPF for packet to %pSG",
186 if (pim_rpf_addr_is_inaddr_any(rpg
)) {
187 if (PIM_DEBUG_MROUTE
)
188 zlog_debug("%s: null RPF for packet to %pSG",
195 * If we've received a multicast packet that isn't connected to
198 if (!pim_if_connected_to_source(ifp
, msg
->msg_im_src
)) {
199 if (PIM_DEBUG_MROUTE
)
201 "%s: incoming packet to %pSG from non-connected source",
206 if (!(PIM_I_am_DR(pim_ifp
))) {
207 /* unlike the other debug messages, this one is further in the
208 * "normal operation" category and thus under _DETAIL
210 if (PIM_DEBUG_MROUTE_DETAIL
)
212 "%s: not DR on interface, not forwarding traffic for %pSG",
216 * We are not the DR, but we are still receiving packets
217 * Let's blackhole those packets for the moment
218 * As that they will be coming up to the cpu
219 * and causing us to consider them.
221 * This *will* create a dangling channel_oil
222 * that I see no way to get rid of. Just noting
223 * this for future reference.
225 up
= pim_upstream_find_or_add(
226 &sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
, __func__
);
227 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
232 up
= pim_upstream_find_or_add(&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
,
234 if (up
->channel_oil
->installed
) {
236 "%s: NOCACHE for %pSG, MFC entry disappeared - reinstalling",
242 * I moved this debug till after the actual add because
243 * I want to take advantage of the up->sg_str being filled in.
245 if (PIM_DEBUG_MROUTE
) {
246 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
247 __func__
, up
->sg_str
);
250 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
251 pim_upstream_keep_alive_timer_start(up
, pim_ifp
->pim
->keep_alive_time
);
253 up
->channel_oil
->cc
.pktcnt
++;
254 // resolve mfcc_parent prior to mroute_add in channel_add_oif
255 if (up
->rpf
.source_nexthop
.interface
&&
256 *oil_parent(up
->channel_oil
) >= MAXVIFS
) {
257 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
259 pim_register_join(up
);
260 /* if we have receiver, inherit from parent */
261 pim_upstream_inherited_olist_decide(pim_ifp
->pim
, up
);
263 /* we just got NOCACHE from the kernel, so... MFC is not in the
264 * kernel for some reason or another. Try installing again.
267 pim_upstream_mroute_update(up
->channel_oil
, __func__
);
271 int pim_mroute_msg_wholepkt(int fd
, struct interface
*ifp
, const char *buf
,
274 struct pim_interface
*pim_ifp
;
277 const ipv_hdr
*ip_hdr
;
278 struct pim_upstream
*up
;
282 ip_hdr
= (const ipv_hdr
*)buf
;
284 memset(&sg
, 0, sizeof(sg
));
285 sg
.src
= IPV_SRC(ip_hdr
);
286 sg
.grp
= IPV_DST(ip_hdr
);
288 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
290 pim_sgaddr star
= sg
;
291 star
.src
= PIMADDR_ANY
;
293 up
= pim_upstream_find(pim_ifp
->pim
, &star
);
295 if (up
&& PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
)) {
296 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
297 PIM_UPSTREAM_FLAG_MASK_SRC_LHR
,
300 if (PIM_DEBUG_MROUTE
)
302 "%s: Unable to create upstream information for %pSG",
306 pim_upstream_keep_alive_timer_start(
307 up
, pim_ifp
->pim
->keep_alive_time
);
308 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
309 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
311 if (PIM_DEBUG_MROUTE
)
312 zlog_debug("%s: Creating %s upstream on LHR",
313 __func__
, up
->sg_str
);
316 if (PIM_DEBUG_MROUTE_DETAIL
) {
318 "%s: Unable to find upstream channel WHOLEPKT%pSG",
324 if (!up
->rpf
.source_nexthop
.interface
) {
325 if (PIM_DEBUG_PIM_TRACE
)
326 zlog_debug("%s: up %s RPF is not present", __func__
,
331 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
333 rpg
= pim_ifp
? RP(pim_ifp
->pim
, sg
.grp
) : NULL
;
335 if ((pim_rpf_addr_is_inaddr_any(rpg
)) || (!pim_ifp
) ||
336 (!(PIM_I_am_DR(pim_ifp
)))) {
337 if (PIM_DEBUG_MROUTE
) {
338 zlog_debug("%s: Failed Check send packet", __func__
);
344 * If we've received a register suppress
346 if (!up
->t_rs_timer
) {
347 if (pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
348 if (PIM_DEBUG_PIM_REG
)
350 "%pSG register forward skipped as group is SSM",
355 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
356 if (PIM_DEBUG_PIM_REG
)
358 "%s register forward skipped, not FHR",
363 pim_register_send((uint8_t *)buf
+ sizeof(ipv_hdr
),
364 len
- sizeof(ipv_hdr
),
365 pim_ifp
->primary_address
, rpg
, 0, up
);
370 int pim_mroute_msg_wrongvif(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
372 struct pim_ifchannel
*ch
;
373 struct pim_interface
*pim_ifp
;
376 memset(&sg
, 0, sizeof(sg
));
377 sg
.src
= msg
->msg_im_src
;
378 sg
.grp
= msg
->msg_im_dst
;
381 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
383 RFC 4601 4.8.2. PIM-SSM-Only Routers
385 iif is the incoming interface of the packet.
386 if (iif is in inherited_olist(S,G)) {
387 send Assert(S,G) on iif
392 if (PIM_DEBUG_MROUTE
)
394 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
395 __func__
, &sg
, msg
->msg_im_vif
);
401 if (PIM_DEBUG_MROUTE
)
403 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
404 __func__
, &sg
, ifp
->name
);
408 ch
= pim_ifchannel_find(ifp
, &sg
);
410 pim_sgaddr star_g
= sg
;
411 if (PIM_DEBUG_MROUTE
)
413 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
414 __func__
, &sg
, ifp
->name
);
416 star_g
.src
= PIMADDR_ANY
;
417 ch
= pim_ifchannel_find(ifp
, &star_g
);
419 if (PIM_DEBUG_MROUTE
)
421 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
422 __func__
, &star_g
, ifp
->name
);
428 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
430 Transitions from NoInfo State
432 An (S,G) data packet arrives on interface I, AND
433 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
434 downstream interface that is in our (S,G) outgoing interface
435 list. We optimistically assume that we will be the assert
436 winner for this (S,G), and so we transition to the "I am Assert
437 Winner" state and perform Actions A1 (below), which will
438 initiate the assert negotiation for (S,G).
441 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
442 if (PIM_DEBUG_MROUTE
) {
444 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
445 __func__
, ch
->sg_str
, ifp
->name
);
450 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
451 if (PIM_DEBUG_MROUTE
) {
453 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
454 __func__
, ch
->sg_str
, ifp
->name
);
459 if (assert_action_a1(ch
)) {
460 if (PIM_DEBUG_MROUTE
) {
462 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
463 __func__
, ch
->sg_str
, ifp
->name
);
471 int pim_mroute_msg_wrvifwhole(int fd
, struct interface
*ifp
, const char *buf
,
474 const ipv_hdr
*ip_hdr
= (const ipv_hdr
*)buf
;
475 struct pim_interface
*pim_ifp
;
476 struct pim_instance
*pim
;
477 struct pim_ifchannel
*ch
;
478 struct pim_upstream
*up
;
484 memset(&sg
, 0, sizeof(sg
));
485 sg
.src
= IPV_SRC(ip_hdr
);
486 sg
.grp
= IPV_DST(ip_hdr
);
488 ch
= pim_ifchannel_find(ifp
, &sg
);
490 if (PIM_DEBUG_MROUTE
)
492 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
493 ch
->sg_str
, ifp
->name
);
498 star_g
.src
= PIMADDR_ANY
;
502 * If the incoming interface is the pimreg, then
503 * we know the callback is associated with a pim register
504 * packet and there is nothing to do here as that
505 * normal pim processing will see the packet and allow
506 * us to do the right thing.
508 if (ifp
== pim
->regiface
) {
512 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
514 struct pim_upstream
*parent
;
515 struct pim_nexthop source
;
516 struct pim_rpf
*rpf
= RP(pim_ifp
->pim
, sg
.grp
);
518 /* No RPF or No RPF interface or No mcast on RPF interface */
519 if (!rpf
|| !rpf
->source_nexthop
.interface
||
520 !rpf
->source_nexthop
.interface
->info
)
524 * If we have received a WRVIFWHOLE and are at this
525 * point, we could be receiving the packet on the *,G
526 * tree, let's check and if so we can safely drop
529 parent
= pim_upstream_find(pim_ifp
->pim
, &star_g
);
530 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
533 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
535 memset(&source
, 0, sizeof(source
));
537 * If we are the fhr that means we are getting a callback during
538 * the pimreg period, so I believe we can ignore this packet
540 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
542 * No if channel, but upstream we are at the RP.
544 * This could be a anycast RP too and we may
545 * not have received a register packet from
546 * the source here at all. So gracefully
547 * bow out of doing a nexthop lookup and
548 * setting the SPTBIT to true
550 if (!(pim_addr_is_any(up
->upstream_register
)) &&
551 pim_nexthop_lookup(pim_ifp
->pim
, &source
,
552 up
->upstream_register
, 0)) {
553 pim_register_stop_send(source
.interface
, &sg
,
554 pim_ifp
->primary_address
,
555 up
->upstream_register
);
556 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
559 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
560 if (!up
->channel_oil
->installed
)
561 pim_upstream_mroute_add(up
->channel_oil
,
564 if (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
)) {
565 if (pim_nexthop_lookup(pim_ifp
->pim
, &source
,
566 up
->upstream_register
,
568 pim_register_stop_send(
569 source
.interface
, &sg
,
570 pim_ifp
->primary_address
,
571 up
->upstream_register
);
572 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
575 * At this point pimd is connected to
576 * the source, it has a parent, we are not
577 * the RP and the SPTBIT should be set
578 * since we know *the* S,G is on the SPT.
579 * The first time this happens, let's cause
580 * an immediate join to go out so that
581 * the RP can trim this guy immediately
582 * if necessary, instead of waiting
583 * one join/prune send cycle
585 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
&&
587 up
->rpf
.source_nexthop
.interface
!=
588 up
->parent
->rpf
.source_nexthop
590 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
591 pim_jp_agg_single_upstream_send(
592 &up
->parent
->rpf
, up
->parent
,
596 pim_upstream_keep_alive_timer_start(
597 up
, pim_ifp
->pim
->keep_alive_time
);
598 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
599 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
605 if (pim_if_connected_to_source(ifp
, sg
.src
)) {
606 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
607 PIM_UPSTREAM_FLAG_MASK_FHR
, __func__
,
610 if (PIM_DEBUG_MROUTE
)
612 "%pSG: WRONGVIF%s unable to create upstream on interface",
616 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
617 pim_upstream_keep_alive_timer_start(
618 up
, pim_ifp
->pim
->keep_alive_time
);
619 up
->channel_oil
->cc
.pktcnt
++;
620 pim_register_join(up
);
621 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
622 if (!up
->channel_oil
->installed
)
623 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
625 // Send the packet to the RP
626 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
628 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
629 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
,
631 if (!up
->channel_oil
->installed
)
632 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
639 static int process_igmp_packet(struct pim_instance
*pim
, const char *buf
,
640 size_t buf_size
, ifindex_t ifindex
)
642 struct interface
*ifp
;
643 struct pim_interface
*pim_ifp
;
644 struct in_addr ifaddr
;
645 struct gm_sock
*igmp
;
646 const struct prefix
*connected_src
;
647 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
649 /* We have the IP packet but we do not know which interface this
651 * received on. Find the interface that is on the same subnet as
655 ifp
= if_lookup_by_index(ifindex
, pim
->vrf
->vrf_id
);
657 if (!ifp
|| !ifp
->info
)
660 connected_src
= pim_if_connected_to_source(ifp
, ip_hdr
->ip_src
);
662 if (!connected_src
&& !pim_addr_is_any(ip_hdr
->ip_src
)) {
663 if (PIM_DEBUG_GM_PACKETS
) {
665 "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
666 ifp
->name
, &ip_hdr
->ip_src
);
672 ifaddr
= connected_src
? connected_src
->u
.prefix4
673 : pim_ifp
->primary_address
;
674 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
, ifaddr
);
676 if (PIM_DEBUG_GM_PACKETS
) {
678 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
679 __func__
, pim
->vrf
->name
, ifp
->name
, igmp
,
680 &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
);
683 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
684 else if (PIM_DEBUG_GM_PACKETS
)
686 "No IGMP socket on interface: %s with connected source: %pI4",
693 int pim_mroute_msg(struct pim_instance
*pim
, const char *buf
, size_t buf_size
,
696 struct interface
*ifp
;
697 const ipv_hdr
*ip_hdr
;
700 if (buf_size
< (int)sizeof(ipv_hdr
))
703 ip_hdr
= (const ipv_hdr
*)buf
;
706 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
707 process_igmp_packet(pim
, buf
, buf_size
, ifindex
);
708 } else if (ip_hdr
->ip_p
) {
709 if (PIM_DEBUG_MROUTE_DETAIL
) {
711 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
712 __func__
, ip_hdr
->ip_p
, &ip_hdr
->ip_src
,
713 &ip_hdr
->ip_dst
, (long int)buf_size
);
719 if ((ip_hdr
->ip6_vfc
& 0xf) == 0) {
721 msg
= (const kernmsg
*)buf
;
723 ifp
= pim_if_find_by_vif_index(pim
, msg
->msg_im_vif
);
727 if (PIM_DEBUG_MROUTE
) {
730 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld",
731 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
732 msg
->msg_im_msgtype
, ip_hdr
->ip_p
,
733 pim
->mroute_socket
, &msg
->msg_im_src
,
734 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
738 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld",
739 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
740 msg
->msg_im_msgtype
, ip_hdr
->ip6_nxt
,
741 pim
->mroute_socket
, &msg
->msg_im_src
,
742 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
747 switch (msg
->msg_im_msgtype
) {
749 return pim_mroute_msg_wrongvif(pim
->mroute_socket
, ifp
,
752 return pim_mroute_msg_nocache(pim
->mroute_socket
, ifp
,
755 return pim_mroute_msg_wholepkt(pim
->mroute_socket
, ifp
,
758 case GMMSG_WRVIFWHOLE
:
759 return pim_mroute_msg_wrvifwhole(pim
->mroute_socket
,
760 ifp
, (const char *)msg
,
770 static void mroute_read(struct event
*t
)
772 struct pim_instance
*pim
;
773 static long long count
;
781 rd
= pim_socket_recvfromto(pim
->mroute_socket
, (uint8_t *)buf
,
782 sizeof(buf
), NULL
, NULL
, NULL
, NULL
,
787 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
791 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
792 __func__
, rd
, pim
->mroute_socket
, errno
,
793 safe_strerror(errno
));
797 pim_mroute_msg(pim
, buf
, rd
, ifindex
);
800 if (count
% router
->packet_process
== 0)
810 static void mroute_read_on(struct pim_instance
*pim
)
812 event_add_read(router
->master
, mroute_read
, pim
, pim
->mroute_socket
,
816 static void mroute_read_off(struct pim_instance
*pim
)
818 EVENT_OFF(pim
->thread
);
821 int pim_mroute_socket_enable(struct pim_instance
*pim
)
825 frr_with_privs(&pimd_privs
) {
828 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
830 fd
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
833 zlog_warn("Could not create mroute socket: errno=%d: %s",
835 safe_strerror(errno
));
840 struct icmp6_filter filter
[1];
843 /* Unlike IPv4, this socket is not used for MLD, so just drop
844 * everything with an empty ICMP6 filter. Otherwise we get
845 * all kinds of garbage here, possibly even non-multicast
846 * related ICMPv6 traffic (e.g. ping)
848 * (mroute kernel upcall "packets" are injected directly on the
849 * socket, this sockopt -or any other- has no effect on them)
851 ICMP6_FILTER_SETBLOCKALL(filter
);
852 ret
= setsockopt(fd
, SOL_ICMPV6
, ICMP6_FILTER
, filter
,
856 "(VRF %s) failed to set mroute control filter: %m",
860 #ifdef SO_BINDTODEVICE
861 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
862 && setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
863 pim
->vrf
->name
, strlen(pim
->vrf
->name
))) {
864 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
865 safe_strerror(errno
));
873 pim
->mroute_socket
= fd
;
874 if (pim_mroute_set(pim
, 1)) {
876 "Could not enable mroute on socket fd=%d: errno=%d: %s",
877 fd
, errno
, safe_strerror(errno
));
879 pim
->mroute_socket
= -1;
883 pim
->mroute_socket_creation
= pim_time_monotonic_sec();
890 int pim_mroute_socket_disable(struct pim_instance
*pim
)
892 if (pim_mroute_set(pim
, 0)) {
894 "Could not disable mroute on socket fd=%d: errno=%d: %s",
895 pim
->mroute_socket
, errno
, safe_strerror(errno
));
899 if (close(pim
->mroute_socket
)) {
900 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
901 pim
->mroute_socket
, errno
, safe_strerror(errno
));
905 mroute_read_off(pim
);
906 pim
->mroute_socket
= -1;
912 For each network interface (e.g., physical or a virtual tunnel) that
913 would be used for multicast forwarding, a corresponding multicast
914 interface must be added to the kernel.
916 int pim_mroute_add_vif(struct interface
*ifp
, pim_addr ifaddr
,
919 struct pim_interface
*pim_ifp
= ifp
->info
;
923 if (PIM_DEBUG_MROUTE
)
924 zlog_debug("%s: Add Vif %d (%s[%s])", __func__
,
925 pim_ifp
->mroute_vif_index
, ifp
->name
,
926 pim_ifp
->pim
->vrf
->name
);
928 memset(&vc
, 0, sizeof(vc
));
929 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
931 #ifdef VIFF_USE_IFINDEX
932 vc
.vc_lcl_ifindex
= ifp
->ifindex
;
934 if (ifaddr
.s_addr
== INADDR_ANY
) {
936 "%s: unnumbered interfaces are not supported on this platform",
940 memcpy(&vc
.vc_lcl_addr
, &ifaddr
, sizeof(vc
.vc_lcl_addr
));
943 vc
.vc_pifi
= ifp
->ifindex
;
946 vc
.vc_threshold
= PIM_MROUTE_MIN_TTL
;
947 vc
.vc_rate_limit
= 0;
950 #ifdef PIM_DVMRP_TUNNEL
951 if (vc
.vc_flags
& VIFF_TUNNEL
) {
952 memcpy(&vc
.vc_rmt_addr
, &vif_remote_addr
,
953 sizeof(vc
.vc_rmt_addr
));
958 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_VIF
,
959 (void *)&vc
, sizeof(vc
));
962 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
963 __func__
, pim_ifp
->pim
->mroute_socket
, ifp
->ifindex
,
964 &ifaddr
, flags
, errno
, safe_strerror(errno
));
971 int pim_mroute_del_vif(struct interface
*ifp
)
973 struct pim_interface
*pim_ifp
= ifp
->info
;
977 if (PIM_DEBUG_MROUTE
)
978 zlog_debug("%s: Del Vif %d (%s[%s])", __func__
,
979 pim_ifp
->mroute_vif_index
, ifp
->name
,
980 pim_ifp
->pim
->vrf
->name
);
982 memset(&vc
, 0, sizeof(vc
));
983 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
985 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_VIF
,
986 (void *)&vc
, sizeof(vc
));
989 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
990 __FILE__
, __func__
, pim_ifp
->pim
->mroute_socket
,
991 pim_ifp
->mroute_vif_index
, errno
, safe_strerror(errno
));
999 * Prevent creating MFC entry with OIF=IIF.
1001 * This is a protection against implementation mistakes.
1003 * PIM protocol implicitely ensures loopfree multicast topology.
1005 * IGMP must be protected against adding looped MFC entries created
1006 * by both source and receiver attached to the same interface. See
1008 * We shall allow igmp to create upstream when it is DR for the intf.
1009 * Assume RP reachable via non DR.
1011 bool pim_mroute_allow_iif_in_oil(struct channel_oil
*c_oil
,
1014 #ifdef PIM_ENFORCE_LOOPFREE_MFC
1015 struct interface
*ifp_out
;
1016 struct pim_interface
*pim_ifp
;
1019 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil
->up
->flags
))
1022 ifp_out
= pim_if_find_by_vif_index(c_oil
->pim
, oif_index
);
1025 pim_ifp
= ifp_out
->info
;
1028 if ((c_oil
->oif_flags
[oif_index
] & PIM_OIF_FLAG_PROTO_GM
) &&
1029 PIM_I_am_DR(pim_ifp
))
1038 static inline void pim_mroute_copy(struct channel_oil
*out
,
1039 struct channel_oil
*in
)
1043 *oil_origin(out
) = *oil_origin(in
);
1044 *oil_mcastgrp(out
) = *oil_mcastgrp(in
);
1045 *oil_parent(out
) = *oil_parent(in
);
1047 for (i
= 0; i
< MAXVIFS
; ++i
) {
1048 if (*oil_parent(out
) == i
&&
1049 !pim_mroute_allow_iif_in_oil(in
, i
)) {
1050 oil_if_set(out
, i
, 0);
1054 if (in
->oif_flags
[i
] & PIM_OIF_FLAG_MUTE
)
1055 oil_if_set(out
, i
, 0);
1057 oil_if_set(out
, i
, oil_if_has(in
, i
));
1061 /* This function must not be called directly 0
1062 * use pim_upstream_mroute_add or pim_static_mroute_add instead
1064 static int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1066 struct pim_instance
*pim
= c_oil
->pim
;
1067 struct channel_oil tmp_oil
[1] = { };
1070 pim
->mroute_add_last
= pim_time_monotonic_sec();
1071 ++pim
->mroute_add_events
;
1073 /* Copy the oil to a temporary structure to fixup (without need to
1074 * later restore) before sending the mroute add to the dataplane
1076 pim_mroute_copy(tmp_oil
, c_oil
);
1078 /* The linux kernel *expects* the incoming
1079 * vif to be part of the outgoing list
1080 * in the case of a (*,G).
1082 if (pim_addr_is_any(*oil_origin(c_oil
))) {
1083 oil_if_set(tmp_oil
, *oil_parent(c_oil
), 1);
1087 * If we have an unresolved cache entry for the S,G
1088 * it is owned by the pimreg for the incoming IIF
1089 * So set pimreg as the IIF temporarily to cause
1090 * the packets to be forwarded. Then set it
1091 * to the correct IIF afterwords.
1093 if (!c_oil
->installed
&& !pim_addr_is_any(*oil_origin(c_oil
))
1094 && *oil_parent(c_oil
) != 0) {
1095 *oil_parent(tmp_oil
) = 0;
1097 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
1098 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1099 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1101 if (!err
&& !c_oil
->installed
1102 && !pim_addr_is_any(*oil_origin(c_oil
))
1103 && *oil_parent(c_oil
) != 0) {
1104 *oil_parent(tmp_oil
) = *oil_parent(c_oil
);
1105 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1106 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1111 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
1112 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1113 safe_strerror(errno
));
1117 if (PIM_DEBUG_MROUTE
) {
1119 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__
, name
,
1121 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1124 if (!c_oil
->installed
) {
1125 c_oil
->installed
= 1;
1126 c_oil
->mroute_creation
= pim_time_monotonic_sec();
1132 static int pim_upstream_get_mroute_iif(struct channel_oil
*c_oil
,
1135 vifi_t iif
= MAXVIFS
;
1136 struct interface
*ifp
= NULL
;
1137 struct pim_interface
*pim_ifp
;
1138 struct pim_upstream
*up
= c_oil
->up
;
1141 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
)) {
1143 ifp
= up
->parent
->rpf
.source_nexthop
.interface
;
1145 ifp
= up
->rpf
.source_nexthop
.interface
;
1148 pim_ifp
= (struct pim_interface
*)ifp
->info
;
1150 iif
= pim_ifp
->mroute_vif_index
;
1156 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
1161 if (*oil_parent(c_oil
) >= MAXVIFS
) {
1162 /* the c_oil cannot be installed as a mroute yet */
1163 if (PIM_DEBUG_MROUTE
)
1165 "%s(%s) %s mroute not ready to be installed; %s",
1167 pim_channel_oil_dump(c_oil
, buf
,
1170 "uninstall" : "skip");
1171 /* if already installed flush it out as we are going to stop
1172 * updates to it leaving it in a stale state
1174 if (c_oil
->installed
)
1175 pim_mroute_del(c_oil
, name
);
1176 /* return success (skipped) */
1180 return pim_mroute_add(c_oil
, name
);
1183 /* IIF associated with SGrpt entries are re-evaluated when the parent
1184 * (*,G) entries IIF changes
1186 static void pim_upstream_all_sources_iif_update(struct pim_upstream
*up
)
1188 struct listnode
*listnode
;
1189 struct pim_upstream
*child
;
1191 for (ALL_LIST_ELEMENTS_RO(up
->sources
, listnode
,
1193 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
1194 pim_upstream_mroute_iif_update(child
->channel_oil
,
1199 /* In the case of "PIM state machine" added mroutes an upstream entry
1200 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1202 int pim_upstream_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1206 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1208 if (*oil_parent(c_oil
) != iif
) {
1209 *oil_parent(c_oil
) = iif
;
1210 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1212 pim_upstream_all_sources_iif_update(c_oil
->up
);
1214 *oil_parent(c_oil
) = iif
;
1217 return pim_upstream_mroute_update(c_oil
, name
);
1220 /* Look for IIF changes and update the dateplane entry only if the IIF
1223 int pim_upstream_mroute_iif_update(struct channel_oil
*c_oil
, const char *name
)
1228 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1229 if (*oil_parent(c_oil
) == iif
) {
1233 *oil_parent(c_oil
) = iif
;
1235 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1237 pim_upstream_all_sources_iif_update(c_oil
->up
);
1239 if (PIM_DEBUG_MROUTE_DETAIL
)
1240 zlog_debug("%s(%s) %s mroute iif update %d",
1242 pim_channel_oil_dump(c_oil
, buf
,
1244 /* XXX: is this hack needed? */
1245 c_oil
->oil_inherited_rescan
= 1;
1246 return pim_upstream_mroute_update(c_oil
, name
);
1249 int pim_static_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1251 return pim_mroute_add(c_oil
, name
);
1254 void pim_static_mroute_iif_update(struct channel_oil
*c_oil
,
1255 int input_vif_index
,
1258 if (*oil_parent(c_oil
) == input_vif_index
)
1261 *oil_parent(c_oil
) = input_vif_index
;
1262 if (input_vif_index
== MAXVIFS
)
1263 pim_mroute_del(c_oil
, name
);
1265 pim_static_mroute_add(c_oil
, name
);
1268 int pim_mroute_del(struct channel_oil
*c_oil
, const char *name
)
1270 struct pim_instance
*pim
= c_oil
->pim
;
1273 pim
->mroute_del_last
= pim_time_monotonic_sec();
1274 ++pim
->mroute_del_events
;
1276 if (!c_oil
->installed
) {
1277 if (PIM_DEBUG_MROUTE
) {
1280 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1281 __FILE__
, __func__
, *oil_parent(c_oil
),
1282 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1287 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_MFC
,
1288 &c_oil
->oil
, sizeof(c_oil
->oil
));
1290 if (PIM_DEBUG_MROUTE
)
1292 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
1293 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1294 safe_strerror(errno
));
1298 if (PIM_DEBUG_MROUTE
) {
1300 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__
, name
,
1302 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1305 // Reset kernel installed flag
1306 c_oil
->installed
= 0;
1311 void pim_mroute_update_counters(struct channel_oil
*c_oil
)
1313 struct pim_instance
*pim
= c_oil
->pim
;
1314 pim_sioc_sg_req sgreq
;
1316 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
1317 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
1318 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
1320 if (!c_oil
->installed
) {
1321 c_oil
->cc
.lastused
= 100 * pim
->keep_alive_time
;
1322 if (PIM_DEBUG_MROUTE
) {
1325 sg
.src
= *oil_origin(c_oil
);
1326 sg
.grp
= *oil_mcastgrp(c_oil
);
1327 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1334 memset(&sgreq
, 0, sizeof(sgreq
));
1336 pim_zlookup_sg_statistics(c_oil
);
1339 sgreq
.src
= *oil_origin(c_oil
);
1340 sgreq
.grp
= *oil_mcastgrp(c_oil
);
1342 sgreq
.src
= c_oil
->oil
.mf6cc_origin
;
1343 sgreq
.grp
= c_oil
->oil
.mf6cc_mcastgrp
;
1345 if (ioctl(pim
->mroute_socket
, PIM_SIOCGETSGCNT
, &sgreq
)) {
1348 sg
.src
= *oil_origin(c_oil
);
1349 sg
.grp
= *oil_mcastgrp(c_oil
);
1352 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1353 (unsigned long)PIM_SIOCGETSGCNT
, &sg
, errno
,
1354 safe_strerror(errno
));
1358 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
1359 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
1360 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;