3 * Copyright (C) 2008 Everton da Silva Marques
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
28 #include "lib_errors.h"
29 #include "lib/network.h"
33 #include "pim_mroute.h"
37 #include "pim_iface.h"
38 #include "pim_macro.h"
41 #include "pim_register.h"
42 #include "pim_ifchannel.h"
43 #include "pim_zlookup.h"
46 #include "pim_vxlan.h"
49 static void mroute_read_on(struct pim_instance
*pim
);
51 int pim_mroute_set(struct pim_instance
*pim
, int enable
)
55 socklen_t data_len
= sizeof(data
);
58 * We need to create the VRF table for the pim mroute_socket
60 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
) {
61 frr_with_privs (&pimd_privs
) {
63 data
= pim
->vrf
->data
.l
.table_id
;
64 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
,
65 MRT_TABLE
, &data
, data_len
);
68 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s",
69 __FILE__
, __func__
, pim
->mroute_socket
,
70 data
, errno
, safe_strerror(errno
));
76 frr_with_privs (&pimd_privs
) {
77 opt
= enable
? MRT_INIT
: MRT_DONE
;
79 * *BSD *cares* about what value we pass down
83 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, opt
, &data
,
87 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
88 __FILE__
, __func__
, pim
->mroute_socket
,
89 enable
? "MRT_INIT" : "MRT_DONE", data
, errno
,
90 safe_strerror(errno
));
95 #if defined(HAVE_IP_PKTINFO)
97 /* Linux and Solaris IP_PKTINFO */
99 if (setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, IP_PKTINFO
,
102 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
103 pim
->mroute_socket
, errno
,
104 safe_strerror(errno
));
111 /* Linux and Solaris IPV6_PKTINFO */
113 if (setsockopt(pim
->mroute_socket
, PIM_IPPROTO
,
114 IPV6_RECVPKTINFO
, &data
, data_len
)) {
116 "Could not set IPV6_RECVPKTINFO on socket fd=%d: errno=%d: %s",
117 pim
->mroute_socket
, errno
,
118 safe_strerror(errno
));
122 setsockopt_so_recvbuf(pim
->mroute_socket
, 1024 * 1024 * 8);
124 if (set_nonblocking(pim
->mroute_socket
) < 0) {
126 "Could not set non blocking on socket fd=%d: errno=%d: %s",
127 pim
->mroute_socket
, errno
, safe_strerror(errno
));
133 int upcalls
= GMMSG_WRVIFWHOLE
;
136 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, opt
, &upcalls
,
140 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
141 errno
, safe_strerror(errno
));
146 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
153 static const char *const gmmsgtype2str
[GMMSG_WRVIFWHOLE
+ 1] = {
154 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
157 int pim_mroute_msg_nocache(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
159 struct pim_interface
*pim_ifp
= ifp
->info
;
160 struct pim_upstream
*up
;
164 rpg
= pim_ifp
? RP(pim_ifp
->pim
, msg
->msg_im_dst
) : NULL
;
166 * If the incoming interface is unknown OR
167 * the Interface type is SSM we don't need to
170 if (!rpg
|| pim_rpf_addr_is_inaddr_any(rpg
)) {
171 if (PIM_DEBUG_MROUTE_DETAIL
)
173 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
180 * If we've received a multicast packet that isn't connected to
183 if (!pim_if_connected_to_source(ifp
, msg
->msg_im_src
)) {
184 if (PIM_DEBUG_MROUTE_DETAIL
)
186 "%s: Received incoming packet that doesn't originate on our seg",
191 memset(&sg
, 0, sizeof(sg
));
192 sg
.src
= msg
->msg_im_src
;
193 sg
.grp
= msg
->msg_im_dst
;
195 if (!(PIM_I_am_DR(pim_ifp
))) {
196 if (PIM_DEBUG_MROUTE_DETAIL
)
198 "%s: Interface is not the DR blackholing incoming traffic for %pSG",
202 * We are not the DR, but we are still receiving packets
203 * Let's blackhole those packets for the moment
204 * As that they will be coming up to the cpu
205 * and causing us to consider them.
207 * This *will* create a dangling channel_oil
208 * that I see no way to get rid of. Just noting
209 * this for future reference.
211 up
= pim_upstream_find_or_add(
212 &sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
, __func__
);
213 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
218 up
= pim_upstream_find_or_add(&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
,
222 * I moved this debug till after the actual add because
223 * I want to take advantage of the up->sg_str being filled in.
225 if (PIM_DEBUG_MROUTE
) {
226 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
227 __func__
, up
->sg_str
);
230 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
231 pim_upstream_keep_alive_timer_start(up
, pim_ifp
->pim
->keep_alive_time
);
233 up
->channel_oil
->cc
.pktcnt
++;
234 // resolve mfcc_parent prior to mroute_add in channel_add_oif
235 if (up
->rpf
.source_nexthop
.interface
&&
236 *oil_parent(up
->channel_oil
) >= MAXVIFS
) {
237 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
239 pim_register_join(up
);
240 /* if we have receiver, inherit from parent */
241 pim_upstream_inherited_olist_decide(pim_ifp
->pim
, up
);
246 int pim_mroute_msg_wholepkt(int fd
, struct interface
*ifp
, const char *buf
,
249 struct pim_interface
*pim_ifp
;
252 const ipv_hdr
*ip_hdr
;
253 struct pim_upstream
*up
;
257 ip_hdr
= (const ipv_hdr
*)buf
;
259 memset(&sg
, 0, sizeof(sg
));
260 sg
.src
= IPV_SRC(ip_hdr
);
261 sg
.grp
= IPV_DST(ip_hdr
);
263 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
265 pim_sgaddr star
= sg
;
266 star
.src
= PIMADDR_ANY
;
268 up
= pim_upstream_find(pim_ifp
->pim
, &star
);
270 if (up
&& PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
)) {
271 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
272 PIM_UPSTREAM_FLAG_MASK_SRC_LHR
,
275 if (PIM_DEBUG_MROUTE
)
277 "%s: Unable to create upstream information for %pSG",
281 pim_upstream_keep_alive_timer_start(
282 up
, pim_ifp
->pim
->keep_alive_time
);
283 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
284 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
286 if (PIM_DEBUG_MROUTE
)
287 zlog_debug("%s: Creating %s upstream on LHR",
288 __func__
, up
->sg_str
);
291 if (PIM_DEBUG_MROUTE_DETAIL
) {
293 "%s: Unable to find upstream channel WHOLEPKT%pSG",
299 if (!up
->rpf
.source_nexthop
.interface
) {
300 if (PIM_DEBUG_PIM_TRACE
)
301 zlog_debug("%s: up %s RPF is not present", __func__
,
306 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
308 rpg
= pim_ifp
? RP(pim_ifp
->pim
, sg
.grp
) : NULL
;
310 if ((pim_rpf_addr_is_inaddr_any(rpg
)) || (!pim_ifp
) ||
311 (!(PIM_I_am_DR(pim_ifp
)))) {
312 if (PIM_DEBUG_MROUTE
) {
313 zlog_debug("%s: Failed Check send packet", __func__
);
319 * If we've received a register suppress
321 if (!up
->t_rs_timer
) {
322 if (pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
323 if (PIM_DEBUG_PIM_REG
)
325 "%pSG register forward skipped as group is SSM",
330 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
331 if (PIM_DEBUG_PIM_REG
)
333 "%s register forward skipped, not FHR",
338 pim_register_send((uint8_t *)buf
+ sizeof(ipv_hdr
),
339 len
- sizeof(ipv_hdr
),
340 pim_ifp
->primary_address
, rpg
, 0, up
);
345 int pim_mroute_msg_wrongvif(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
347 struct pim_ifchannel
*ch
;
348 struct pim_interface
*pim_ifp
;
351 memset(&sg
, 0, sizeof(sg
));
352 sg
.src
= msg
->msg_im_src
;
353 sg
.grp
= msg
->msg_im_dst
;
356 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
358 RFC 4601 4.8.2. PIM-SSM-Only Routers
360 iif is the incoming interface of the packet.
361 if (iif is in inherited_olist(S,G)) {
362 send Assert(S,G) on iif
367 if (PIM_DEBUG_MROUTE
)
369 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
370 __func__
, &sg
, msg
->msg_im_vif
);
376 if (PIM_DEBUG_MROUTE
)
378 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
379 __func__
, &sg
, ifp
->name
);
383 ch
= pim_ifchannel_find(ifp
, &sg
);
385 pim_sgaddr star_g
= sg
;
386 if (PIM_DEBUG_MROUTE
)
388 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
389 __func__
, &sg
, ifp
->name
);
391 star_g
.src
= PIMADDR_ANY
;
392 ch
= pim_ifchannel_find(ifp
, &star_g
);
394 if (PIM_DEBUG_MROUTE
)
396 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
397 __func__
, &star_g
, ifp
->name
);
403 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
405 Transitions from NoInfo State
407 An (S,G) data packet arrives on interface I, AND
408 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
409 downstream interface that is in our (S,G) outgoing interface
410 list. We optimistically assume that we will be the assert
411 winner for this (S,G), and so we transition to the "I am Assert
412 Winner" state and perform Actions A1 (below), which will
413 initiate the assert negotiation for (S,G).
416 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
417 if (PIM_DEBUG_MROUTE
) {
419 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
420 __func__
, ch
->sg_str
, ifp
->name
);
425 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
426 if (PIM_DEBUG_MROUTE
) {
428 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
429 __func__
, ch
->sg_str
, ifp
->name
);
434 if (assert_action_a1(ch
)) {
435 if (PIM_DEBUG_MROUTE
) {
437 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
438 __func__
, ch
->sg_str
, ifp
->name
);
446 int pim_mroute_msg_wrvifwhole(int fd
, struct interface
*ifp
, const char *buf
,
449 const ipv_hdr
*ip_hdr
= (const ipv_hdr
*)buf
;
450 struct pim_interface
*pim_ifp
;
451 struct pim_instance
*pim
;
452 struct pim_ifchannel
*ch
;
453 struct pim_upstream
*up
;
459 memset(&sg
, 0, sizeof(sg
));
460 sg
.src
= IPV_SRC(ip_hdr
);
461 sg
.grp
= IPV_DST(ip_hdr
);
463 ch
= pim_ifchannel_find(ifp
, &sg
);
465 if (PIM_DEBUG_MROUTE
)
467 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
468 ch
->sg_str
, ifp
->name
);
473 star_g
.src
= PIMADDR_ANY
;
477 * If the incoming interface is the pimreg, then
478 * we know the callback is associated with a pim register
479 * packet and there is nothing to do here as that
480 * normal pim processing will see the packet and allow
481 * us to do the right thing.
483 if (ifp
== pim
->regiface
) {
487 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
489 struct pim_upstream
*parent
;
490 struct pim_nexthop source
;
491 struct pim_rpf
*rpf
= RP(pim_ifp
->pim
, sg
.grp
);
493 /* No RPF or No RPF interface or No mcast on RPF interface */
494 if (!rpf
|| !rpf
->source_nexthop
.interface
||
495 !rpf
->source_nexthop
.interface
->info
)
499 * If we have received a WRVIFWHOLE and are at this
500 * point, we could be receiving the packet on the *,G
501 * tree, let's check and if so we can safely drop
504 parent
= pim_upstream_find(pim_ifp
->pim
, &star_g
);
505 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
508 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
510 memset(&source
, 0, sizeof(source
));
512 * If we are the fhr that means we are getting a callback during
513 * the pimreg period, so I believe we can ignore this packet
515 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
517 * No if channel, but upstream we are at the RP.
519 * This could be a anycast RP too and we may
520 * not have received a register packet from
521 * the source here at all. So gracefully
522 * bow out of doing a nexthop lookup and
523 * setting the SPTBIT to true
525 if (!(pim_addr_is_any(up
->upstream_register
)) &&
526 pim_nexthop_lookup(pim_ifp
->pim
, &source
,
527 up
->upstream_register
, 0)) {
528 pim_register_stop_send(source
.interface
, &sg
,
529 pim_ifp
->primary_address
,
530 up
->upstream_register
);
531 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
534 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
535 if (!up
->channel_oil
->installed
)
536 pim_upstream_mroute_add(up
->channel_oil
,
539 if (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
)) {
540 if (pim_nexthop_lookup(pim_ifp
->pim
, &source
,
541 up
->upstream_register
,
543 pim_register_stop_send(
544 source
.interface
, &sg
,
545 pim_ifp
->primary_address
,
546 up
->upstream_register
);
547 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
550 * At this point pimd is connected to
551 * the source, it has a parent, we are not
552 * the RP and the SPTBIT should be set
553 * since we know *the* S,G is on the SPT.
554 * The first time this happens, let's cause
555 * an immediate join to go out so that
556 * the RP can trim this guy immediately
557 * if necessary, instead of waiting
558 * one join/prune send cycle
560 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
&&
562 up
->rpf
.source_nexthop
.interface
!=
563 up
->parent
->rpf
.source_nexthop
565 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
566 pim_jp_agg_single_upstream_send(
567 &up
->parent
->rpf
, up
->parent
,
571 pim_upstream_keep_alive_timer_start(
572 up
, pim_ifp
->pim
->keep_alive_time
);
573 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
574 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
580 if (pim_if_connected_to_source(ifp
, sg
.src
)) {
581 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
582 PIM_UPSTREAM_FLAG_MASK_FHR
, __func__
,
585 if (PIM_DEBUG_MROUTE
)
587 "%pSG: WRONGVIF%s unable to create upstream on interface",
591 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
592 pim_upstream_keep_alive_timer_start(
593 up
, pim_ifp
->pim
->keep_alive_time
);
594 up
->channel_oil
->cc
.pktcnt
++;
595 pim_register_join(up
);
596 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
597 if (!up
->channel_oil
->installed
)
598 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
600 // Send the packet to the RP
601 pim_mroute_msg_wholepkt(fd
, ifp
, buf
, len
);
603 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
604 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
,
606 if (!up
->channel_oil
->installed
)
607 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
614 static int process_igmp_packet(struct pim_instance
*pim
, const char *buf
,
615 size_t buf_size
, ifindex_t ifindex
)
617 struct interface
*ifp
;
618 struct pim_interface
*pim_ifp
;
619 struct in_addr ifaddr
;
620 struct gm_sock
*igmp
;
621 const struct prefix
*connected_src
;
622 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
624 /* We have the IP packet but we do not know which interface this
626 * received on. Find the interface that is on the same subnet as
630 ifp
= if_lookup_by_index(ifindex
, pim
->vrf
->vrf_id
);
632 if (!ifp
|| !ifp
->info
)
635 connected_src
= pim_if_connected_to_source(ifp
, ip_hdr
->ip_src
);
637 if (!connected_src
) {
638 if (PIM_DEBUG_GM_PACKETS
) {
640 "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
641 ifp
->name
, &ip_hdr
->ip_src
);
647 ifaddr
= connected_src
->u
.prefix4
;
648 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
, ifaddr
);
650 if (PIM_DEBUG_GM_PACKETS
) {
652 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
653 __func__
, pim
->vrf
->name
, ifp
->name
, igmp
,
654 &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
);
657 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
658 else if (PIM_DEBUG_GM_PACKETS
) {
660 "No IGMP socket on interface: %s with connected source: %pFX",
661 ifp
->name
, connected_src
);
667 int pim_mroute_msg(struct pim_instance
*pim
, const char *buf
, size_t buf_size
,
670 struct interface
*ifp
;
671 const ipv_hdr
*ip_hdr
;
674 if (buf_size
< (int)sizeof(ipv_hdr
))
677 ip_hdr
= (const ipv_hdr
*)buf
;
680 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
681 process_igmp_packet(pim
, buf
, buf_size
, ifindex
);
682 } else if (ip_hdr
->ip_p
) {
683 if (PIM_DEBUG_MROUTE_DETAIL
) {
685 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
686 __func__
, ip_hdr
->ip_p
, &ip_hdr
->ip_src
,
687 &ip_hdr
->ip_dst
, (long int)buf_size
);
693 if ((ip_hdr
->ip6_vfc
& 0xf) == 0) {
695 msg
= (const kernmsg
*)buf
;
697 ifp
= pim_if_find_by_vif_index(pim
, msg
->msg_im_vif
);
701 if (PIM_DEBUG_MROUTE
) {
704 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld",
705 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
706 msg
->msg_im_msgtype
, ip_hdr
->ip_p
,
707 pim
->mroute_socket
, &msg
->msg_im_src
,
708 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
712 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld",
713 __func__
, gmmsgtype2str
[msg
->msg_im_msgtype
],
714 msg
->msg_im_msgtype
, ip_hdr
->ip6_nxt
,
715 pim
->mroute_socket
, &msg
->msg_im_src
,
716 &msg
->msg_im_dst
, ifp
->name
, msg
->msg_im_vif
,
721 switch (msg
->msg_im_msgtype
) {
723 return pim_mroute_msg_wrongvif(pim
->mroute_socket
, ifp
,
726 return pim_mroute_msg_nocache(pim
->mroute_socket
, ifp
,
729 return pim_mroute_msg_wholepkt(pim
->mroute_socket
, ifp
,
732 case GMMSG_WRVIFWHOLE
:
733 return pim_mroute_msg_wrvifwhole(pim
->mroute_socket
,
734 ifp
, (const char *)msg
,
744 static void mroute_read(struct thread
*t
)
746 struct pim_instance
*pim
;
747 static long long count
;
755 rd
= pim_socket_recvfromto(pim
->mroute_socket
, (uint8_t *)buf
,
756 sizeof(buf
), NULL
, NULL
, NULL
, NULL
,
761 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
765 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
766 __func__
, rd
, pim
->mroute_socket
, errno
,
767 safe_strerror(errno
));
771 pim_mroute_msg(pim
, buf
, rd
, ifindex
);
774 if (count
% router
->packet_process
== 0)
784 static void mroute_read_on(struct pim_instance
*pim
)
786 thread_add_read(router
->master
, mroute_read
, pim
, pim
->mroute_socket
,
790 static void mroute_read_off(struct pim_instance
*pim
)
792 THREAD_OFF(pim
->thread
);
795 int pim_mroute_socket_enable(struct pim_instance
*pim
)
799 frr_with_privs(&pimd_privs
) {
802 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
804 fd
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
807 zlog_warn("Could not create mroute socket: errno=%d: %s",
809 safe_strerror(errno
));
814 struct icmp6_filter filter
[1];
817 /* Unlike IPv4, this socket is not used for MLD, so just drop
818 * everything with an empty ICMP6 filter. Otherwise we get
819 * all kinds of garbage here, possibly even non-multicast
820 * related ICMPv6 traffic (e.g. ping)
822 * (mroute kernel upcall "packets" are injected directly on the
823 * socket, this sockopt -or any other- has no effect on them)
825 ICMP6_FILTER_SETBLOCKALL(filter
);
826 ret
= setsockopt(fd
, SOL_ICMPV6
, ICMP6_FILTER
, filter
,
830 "(VRF %s) failed to set mroute control filter: %m",
834 #ifdef SO_BINDTODEVICE
835 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
836 && setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
837 pim
->vrf
->name
, strlen(pim
->vrf
->name
))) {
838 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
839 safe_strerror(errno
));
847 pim
->mroute_socket
= fd
;
848 if (pim_mroute_set(pim
, 1)) {
850 "Could not enable mroute on socket fd=%d: errno=%d: %s",
851 fd
, errno
, safe_strerror(errno
));
853 pim
->mroute_socket
= -1;
857 pim
->mroute_socket_creation
= pim_time_monotonic_sec();
864 int pim_mroute_socket_disable(struct pim_instance
*pim
)
866 if (pim_mroute_set(pim
, 0)) {
868 "Could not disable mroute on socket fd=%d: errno=%d: %s",
869 pim
->mroute_socket
, errno
, safe_strerror(errno
));
873 if (close(pim
->mroute_socket
)) {
874 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
875 pim
->mroute_socket
, errno
, safe_strerror(errno
));
879 mroute_read_off(pim
);
880 pim
->mroute_socket
= -1;
886 For each network interface (e.g., physical or a virtual tunnel) that
887 would be used for multicast forwarding, a corresponding multicast
888 interface must be added to the kernel.
890 int pim_mroute_add_vif(struct interface
*ifp
, pim_addr ifaddr
,
893 struct pim_interface
*pim_ifp
= ifp
->info
;
897 if (PIM_DEBUG_MROUTE
)
898 zlog_debug("%s: Add Vif %d (%s[%s])", __func__
,
899 pim_ifp
->mroute_vif_index
, ifp
->name
,
900 pim_ifp
->pim
->vrf
->name
);
902 memset(&vc
, 0, sizeof(vc
));
903 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
905 #ifdef VIFF_USE_IFINDEX
906 vc
.vc_lcl_ifindex
= ifp
->ifindex
;
908 if (ifaddr
.s_addr
== INADDR_ANY
) {
910 "%s: unnumbered interfaces are not supported on this platform",
914 memcpy(&vc
.vc_lcl_addr
, &ifaddr
, sizeof(vc
.vc_lcl_addr
));
917 vc
.vc_pifi
= ifp
->ifindex
;
920 vc
.vc_threshold
= PIM_MROUTE_MIN_TTL
;
921 vc
.vc_rate_limit
= 0;
924 #ifdef PIM_DVMRP_TUNNEL
925 if (vc
.vc_flags
& VIFF_TUNNEL
) {
926 memcpy(&vc
.vc_rmt_addr
, &vif_remote_addr
,
927 sizeof(vc
.vc_rmt_addr
));
932 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_VIF
,
933 (void *)&vc
, sizeof(vc
));
936 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
937 __func__
, pim_ifp
->pim
->mroute_socket
, ifp
->ifindex
,
938 &ifaddr
, flags
, errno
, safe_strerror(errno
));
945 int pim_mroute_del_vif(struct interface
*ifp
)
947 struct pim_interface
*pim_ifp
= ifp
->info
;
951 if (PIM_DEBUG_MROUTE
)
952 zlog_debug("%s: Del Vif %d (%s[%s])", __func__
,
953 pim_ifp
->mroute_vif_index
, ifp
->name
,
954 pim_ifp
->pim
->vrf
->name
);
956 memset(&vc
, 0, sizeof(vc
));
957 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
959 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_VIF
,
960 (void *)&vc
, sizeof(vc
));
963 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
964 __FILE__
, __func__
, pim_ifp
->pim
->mroute_socket
,
965 pim_ifp
->mroute_vif_index
, errno
, safe_strerror(errno
));
973 * Prevent creating MFC entry with OIF=IIF.
975 * This is a protection against implementation mistakes.
977 * PIM protocol implicitely ensures loopfree multicast topology.
979 * IGMP must be protected against adding looped MFC entries created
980 * by both source and receiver attached to the same interface. See
982 * We shall allow igmp to create upstream when it is DR for the intf.
983 * Assume RP reachable via non DR.
985 bool pim_mroute_allow_iif_in_oil(struct channel_oil
*c_oil
,
988 #ifdef PIM_ENFORCE_LOOPFREE_MFC
989 struct interface
*ifp_out
;
990 struct pim_interface
*pim_ifp
;
993 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil
->up
->flags
))
996 ifp_out
= pim_if_find_by_vif_index(c_oil
->pim
, oif_index
);
999 pim_ifp
= ifp_out
->info
;
1002 if ((c_oil
->oif_flags
[oif_index
] & PIM_OIF_FLAG_PROTO_GM
) &&
1003 PIM_I_am_DR(pim_ifp
))
1012 static inline void pim_mroute_copy(struct channel_oil
*out
,
1013 struct channel_oil
*in
)
1017 *oil_origin(out
) = *oil_origin(in
);
1018 *oil_mcastgrp(out
) = *oil_mcastgrp(in
);
1019 *oil_parent(out
) = *oil_parent(in
);
1021 for (i
= 0; i
< MAXVIFS
; ++i
) {
1022 if (*oil_parent(out
) == i
&&
1023 !pim_mroute_allow_iif_in_oil(in
, i
)) {
1024 oil_if_set(out
, i
, 0);
1028 if (in
->oif_flags
[i
] & PIM_OIF_FLAG_MUTE
)
1029 oil_if_set(out
, i
, 0);
1031 oil_if_set(out
, i
, oil_if_has(in
, i
));
1035 /* This function must not be called directly 0
1036 * use pim_upstream_mroute_add or pim_static_mroute_add instead
1038 static int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1040 struct pim_instance
*pim
= c_oil
->pim
;
1041 struct channel_oil tmp_oil
[1] = { };
1044 pim
->mroute_add_last
= pim_time_monotonic_sec();
1045 ++pim
->mroute_add_events
;
1047 /* Copy the oil to a temporary structure to fixup (without need to
1048 * later restore) before sending the mroute add to the dataplane
1050 pim_mroute_copy(tmp_oil
, c_oil
);
1052 /* The linux kernel *expects* the incoming
1053 * vif to be part of the outgoing list
1054 * in the case of a (*,G).
1056 if (pim_addr_is_any(*oil_origin(c_oil
))) {
1057 oil_if_set(tmp_oil
, *oil_parent(c_oil
), 1);
1061 * If we have an unresolved cache entry for the S,G
1062 * it is owned by the pimreg for the incoming IIF
1063 * So set pimreg as the IIF temporarily to cause
1064 * the packets to be forwarded. Then set it
1065 * to the correct IIF afterwords.
1067 if (!c_oil
->installed
&& !pim_addr_is_any(*oil_origin(c_oil
))
1068 && *oil_parent(c_oil
) != 0) {
1069 *oil_parent(tmp_oil
) = 0;
1071 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
1072 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1073 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1075 if (!err
&& !c_oil
->installed
1076 && !pim_addr_is_any(*oil_origin(c_oil
))
1077 && *oil_parent(c_oil
) != 0) {
1078 *oil_parent(tmp_oil
) = *oil_parent(c_oil
);
1079 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
1080 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1085 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
1086 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1087 safe_strerror(errno
));
1091 if (PIM_DEBUG_MROUTE
) {
1093 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__
, name
,
1095 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1098 if (!c_oil
->installed
) {
1099 c_oil
->installed
= 1;
1100 c_oil
->mroute_creation
= pim_time_monotonic_sec();
1106 static int pim_upstream_get_mroute_iif(struct channel_oil
*c_oil
,
1109 vifi_t iif
= MAXVIFS
;
1110 struct interface
*ifp
= NULL
;
1111 struct pim_interface
*pim_ifp
;
1112 struct pim_upstream
*up
= c_oil
->up
;
1115 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
)) {
1117 ifp
= up
->parent
->rpf
.source_nexthop
.interface
;
1119 ifp
= up
->rpf
.source_nexthop
.interface
;
1122 pim_ifp
= (struct pim_interface
*)ifp
->info
;
1124 iif
= pim_ifp
->mroute_vif_index
;
1130 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
1135 if (*oil_parent(c_oil
) >= MAXVIFS
) {
1136 /* the c_oil cannot be installed as a mroute yet */
1137 if (PIM_DEBUG_MROUTE
)
1139 "%s(%s) %s mroute not ready to be installed; %s",
1141 pim_channel_oil_dump(c_oil
, buf
,
1144 "uninstall" : "skip");
1145 /* if already installed flush it out as we are going to stop
1146 * updates to it leaving it in a stale state
1148 if (c_oil
->installed
)
1149 pim_mroute_del(c_oil
, name
);
1150 /* return success (skipped) */
1154 return pim_mroute_add(c_oil
, name
);
1157 /* IIF associated with SGrpt entries are re-evaluated when the parent
1158 * (*,G) entries IIF changes
1160 static void pim_upstream_all_sources_iif_update(struct pim_upstream
*up
)
1162 struct listnode
*listnode
;
1163 struct pim_upstream
*child
;
1165 for (ALL_LIST_ELEMENTS_RO(up
->sources
, listnode
,
1167 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
1168 pim_upstream_mroute_iif_update(child
->channel_oil
,
1173 /* In the case of "PIM state machine" added mroutes an upstream entry
1174 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1176 int pim_upstream_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1180 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1182 if (*oil_parent(c_oil
) != iif
) {
1183 *oil_parent(c_oil
) = iif
;
1184 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1186 pim_upstream_all_sources_iif_update(c_oil
->up
);
1188 *oil_parent(c_oil
) = iif
;
1191 return pim_upstream_mroute_update(c_oil
, name
);
1194 /* Look for IIF changes and update the dateplane entry only if the IIF
1197 int pim_upstream_mroute_iif_update(struct channel_oil
*c_oil
, const char *name
)
1202 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1203 if (*oil_parent(c_oil
) == iif
) {
1207 *oil_parent(c_oil
) = iif
;
1209 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1211 pim_upstream_all_sources_iif_update(c_oil
->up
);
1213 if (PIM_DEBUG_MROUTE_DETAIL
)
1214 zlog_debug("%s(%s) %s mroute iif update %d",
1216 pim_channel_oil_dump(c_oil
, buf
,
1218 /* XXX: is this hack needed? */
1219 c_oil
->oil_inherited_rescan
= 1;
1220 return pim_upstream_mroute_update(c_oil
, name
);
1223 int pim_static_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1225 return pim_mroute_add(c_oil
, name
);
1228 void pim_static_mroute_iif_update(struct channel_oil
*c_oil
,
1229 int input_vif_index
,
1232 if (*oil_parent(c_oil
) == input_vif_index
)
1235 *oil_parent(c_oil
) = input_vif_index
;
1236 if (input_vif_index
== MAXVIFS
)
1237 pim_mroute_del(c_oil
, name
);
1239 pim_static_mroute_add(c_oil
, name
);
1242 int pim_mroute_del(struct channel_oil
*c_oil
, const char *name
)
1244 struct pim_instance
*pim
= c_oil
->pim
;
1247 pim
->mroute_del_last
= pim_time_monotonic_sec();
1248 ++pim
->mroute_del_events
;
1250 if (!c_oil
->installed
) {
1251 if (PIM_DEBUG_MROUTE
) {
1254 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1255 __FILE__
, __func__
, *oil_parent(c_oil
),
1256 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1261 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_MFC
,
1262 &c_oil
->oil
, sizeof(c_oil
->oil
));
1264 if (PIM_DEBUG_MROUTE
)
1266 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
1267 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1268 safe_strerror(errno
));
1272 if (PIM_DEBUG_MROUTE
) {
1274 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__
, name
,
1276 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1279 // Reset kernel installed flag
1280 c_oil
->installed
= 0;
1285 void pim_mroute_update_counters(struct channel_oil
*c_oil
)
1287 struct pim_instance
*pim
= c_oil
->pim
;
1288 pim_sioc_sg_req sgreq
;
1290 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
1291 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
1292 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
1294 if (!c_oil
->installed
) {
1295 c_oil
->cc
.lastused
= 100 * pim
->keep_alive_time
;
1296 if (PIM_DEBUG_MROUTE
) {
1299 sg
.src
= *oil_origin(c_oil
);
1300 sg
.grp
= *oil_mcastgrp(c_oil
);
1301 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1308 memset(&sgreq
, 0, sizeof(sgreq
));
1310 pim_zlookup_sg_statistics(c_oil
);
1313 sgreq
.src
= *oil_origin(c_oil
);
1314 sgreq
.grp
= *oil_mcastgrp(c_oil
);
1316 sgreq
.src
= c_oil
->oil
.mf6cc_origin
;
1317 sgreq
.grp
= c_oil
->oil
.mf6cc_mcastgrp
;
1319 if (ioctl(pim
->mroute_socket
, PIM_SIOCGETSGCNT
, &sgreq
)) {
1322 sg
.src
= *oil_origin(c_oil
);
1323 sg
.grp
= *oil_mcastgrp(c_oil
);
1326 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1327 (unsigned long)PIM_SIOCGETSGCNT
, &sg
, errno
,
1328 safe_strerror(errno
));
1332 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
1333 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
1334 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;