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
);
38 int pim_mroute_set(struct pim_instance
*pim
, int enable
)
42 socklen_t data_len
= sizeof(data
);
45 * We need to create the VRF table for the pim mroute_socket
47 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
) {
48 frr_with_privs (&pimd_privs
) {
50 data
= pim
->vrf
->data
.l
.table_id
;
51 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
,
52 MRT_TABLE
, &data
, data_len
);
55 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s",
56 __FILE__
, __func__
, pim
->mroute_socket
,
57 data
, errno
, safe_strerror(errno
));
63 frr_with_privs (&pimd_privs
) {
64 opt
= enable
? MRT_INIT
: MRT_DONE
;
66 * *BSD *cares* about what value we pass down
70 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, opt
, &data
,
74 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
75 __FILE__
, __func__
, pim
->mroute_socket
,
76 enable
? "MRT_INIT" : "MRT_DONE", data
, errno
,
77 safe_strerror(errno
));
82 #if defined(HAVE_IP_PKTINFO)
84 /* Linux and Solaris IP_PKTINFO */
86 if (setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, IP_PKTINFO
,
89 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
90 pim
->mroute_socket
, errno
,
91 safe_strerror(errno
));
98 /* Linux and Solaris IPV6_PKTINFO */
100 if (setsockopt(pim
->mroute_socket
, PIM_IPPROTO
,
101 IPV6_RECVPKTINFO
, &data
, data_len
)) {
103 "Could not set IPV6_RECVPKTINFO on socket fd=%d: errno=%d: %s",
104 pim
->mroute_socket
, errno
,
105 safe_strerror(errno
));
109 setsockopt_so_recvbuf(pim
->mroute_socket
, 1024 * 1024 * 8);
111 if (set_nonblocking(pim
->mroute_socket
) < 0) {
113 "Could not set non blocking on socket fd=%d: errno=%d: %s",
114 pim
->mroute_socket
, errno
, safe_strerror(errno
));
120 int upcalls
= GMMSG_WRVIFWHOLE
;
123 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, opt
, &upcalls
,
127 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
128 errno
, safe_strerror(errno
));
133 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
140 static const char *const gmmsgtype2str
[GMMSG_WRVIFWHOLE
+ 1] = {
141 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
144 int pim_mroute_msg_nocache(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
146 struct pim_interface
*pim_ifp
= ifp
->info
;
147 struct pim_upstream
*up
;
151 rpg
= pim_ifp
? RP(pim_ifp
->pim
, msg
->msg_im_dst
) : NULL
;
153 * If the incoming interface is unknown OR
154 * the Interface type is SSM we don't need to
157 if (!rpg
|| pim_rpf_addr_is_inaddr_any(rpg
)) {
158 if (PIM_DEBUG_MROUTE_DETAIL
)
160 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
167 * If we've received a multicast packet that isn't connected to
170 if (!pim_if_connected_to_source(ifp
, msg
->msg_im_src
)) {
171 if (PIM_DEBUG_MROUTE_DETAIL
)
173 "%s: Received incoming packet that doesn't originate on our seg",
178 memset(&sg
, 0, sizeof(sg
));
179 sg
.src
= msg
->msg_im_src
;
180 sg
.grp
= msg
->msg_im_dst
;
182 if (!(PIM_I_am_DR(pim_ifp
))) {
183 if (PIM_DEBUG_MROUTE_DETAIL
)
185 "%s: Interface is not the DR blackholing incoming traffic for %pSG",
189 * We are not the DR, but we are still receiving packets
190 * Let's blackhole those packets for the moment
191 * As that they will be coming up to the cpu
192 * and causing us to consider them.
194 * This *will* create a dangling channel_oil
195 * that I see no way to get rid of. Just noting
196 * this for future reference.
198 up
= pim_upstream_find_or_add(
199 &sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
, __func__
);
200 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
205 up
= pim_upstream_find_or_add(&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
,
209 * I moved this debug till after the actual add because
210 * I want to take advantage of the up->sg_str being filled in.
212 if (PIM_DEBUG_MROUTE
) {
213 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
214 __func__
, up
->sg_str
);
217 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
218 pim_upstream_keep_alive_timer_start(up
, pim_ifp
->pim
->keep_alive_time
);
220 up
->channel_oil
->cc
.pktcnt
++;
221 // resolve mfcc_parent prior to mroute_add in channel_add_oif
222 if (up
->rpf
.source_nexthop
.interface
&&
223 *oil_parent(up
->channel_oil
) >= MAXVIFS
) {
224 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
226 pim_register_join(up
);
227 /* if we have receiver, inherit from parent */
228 pim_upstream_inherited_olist_decide(pim_ifp
->pim
, up
);
233 int pim_mroute_msg_wholepkt(int fd
, struct interface
*ifp
, const char *buf
,
236 struct pim_interface
*pim_ifp
;
239 const ipv_hdr
*ip_hdr
;
240 struct pim_upstream
*up
;
244 ip_hdr
= (const ipv_hdr
*)buf
;
246 memset(&sg
, 0, sizeof(sg
));
247 sg
.src
= IPV_SRC(ip_hdr
);
248 sg
.grp
= IPV_DST(ip_hdr
);
250 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
252 pim_sgaddr star
= sg
;
253 star
.src
= PIMADDR_ANY
;
255 up
= pim_upstream_find(pim_ifp
->pim
, &star
);
257 if (up
&& PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
)) {
258 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
259 PIM_UPSTREAM_FLAG_MASK_SRC_LHR
,
262 if (PIM_DEBUG_MROUTE
)
264 "%s: Unable to create upstream information for %pSG",
268 pim_upstream_keep_alive_timer_start(
269 up
, pim_ifp
->pim
->keep_alive_time
);
270 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
271 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
273 if (PIM_DEBUG_MROUTE
)
274 zlog_debug("%s: Creating %s upstream on LHR",
275 __func__
, up
->sg_str
);
278 if (PIM_DEBUG_MROUTE_DETAIL
) {
280 "%s: Unable to find upstream channel WHOLEPKT%pSG",
286 if (!up
->rpf
.source_nexthop
.interface
) {
287 if (PIM_DEBUG_PIM_TRACE
)
288 zlog_debug("%s: up %s RPF is not present", __func__
,
293 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
295 rpg
= pim_ifp
? RP(pim_ifp
->pim
, sg
.grp
) : NULL
;
297 if ((pim_rpf_addr_is_inaddr_any(rpg
)) || (!pim_ifp
) ||
298 (!(PIM_I_am_DR(pim_ifp
)))) {
299 if (PIM_DEBUG_MROUTE
) {
300 zlog_debug("%s: Failed Check send packet", __func__
);
306 * If we've received a register suppress
308 if (!up
->t_rs_timer
) {
309 if (pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
310 if (PIM_DEBUG_PIM_REG
)
312 "%pSG register forward skipped as group is SSM",
317 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
318 if (PIM_DEBUG_PIM_REG
)
320 "%s register forward skipped, not FHR",
325 pim_register_send((uint8_t *)buf
+ sizeof(ipv_hdr
),
326 len
- sizeof(ipv_hdr
),
327 pim_ifp
->primary_address
, rpg
, 0, up
);
332 int pim_mroute_msg_wrongvif(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
334 struct pim_ifchannel
*ch
;
335 struct pim_interface
*pim_ifp
;
338 memset(&sg
, 0, sizeof(sg
));
339 sg
.src
= msg
->msg_im_src
;
340 sg
.grp
= msg
->msg_im_dst
;
343 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
345 RFC 4601 4.8.2. PIM-SSM-Only Routers
347 iif is the incoming interface of the packet.
348 if (iif is in inherited_olist(S,G)) {
349 send Assert(S,G) on iif
354 if (PIM_DEBUG_MROUTE
)
356 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
357 __func__
, &sg
, msg
->msg_im_vif
);
363 if (PIM_DEBUG_MROUTE
)
365 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
366 __func__
, &sg
, ifp
->name
);
370 ch
= pim_ifchannel_find(ifp
, &sg
);
372 pim_sgaddr star_g
= sg
;
373 if (PIM_DEBUG_MROUTE
)
375 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
376 __func__
, &sg
, ifp
->name
);
378 star_g
.src
= PIMADDR_ANY
;
379 ch
= pim_ifchannel_find(ifp
, &star_g
);
381 if (PIM_DEBUG_MROUTE
)
383 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
384 __func__
, &star_g
, ifp
->name
);
390 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
392 Transitions from NoInfo State
394 An (S,G) data packet arrives on interface I, AND
395 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
396 downstream interface that is in our (S,G) outgoing interface
397 list. We optimistically assume that we will be the assert
398 winner for this (S,G), and so we transition to the "I am Assert
399 Winner" state and perform Actions A1 (below), which will
400 initiate the assert negotiation for (S,G).
403 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
404 if (PIM_DEBUG_MROUTE
) {
406 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
407 __func__
, ch
->sg_str
, ifp
->name
);
412 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
413 if (PIM_DEBUG_MROUTE
) {
415 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
416 __func__
, ch
->sg_str
, ifp
->name
);
421 if (assert_action_a1(ch
)) {
422 if (PIM_DEBUG_MROUTE
) {
424 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
425 __func__
, ch
->sg_str
, ifp
->name
);
433 int pim_mroute_msg_wrvifwhole(int fd
, struct interface
*ifp
, const char *buf
,
436 const ipv_hdr
*ip_hdr
= (const ipv_hdr
*)buf
;
437 struct pim_interface
*pim_ifp
;
438 struct pim_instance
*pim
;
439 struct pim_ifchannel
*ch
;
440 struct pim_upstream
*up
;
446 memset(&sg
, 0, sizeof(sg
));
447 sg
.src
= IPV_SRC(ip_hdr
);
448 sg
.grp
= IPV_DST(ip_hdr
);
450 ch
= pim_ifchannel_find(ifp
, &sg
);
452 if (PIM_DEBUG_MROUTE
)
454 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
455 ch
->sg_str
, ifp
->name
);
460 star_g
.src
= PIMADDR_ANY
;
464 * If the incoming interface is the pimreg, then
465 * we know the callback is associated with a pim register
466 * packet and there is nothing to do here as that
467 * normal pim processing will see the packet and allow
468 * us to do the right thing.
470 if (ifp
== pim
->regiface
) {
474 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
476 struct pim_upstream
*parent
;
477 struct pim_nexthop source
;
478 struct pim_rpf
*rpf
= RP(pim_ifp
->pim
, sg
.grp
);
480 /* No RPF or No RPF interface or No mcast on RPF interface */
481 if (!rpf
|| !rpf
->source_nexthop
.interface
||
482 !rpf
->source_nexthop
.interface
->info
)
486 * If we have received a WRVIFWHOLE and are at this
487 * point, we could be receiving the packet on the *,G
488 * tree, let's check and if so we can safely drop
491 parent
= pim_upstream_find(pim_ifp
->pim
, &star_g
);
492 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
495 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
497 memset(&source
, 0, sizeof(source
));
499 * If we are the fhr that means we are getting a callback during
500 * the pimreg period, so I believe we can ignore this packet
502 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
504 * No if channel, but upstream we are at the RP.
506 * This could be a anycast RP too and we may
507 * not have received a register packet from
508 * the source here at all. So gracefully
509 * bow out of doing a nexthop lookup and
510 * setting the SPTBIT to true
512 if (!(pim_addr_is_any(up
->upstream_register
)) &&
513 pim_nexthop_lookup(pim_ifp
->pim
, &source
,
514 up
->upstream_register
, 0)) {
515 pim_register_stop_send(source
.interface
, &sg
,
516 pim_ifp
->primary_address
,
517 up
->upstream_register
);
518 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
521 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
522 if (!up
->channel_oil
->installed
)
523 pim_upstream_mroute_add(up
->channel_oil
,
526 if (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
)) {
527 if (pim_nexthop_lookup(pim_ifp
->pim
, &source
,
528 up
->upstream_register
,
530 pim_register_stop_send(
531 source
.interface
, &sg
,
532 pim_ifp
->primary_address
,
533 up
->upstream_register
);
534 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
537 * At this point pimd is connected to
538 * the source, it has a parent, we are not
539 * the RP and the SPTBIT should be set
540 * since we know *the* S,G is on the SPT.
541 * The first time this happens, let's cause
542 * an immediate join to go out so that
543 * the RP can trim this guy immediately
544 * if necessary, instead of waiting
545 * one join/prune send cycle
547 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
&&
549 up
->rpf
.source_nexthop
.interface
!=
550 up
->parent
->rpf
.source_nexthop
552 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
553 pim_jp_agg_single_upstream_send(
554 &up
->parent
->rpf
, up
->parent
,
558 pim_upstream_keep_alive_timer_start(
559 up
, pim_ifp
->pim
->keep_alive_time
);
560 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
561 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
567 if (pim_if_connected_to_source(ifp
, sg
.src
)) {
568 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
569 PIM_UPSTREAM_FLAG_MASK_FHR
, __func__
,
572 if (PIM_DEBUG_MROUTE
)
574 "%pSG: WRONGVIF%s unable to create upstream on interface",
578 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
579 pim_upstream_keep_alive_timer_start(
580 up
, pim_ifp
->pim
->keep_alive_time
);
581 up
->channel_oil
->cc
.pktcnt
++;
582 pim_register_join(up
);
583 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
584 if (!up
->channel_oil
->installed
)
585 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
587 // Send the packet to the RP
588 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
590 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
591 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
,
593 if (!up
->channel_oil
->installed
)
594 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
601 static int process_igmp_packet(struct pim_instance
*pim
, const char *buf
,
602 size_t buf_size
, ifindex_t ifindex
)
604 struct interface
*ifp
;
605 struct pim_interface
*pim_ifp
;
606 struct in_addr ifaddr
;
607 struct gm_sock
*igmp
;
608 const struct prefix
*connected_src
;
609 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
611 /* We have the IP packet but we do not know which interface this
613 * received on. Find the interface that is on the same subnet as
617 ifp
= if_lookup_by_index(ifindex
, pim
->vrf
->vrf_id
);
619 if (!ifp
|| !ifp
->info
)
622 connected_src
= pim_if_connected_to_source(ifp
, ip_hdr
->ip_src
);
624 if (!connected_src
&& !pim_addr_is_any(ip_hdr
->ip_src
)) {
625 if (PIM_DEBUG_GM_PACKETS
) {
627 "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
628 ifp
->name
, &ip_hdr
->ip_src
);
634 ifaddr
= connected_src
? connected_src
->u
.prefix4
635 : pim_ifp
->primary_address
;
636 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
, ifaddr
);
638 if (PIM_DEBUG_GM_PACKETS
) {
640 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
641 __func__
, pim
->vrf
->name
, ifp
->name
, igmp
,
642 &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
);
645 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
646 else if (PIM_DEBUG_GM_PACKETS
)
648 "No IGMP socket on interface: %s with connected source: %pI4",
655 int pim_mroute_msg(struct pim_instance
*pim
, const char *buf
, size_t buf_size
,
658 struct interface
*ifp
;
659 const ipv_hdr
*ip_hdr
;
662 if (buf_size
< (int)sizeof(ipv_hdr
))
665 ip_hdr
= (const ipv_hdr
*)buf
;
668 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
669 process_igmp_packet(pim
, buf
, buf_size
, ifindex
);
670 } else if (ip_hdr
->ip_p
) {
671 if (PIM_DEBUG_MROUTE_DETAIL
) {
673 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
674 __func__
, ip_hdr
->ip_p
, &ip_hdr
->ip_src
,
675 &ip_hdr
->ip_dst
, (long int)buf_size
);
681 if ((ip_hdr
->ip6_vfc
& 0xf) == 0) {
683 msg
= (const kernmsg
*)buf
;
685 ifp
= pim_if_find_by_vif_index(pim
, msg
->msg_im_vif
);
689 if (PIM_DEBUG_MROUTE
) {
692 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld",
693 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
694 msg
->msg_im_msgtype
, ip_hdr
->ip_p
,
695 pim
->mroute_socket
, &msg
->msg_im_src
,
696 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
700 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld",
701 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
702 msg
->msg_im_msgtype
, ip_hdr
->ip6_nxt
,
703 pim
->mroute_socket
, &msg
->msg_im_src
,
704 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
709 switch (msg
->msg_im_msgtype
) {
711 return pim_mroute_msg_wrongvif(pim
->mroute_socket
, ifp
,
714 return pim_mroute_msg_nocache(pim
->mroute_socket
, ifp
,
717 return pim_mroute_msg_wholepkt(pim
->mroute_socket
, ifp
,
720 case GMMSG_WRVIFWHOLE
:
721 return pim_mroute_msg_wrvifwhole(pim
->mroute_socket
,
722 ifp
, (const char *)msg
,
732 static void mroute_read(struct thread
*t
)
734 struct pim_instance
*pim
;
735 static long long count
;
743 rd
= pim_socket_recvfromto(pim
->mroute_socket
, (uint8_t *)buf
,
744 sizeof(buf
), NULL
, NULL
, NULL
, NULL
,
749 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
753 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
754 __func__
, rd
, pim
->mroute_socket
, errno
,
755 safe_strerror(errno
));
759 pim_mroute_msg(pim
, buf
, rd
, ifindex
);
762 if (count
% router
->packet_process
== 0)
772 static void mroute_read_on(struct pim_instance
*pim
)
774 thread_add_read(router
->master
, mroute_read
, pim
, pim
->mroute_socket
,
778 static void mroute_read_off(struct pim_instance
*pim
)
780 THREAD_OFF(pim
->thread
);
783 int pim_mroute_socket_enable(struct pim_instance
*pim
)
787 frr_with_privs(&pimd_privs
) {
790 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
792 fd
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
795 zlog_warn("Could not create mroute socket: errno=%d: %s",
797 safe_strerror(errno
));
802 struct icmp6_filter filter
[1];
805 /* Unlike IPv4, this socket is not used for MLD, so just drop
806 * everything with an empty ICMP6 filter. Otherwise we get
807 * all kinds of garbage here, possibly even non-multicast
808 * related ICMPv6 traffic (e.g. ping)
810 * (mroute kernel upcall "packets" are injected directly on the
811 * socket, this sockopt -or any other- has no effect on them)
813 ICMP6_FILTER_SETBLOCKALL(filter
);
814 ret
= setsockopt(fd
, SOL_ICMPV6
, ICMP6_FILTER
, filter
,
818 "(VRF %s) failed to set mroute control filter: %m",
822 #ifdef SO_BINDTODEVICE
823 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
824 && setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
825 pim
->vrf
->name
, strlen(pim
->vrf
->name
))) {
826 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
827 safe_strerror(errno
));
835 pim
->mroute_socket
= fd
;
836 if (pim_mroute_set(pim
, 1)) {
838 "Could not enable mroute on socket fd=%d: errno=%d: %s",
839 fd
, errno
, safe_strerror(errno
));
841 pim
->mroute_socket
= -1;
845 pim
->mroute_socket_creation
= pim_time_monotonic_sec();
852 int pim_mroute_socket_disable(struct pim_instance
*pim
)
854 if (pim_mroute_set(pim
, 0)) {
856 "Could not disable mroute on socket fd=%d: errno=%d: %s",
857 pim
->mroute_socket
, errno
, safe_strerror(errno
));
861 if (close(pim
->mroute_socket
)) {
862 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
863 pim
->mroute_socket
, errno
, safe_strerror(errno
));
867 mroute_read_off(pim
);
868 pim
->mroute_socket
= -1;
874 For each network interface (e.g., physical or a virtual tunnel) that
875 would be used for multicast forwarding, a corresponding multicast
876 interface must be added to the kernel.
878 int pim_mroute_add_vif(struct interface
*ifp
, pim_addr ifaddr
,
881 struct pim_interface
*pim_ifp
= ifp
->info
;
885 if (PIM_DEBUG_MROUTE
)
886 zlog_debug("%s: Add Vif %d (%s[%s])", __func__
,
887 pim_ifp
->mroute_vif_index
, ifp
->name
,
888 pim_ifp
->pim
->vrf
->name
);
890 memset(&vc
, 0, sizeof(vc
));
891 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
893 #ifdef VIFF_USE_IFINDEX
894 vc
.vc_lcl_ifindex
= ifp
->ifindex
;
896 if (ifaddr
.s_addr
== INADDR_ANY
) {
898 "%s: unnumbered interfaces are not supported on this platform",
902 memcpy(&vc
.vc_lcl_addr
, &ifaddr
, sizeof(vc
.vc_lcl_addr
));
905 vc
.vc_pifi
= ifp
->ifindex
;
908 vc
.vc_threshold
= PIM_MROUTE_MIN_TTL
;
909 vc
.vc_rate_limit
= 0;
912 #ifdef PIM_DVMRP_TUNNEL
913 if (vc
.vc_flags
& VIFF_TUNNEL
) {
914 memcpy(&vc
.vc_rmt_addr
, &vif_remote_addr
,
915 sizeof(vc
.vc_rmt_addr
));
920 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_VIF
,
921 (void *)&vc
, sizeof(vc
));
924 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
925 __func__
, pim_ifp
->pim
->mroute_socket
, ifp
->ifindex
,
926 &ifaddr
, flags
, errno
, safe_strerror(errno
));
933 int pim_mroute_del_vif(struct interface
*ifp
)
935 struct pim_interface
*pim_ifp
= ifp
->info
;
939 if (PIM_DEBUG_MROUTE
)
940 zlog_debug("%s: Del Vif %d (%s[%s])", __func__
,
941 pim_ifp
->mroute_vif_index
, ifp
->name
,
942 pim_ifp
->pim
->vrf
->name
);
944 memset(&vc
, 0, sizeof(vc
));
945 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
947 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_VIF
,
948 (void *)&vc
, sizeof(vc
));
951 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
952 __FILE__
, __func__
, pim_ifp
->pim
->mroute_socket
,
953 pim_ifp
->mroute_vif_index
, errno
, safe_strerror(errno
));
961 * Prevent creating MFC entry with OIF=IIF.
963 * This is a protection against implementation mistakes.
965 * PIM protocol implicitely ensures loopfree multicast topology.
967 * IGMP must be protected against adding looped MFC entries created
968 * by both source and receiver attached to the same interface. See
970 * We shall allow igmp to create upstream when it is DR for the intf.
971 * Assume RP reachable via non DR.
973 bool pim_mroute_allow_iif_in_oil(struct channel_oil
*c_oil
,
976 #ifdef PIM_ENFORCE_LOOPFREE_MFC
977 struct interface
*ifp_out
;
978 struct pim_interface
*pim_ifp
;
981 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil
->up
->flags
))
984 ifp_out
= pim_if_find_by_vif_index(c_oil
->pim
, oif_index
);
987 pim_ifp
= ifp_out
->info
;
990 if ((c_oil
->oif_flags
[oif_index
] & PIM_OIF_FLAG_PROTO_GM
) &&
991 PIM_I_am_DR(pim_ifp
))
1000 static inline void pim_mroute_copy(struct channel_oil
*out
,
1001 struct channel_oil
*in
)
1005 *oil_origin(out
) = *oil_origin(in
);
1006 *oil_mcastgrp(out
) = *oil_mcastgrp(in
);
1007 *oil_parent(out
) = *oil_parent(in
);
1009 for (i
= 0; i
< MAXVIFS
; ++i
) {
1010 if (*oil_parent(out
) == i
&&
1011 !pim_mroute_allow_iif_in_oil(in
, i
)) {
1012 oil_if_set(out
, i
, 0);
1016 if (in
->oif_flags
[i
] & PIM_OIF_FLAG_MUTE
)
1017 oil_if_set(out
, i
, 0);
1019 oil_if_set(out
, i
, oil_if_has(in
, i
));
1023 /* This function must not be called directly 0
1024 * use pim_upstream_mroute_add or pim_static_mroute_add instead
1026 static int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1028 struct pim_instance
*pim
= c_oil
->pim
;
1029 struct channel_oil tmp_oil
[1] = { };
1032 pim
->mroute_add_last
= pim_time_monotonic_sec();
1033 ++pim
->mroute_add_events
;
1035 /* Copy the oil to a temporary structure to fixup (without need to
1036 * later restore) before sending the mroute add to the dataplane
1038 pim_mroute_copy(tmp_oil
, c_oil
);
1040 /* The linux kernel *expects* the incoming
1041 * vif to be part of the outgoing list
1042 * in the case of a (*,G).
1044 if (pim_addr_is_any(*oil_origin(c_oil
))) {
1045 oil_if_set(tmp_oil
, *oil_parent(c_oil
), 1);
1049 * If we have an unresolved cache entry for the S,G
1050 * it is owned by the pimreg for the incoming IIF
1051 * So set pimreg as the IIF temporarily to cause
1052 * the packets to be forwarded. Then set it
1053 * to the correct IIF afterwords.
1055 if (!c_oil
->installed
&& !pim_addr_is_any(*oil_origin(c_oil
))
1056 && *oil_parent(c_oil
) != 0) {
1057 *oil_parent(tmp_oil
) = 0;
1059 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
1060 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1061 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1063 if (!err
&& !c_oil
->installed
1064 && !pim_addr_is_any(*oil_origin(c_oil
))
1065 && *oil_parent(c_oil
) != 0) {
1066 *oil_parent(tmp_oil
) = *oil_parent(c_oil
);
1067 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1068 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1073 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
1074 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1075 safe_strerror(errno
));
1079 if (PIM_DEBUG_MROUTE
) {
1081 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__
, name
,
1083 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1086 if (!c_oil
->installed
) {
1087 c_oil
->installed
= 1;
1088 c_oil
->mroute_creation
= pim_time_monotonic_sec();
1094 static int pim_upstream_get_mroute_iif(struct channel_oil
*c_oil
,
1097 vifi_t iif
= MAXVIFS
;
1098 struct interface
*ifp
= NULL
;
1099 struct pim_interface
*pim_ifp
;
1100 struct pim_upstream
*up
= c_oil
->up
;
1103 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
)) {
1105 ifp
= up
->parent
->rpf
.source_nexthop
.interface
;
1107 ifp
= up
->rpf
.source_nexthop
.interface
;
1110 pim_ifp
= (struct pim_interface
*)ifp
->info
;
1112 iif
= pim_ifp
->mroute_vif_index
;
1118 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
1123 if (*oil_parent(c_oil
) >= MAXVIFS
) {
1124 /* the c_oil cannot be installed as a mroute yet */
1125 if (PIM_DEBUG_MROUTE
)
1127 "%s(%s) %s mroute not ready to be installed; %s",
1129 pim_channel_oil_dump(c_oil
, buf
,
1132 "uninstall" : "skip");
1133 /* if already installed flush it out as we are going to stop
1134 * updates to it leaving it in a stale state
1136 if (c_oil
->installed
)
1137 pim_mroute_del(c_oil
, name
);
1138 /* return success (skipped) */
1142 return pim_mroute_add(c_oil
, name
);
1145 /* IIF associated with SGrpt entries are re-evaluated when the parent
1146 * (*,G) entries IIF changes
1148 static void pim_upstream_all_sources_iif_update(struct pim_upstream
*up
)
1150 struct listnode
*listnode
;
1151 struct pim_upstream
*child
;
1153 for (ALL_LIST_ELEMENTS_RO(up
->sources
, listnode
,
1155 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
1156 pim_upstream_mroute_iif_update(child
->channel_oil
,
1161 /* In the case of "PIM state machine" added mroutes an upstream entry
1162 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1164 int pim_upstream_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1168 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1170 if (*oil_parent(c_oil
) != iif
) {
1171 *oil_parent(c_oil
) = iif
;
1172 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1174 pim_upstream_all_sources_iif_update(c_oil
->up
);
1176 *oil_parent(c_oil
) = iif
;
1179 return pim_upstream_mroute_update(c_oil
, name
);
1182 /* Look for IIF changes and update the dateplane entry only if the IIF
1185 int pim_upstream_mroute_iif_update(struct channel_oil
*c_oil
, const char *name
)
1190 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1191 if (*oil_parent(c_oil
) == iif
) {
1195 *oil_parent(c_oil
) = iif
;
1197 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1199 pim_upstream_all_sources_iif_update(c_oil
->up
);
1201 if (PIM_DEBUG_MROUTE_DETAIL
)
1202 zlog_debug("%s(%s) %s mroute iif update %d",
1204 pim_channel_oil_dump(c_oil
, buf
,
1206 /* XXX: is this hack needed? */
1207 c_oil
->oil_inherited_rescan
= 1;
1208 return pim_upstream_mroute_update(c_oil
, name
);
1211 int pim_static_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1213 return pim_mroute_add(c_oil
, name
);
1216 void pim_static_mroute_iif_update(struct channel_oil
*c_oil
,
1217 int input_vif_index
,
1220 if (*oil_parent(c_oil
) == input_vif_index
)
1223 *oil_parent(c_oil
) = input_vif_index
;
1224 if (input_vif_index
== MAXVIFS
)
1225 pim_mroute_del(c_oil
, name
);
1227 pim_static_mroute_add(c_oil
, name
);
1230 int pim_mroute_del(struct channel_oil
*c_oil
, const char *name
)
1232 struct pim_instance
*pim
= c_oil
->pim
;
1235 pim
->mroute_del_last
= pim_time_monotonic_sec();
1236 ++pim
->mroute_del_events
;
1238 if (!c_oil
->installed
) {
1239 if (PIM_DEBUG_MROUTE
) {
1242 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1243 __FILE__
, __func__
, *oil_parent(c_oil
),
1244 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1249 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_MFC
,
1250 &c_oil
->oil
, sizeof(c_oil
->oil
));
1252 if (PIM_DEBUG_MROUTE
)
1254 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
1255 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1256 safe_strerror(errno
));
1260 if (PIM_DEBUG_MROUTE
) {
1262 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__
, name
,
1264 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1267 // Reset kernel installed flag
1268 c_oil
->installed
= 0;
1273 void pim_mroute_update_counters(struct channel_oil
*c_oil
)
1275 struct pim_instance
*pim
= c_oil
->pim
;
1276 pim_sioc_sg_req sgreq
;
1278 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
1279 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
1280 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
1282 if (!c_oil
->installed
) {
1283 c_oil
->cc
.lastused
= 100 * pim
->keep_alive_time
;
1284 if (PIM_DEBUG_MROUTE
) {
1287 sg
.src
= *oil_origin(c_oil
);
1288 sg
.grp
= *oil_mcastgrp(c_oil
);
1289 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1296 memset(&sgreq
, 0, sizeof(sgreq
));
1298 pim_zlookup_sg_statistics(c_oil
);
1301 sgreq
.src
= *oil_origin(c_oil
);
1302 sgreq
.grp
= *oil_mcastgrp(c_oil
);
1304 sgreq
.src
= c_oil
->oil
.mf6cc_origin
;
1305 sgreq
.grp
= c_oil
->oil
.mf6cc_mcastgrp
;
1307 if (ioctl(pim
->mroute_socket
, PIM_SIOCGETSGCNT
, &sgreq
)) {
1310 sg
.src
= *oil_origin(c_oil
);
1311 sg
.grp
= *oil_mcastgrp(c_oil
);
1314 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1315 (unsigned long)PIM_SIOCGETSGCNT
, &sg
, errno
,
1316 safe_strerror(errno
));
1320 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
1321 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
1322 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;