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"
32 #include "pim_mroute.h"
36 #include "pim_iface.h"
37 #include "pim_macro.h"
40 #include "pim_register.h"
41 #include "pim_ifchannel.h"
42 #include "pim_zlookup.h"
45 #include "pim_vxlan.h"
47 static void mroute_read_on(struct pim_instance
*pim
);
49 static int pim_mroute_set(struct pim_instance
*pim
, int enable
)
53 socklen_t data_len
= sizeof(data
);
57 * We need to create the VRF table for the pim mroute_socket
59 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
) {
60 frr_with_privs(&pimd_privs
) {
62 data
= pim
->vrf
->data
.l
.table_id
;
63 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
,
68 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
69 __FILE__
, __func__
, pim
->mroute_socket
,
70 data
, errno
, safe_strerror(errno
));
77 frr_with_privs(&pimd_privs
) {
78 opt
= enable
? MRT_INIT
: MRT_DONE
;
80 * *BSD *cares* about what value we pass down
84 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
,
85 opt
, &data
, data_len
);
88 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
89 __FILE__
, __func__
, pim
->mroute_socket
,
90 enable
? "MRT_INIT" : "MRT_DONE", data
, errno
,
91 safe_strerror(errno
));
96 #if defined(HAVE_IP_PKTINFO)
98 /* Linux and Solaris IP_PKTINFO */
100 if (setsockopt(pim
->mroute_socket
, IPPROTO_IP
, IP_PKTINFO
,
103 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
104 pim
->mroute_socket
, errno
,
105 safe_strerror(errno
));
110 setsockopt_so_recvbuf(pim
->mroute_socket
, 1024 * 1024 * 8);
112 flags
= fcntl(pim
->mroute_socket
, F_GETFL
, 0);
114 zlog_warn("Could not get flags on socket fd:%d %d %s",
115 pim
->mroute_socket
, errno
, safe_strerror(errno
));
116 close(pim
->mroute_socket
);
119 if (fcntl(pim
->mroute_socket
, F_SETFL
, flags
| O_NONBLOCK
)) {
120 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
121 pim
->mroute_socket
, errno
, safe_strerror(errno
));
122 close(pim
->mroute_socket
);
128 int upcalls
= IGMPMSG_WRVIFWHOLE
;
131 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
, opt
, &upcalls
,
135 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
136 errno
, safe_strerror(errno
));
141 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
149 static const char *const igmpmsgtype2str
[IGMPMSG_WRVIFWHOLE
+ 1] = {
150 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
152 static int pim_mroute_msg_nocache(int fd
, struct interface
*ifp
,
153 const struct igmpmsg
*msg
)
155 struct pim_interface
*pim_ifp
= ifp
->info
;
156 struct pim_upstream
*up
;
160 rpg
= pim_ifp
? RP(pim_ifp
->pim
, msg
->im_dst
) : NULL
;
162 * If the incoming interface is unknown OR
163 * the Interface type is SSM we don't need to
166 if (!rpg
|| pim_rpf_addr_is_inaddr_none(rpg
)) {
167 if (PIM_DEBUG_MROUTE_DETAIL
)
169 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
176 * If we've received a multicast packet that isn't connected to
179 if (!pim_if_connected_to_source(ifp
, msg
->im_src
)) {
180 if (PIM_DEBUG_MROUTE_DETAIL
)
182 "%s: Received incoming packet that doesn't originate on our seg",
187 memset(&sg
, 0, sizeof(sg
));
188 sg
.src
= msg
->im_src
;
189 sg
.grp
= msg
->im_dst
;
191 if (!(PIM_I_am_DR(pim_ifp
))) {
192 if (PIM_DEBUG_MROUTE_DETAIL
)
193 zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %pSG",
197 * We are not the DR, but we are still receiving packets
198 * Let's blackhole those packets for the moment
199 * As that they will be coming up to the cpu
200 * and causing us to consider them.
202 * This *will* create a dangling channel_oil
203 * that I see no way to get rid of. Just noting
204 * this for future reference.
206 up
= pim_upstream_find_or_add(
207 &sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
, __func__
);
208 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
213 up
= pim_upstream_find_or_add(&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
,
217 * I moved this debug till after the actual add because
218 * I want to take advantage of the up->sg_str being filled in.
220 if (PIM_DEBUG_MROUTE
) {
221 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
222 __func__
, up
->sg_str
);
225 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
226 pim_upstream_keep_alive_timer_start(up
, pim_ifp
->pim
->keep_alive_time
);
228 up
->channel_oil
->cc
.pktcnt
++;
229 // resolve mfcc_parent prior to mroute_add in channel_add_oif
230 if (up
->rpf
.source_nexthop
.interface
&&
231 *oil_parent(up
->channel_oil
) >= MAXVIFS
) {
232 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
234 pim_register_join(up
);
235 /* if we have receiver, inherit from parent */
236 pim_upstream_inherited_olist_decide(pim_ifp
->pim
, up
);
241 static int pim_mroute_msg_wholepkt(int fd
, struct interface
*ifp
,
244 struct pim_interface
*pim_ifp
;
247 const struct ip
*ip_hdr
;
248 struct pim_upstream
*up
;
252 ip_hdr
= (const struct ip
*)buf
;
254 memset(&sg
, 0, sizeof(sg
));
255 sg
.src
= ip_hdr
->ip_src
;
256 sg
.grp
= ip_hdr
->ip_dst
;
258 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
260 pim_sgaddr star
= sg
;
261 star
.src
= PIMADDR_ANY
;
263 up
= pim_upstream_find(pim_ifp
->pim
, &star
);
265 if (up
&& PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
)) {
266 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
267 PIM_UPSTREAM_FLAG_MASK_SRC_LHR
,
270 if (PIM_DEBUG_MROUTE
)
271 zlog_debug("%s: Unable to create upstream information for %pSG",
275 pim_upstream_keep_alive_timer_start(
276 up
, pim_ifp
->pim
->keep_alive_time
);
277 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
278 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
280 if (PIM_DEBUG_MROUTE
)
281 zlog_debug("%s: Creating %s upstream on LHR",
282 __func__
, up
->sg_str
);
285 if (PIM_DEBUG_MROUTE_DETAIL
) {
286 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%pSG",
292 if (!up
->rpf
.source_nexthop
.interface
) {
293 if (PIM_DEBUG_PIM_TRACE
)
294 zlog_debug("%s: up %s RPF is not present", __func__
,
299 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
301 rpg
= pim_ifp
? RP(pim_ifp
->pim
, sg
.grp
) : NULL
;
303 if ((pim_rpf_addr_is_inaddr_none(rpg
)) || (!pim_ifp
)
304 || (!(PIM_I_am_DR(pim_ifp
)))) {
305 if (PIM_DEBUG_MROUTE
) {
306 zlog_debug("%s: Failed Check send packet", __func__
);
312 * If we've received a register suppress
314 if (!up
->t_rs_timer
) {
315 if (pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
316 if (PIM_DEBUG_PIM_REG
)
317 zlog_debug("%pSG register forward skipped as group is SSM",
322 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
323 if (PIM_DEBUG_PIM_REG
)
325 "%s register forward skipped, not FHR",
330 pim_register_send((uint8_t *)buf
+ sizeof(struct ip
),
331 ntohs(ip_hdr
->ip_len
) - sizeof(struct ip
),
332 pim_ifp
->primary_address
, rpg
, 0, up
);
337 static int pim_mroute_msg_wrongvif(int fd
, struct interface
*ifp
,
338 const struct igmpmsg
*msg
)
340 struct pim_ifchannel
*ch
;
341 struct pim_interface
*pim_ifp
;
344 memset(&sg
, 0, sizeof(sg
));
345 sg
.src
= msg
->im_src
;
346 sg
.grp
= msg
->im_dst
;
349 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
351 RFC 4601 4.8.2. PIM-SSM-Only Routers
353 iif is the incoming interface of the packet.
354 if (iif is in inherited_olist(S,G)) {
355 send Assert(S,G) on iif
360 if (PIM_DEBUG_MROUTE
)
361 zlog_debug("%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
362 __func__
, &sg
, msg
->im_vif
);
368 if (PIM_DEBUG_MROUTE
)
369 zlog_debug("%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
370 __func__
, &sg
, ifp
->name
);
374 ch
= pim_ifchannel_find(ifp
, &sg
);
376 pim_sgaddr star_g
= sg
;
377 if (PIM_DEBUG_MROUTE
)
378 zlog_debug("%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
379 __func__
, &sg
, ifp
->name
);
381 star_g
.src
= PIMADDR_ANY
;
382 ch
= pim_ifchannel_find(ifp
, &star_g
);
384 if (PIM_DEBUG_MROUTE
)
385 zlog_debug("%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
393 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
395 Transitions from NoInfo State
397 An (S,G) data packet arrives on interface I, AND
398 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
399 downstream interface that is in our (S,G) outgoing interface
400 list. We optimistically assume that we will be the assert
401 winner for this (S,G), and so we transition to the "I am Assert
402 Winner" state and perform Actions A1 (below), which will
403 initiate the assert negotiation for (S,G).
406 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
407 if (PIM_DEBUG_MROUTE
) {
409 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
410 __func__
, ch
->sg_str
, ifp
->name
);
415 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
416 if (PIM_DEBUG_MROUTE
) {
418 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
419 __func__
, ch
->sg_str
, ifp
->name
);
424 if (assert_action_a1(ch
)) {
425 if (PIM_DEBUG_MROUTE
) {
427 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
428 __func__
, ch
->sg_str
, ifp
->name
);
436 static int pim_mroute_msg_wrvifwhole(int fd
, struct interface
*ifp
,
439 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
440 struct pim_interface
*pim_ifp
;
441 struct pim_instance
*pim
;
442 struct pim_ifchannel
*ch
;
443 struct pim_upstream
*up
;
449 memset(&sg
, 0, sizeof(sg
));
450 sg
.src
= ip_hdr
->ip_src
;
451 sg
.grp
= ip_hdr
->ip_dst
;
453 ch
= pim_ifchannel_find(ifp
, &sg
);
455 if (PIM_DEBUG_MROUTE
)
457 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
458 ch
->sg_str
, ifp
->name
);
463 star_g
.src
= PIMADDR_ANY
;
467 * If the incoming interface is the pimreg, then
468 * we know the callback is associated with a pim register
469 * packet and there is nothing to do here as that
470 * normal pim processing will see the packet and allow
471 * us to do the right thing.
473 if (ifp
== pim
->regiface
) {
477 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
479 struct pim_upstream
*parent
;
480 struct pim_nexthop source
;
481 struct pim_rpf
*rpf
= RP(pim_ifp
->pim
, sg
.grp
);
483 /* No RPF or No RPF interface or No mcast on RPF interface */
484 if (!rpf
|| !rpf
->source_nexthop
.interface
485 || !rpf
->source_nexthop
.interface
->info
)
489 * If we have received a WRVIFWHOLE and are at this
490 * point, we could be receiving the packet on the *,G
491 * tree, let's check and if so we can safely drop
494 parent
= pim_upstream_find(pim_ifp
->pim
, &star_g
);
495 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
498 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
500 memset(&source
, 0, sizeof(source
));
502 * If we are the fhr that means we are getting a callback during
503 * the pimreg period, so I believe we can ignore this packet
505 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
507 * No if channel, but upstream we are at the RP.
509 * This could be a anycast RP too and we may
510 * not have received a register packet from
511 * the source here at all. So gracefully
512 * bow out of doing a nexthop lookup and
513 * setting the SPTBIT to true
515 if (up
->upstream_register
.s_addr
!= INADDR_ANY
&&
516 pim_nexthop_lookup(pim_ifp
->pim
, &source
,
517 up
->upstream_register
, 0)) {
518 pim_register_stop_send(source
.interface
, &sg
,
519 pim_ifp
->primary_address
,
520 up
->upstream_register
);
521 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
524 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
525 if (!up
->channel_oil
->installed
)
526 pim_upstream_mroute_add(up
->channel_oil
,
529 if (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
)) {
530 if (pim_nexthop_lookup(pim_ifp
->pim
, &source
,
531 up
->upstream_register
,
533 pim_register_stop_send(
534 source
.interface
, &sg
,
535 pim_ifp
->primary_address
,
536 up
->upstream_register
);
537 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
539 pim_upstream_keep_alive_timer_start(
540 up
, pim_ifp
->pim
->keep_alive_time
);
541 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
542 pim_mroute_msg_wholepkt(fd
, ifp
, buf
);
548 if (pim_if_connected_to_source(ifp
, sg
.src
)) {
549 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
550 PIM_UPSTREAM_FLAG_MASK_FHR
, __func__
,
553 if (PIM_DEBUG_MROUTE
)
554 zlog_debug("%pSG: WRONGVIF%s unable to create upstream on interface",
558 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
559 pim_upstream_keep_alive_timer_start(
560 up
, pim_ifp
->pim
->keep_alive_time
);
561 up
->channel_oil
->cc
.pktcnt
++;
562 pim_register_join(up
);
563 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
564 if (!up
->channel_oil
->installed
)
565 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
567 // Send the packet to the RP
568 pim_mroute_msg_wholepkt(fd
, ifp
, buf
);
570 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
571 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
,
573 if (!up
->channel_oil
->installed
)
574 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
580 static int pim_mroute_msg(struct pim_instance
*pim
, const char *buf
,
581 int buf_size
, ifindex_t ifindex
)
583 struct interface
*ifp
;
584 struct pim_interface
*pim_ifp
;
585 const struct ip
*ip_hdr
;
586 const struct igmpmsg
*msg
;
587 struct in_addr ifaddr
;
588 struct gm_sock
*igmp
;
589 const struct prefix
*connected_src
;
591 if (buf_size
< (int)sizeof(struct ip
))
594 ip_hdr
= (const struct ip
*)buf
;
596 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
598 /* We have the IP packet but we do not know which interface this
600 * received on. Find the interface that is on the same subnet as
604 ifp
= if_lookup_by_index(ifindex
, pim
->vrf
->vrf_id
);
606 if (!ifp
|| !ifp
->info
)
609 connected_src
= pim_if_connected_to_source(ifp
, ip_hdr
->ip_src
);
611 if (!connected_src
) {
612 if (PIM_DEBUG_IGMP_PACKETS
) {
613 zlog_debug("Recv IGMP packet on interface: %s from a non-connected source: %pI4",
614 ifp
->name
, &ip_hdr
->ip_src
);
620 ifaddr
= connected_src
->u
.prefix4
;
621 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->gm_socket_list
,
624 if (PIM_DEBUG_IGMP_PACKETS
) {
626 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
627 __func__
, pim
->vrf
->name
, ifp
->name
, igmp
,
628 &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
);
631 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
632 else if (PIM_DEBUG_IGMP_PACKETS
) {
633 zlog_debug("No IGMP socket on interface: %s with connected source: %pFX",
634 ifp
->name
, connected_src
);
636 } else if (ip_hdr
->ip_p
) {
637 if (PIM_DEBUG_MROUTE_DETAIL
) {
639 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%d",
640 __func__
, ip_hdr
->ip_p
, &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
,
645 msg
= (const struct igmpmsg
*)buf
;
647 ifp
= pim_if_find_by_vif_index(pim
, msg
->im_vif
);
651 if (PIM_DEBUG_MROUTE
) {
653 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%d",
654 __func__
, igmpmsgtype2str
[msg
->im_msgtype
],
655 msg
->im_msgtype
, ip_hdr
->ip_p
,
656 pim
->mroute_socket
, &msg
->im_src
, &msg
->im_dst
, ifp
->name
,
657 msg
->im_vif
, buf_size
);
660 switch (msg
->im_msgtype
) {
661 case IGMPMSG_WRONGVIF
:
662 return pim_mroute_msg_wrongvif(pim
->mroute_socket
, ifp
,
664 case IGMPMSG_NOCACHE
:
665 return pim_mroute_msg_nocache(pim
->mroute_socket
, ifp
,
667 case IGMPMSG_WHOLEPKT
:
668 return pim_mroute_msg_wholepkt(pim
->mroute_socket
, ifp
,
670 case IGMPMSG_WRVIFWHOLE
:
671 return pim_mroute_msg_wrvifwhole(
672 pim
->mroute_socket
, ifp
, (const char *)msg
);
680 #else /* PIM_IPV != 4 */
682 static int pim_mroute_msg(struct pim_instance
*pim
, const char *buf
,
683 int buf_size
, ifindex_t ifindex
)
687 #endif /* PIM_IPV != 4 */
689 static int mroute_read(struct thread
*t
)
691 struct pim_instance
*pim
;
692 static long long count
;
701 rd
= pim_socket_recvfromto(pim
->mroute_socket
, (uint8_t *)buf
,
702 sizeof(buf
), NULL
, NULL
, NULL
, NULL
,
707 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
711 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
712 __func__
, rd
, pim
->mroute_socket
, errno
,
713 safe_strerror(errno
));
717 result
= pim_mroute_msg(pim
, buf
, rd
, ifindex
);
720 if (count
% router
->packet_process
== 0)
730 static void mroute_read_on(struct pim_instance
*pim
)
732 thread_add_read(router
->master
, mroute_read
, pim
, pim
->mroute_socket
,
736 static void mroute_read_off(struct pim_instance
*pim
)
738 THREAD_OFF(pim
->thread
);
741 int pim_mroute_socket_enable(struct pim_instance
*pim
)
745 frr_with_privs(&pimd_privs
) {
747 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
750 zlog_warn("Could not create mroute socket: errno=%d: %s",
752 safe_strerror(errno
));
756 #ifdef SO_BINDTODEVICE
757 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
758 && setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
759 pim
->vrf
->name
, strlen(pim
->vrf
->name
))) {
760 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
761 safe_strerror(errno
));
769 pim
->mroute_socket
= fd
;
770 if (pim_mroute_set(pim
, 1)) {
772 "Could not enable mroute on socket fd=%d: errno=%d: %s",
773 fd
, errno
, safe_strerror(errno
));
775 pim
->mroute_socket
= -1;
779 pim
->mroute_socket_creation
= pim_time_monotonic_sec();
786 int pim_mroute_socket_disable(struct pim_instance
*pim
)
788 if (pim_mroute_set(pim
, 0)) {
790 "Could not disable mroute on socket fd=%d: errno=%d: %s",
791 pim
->mroute_socket
, errno
, safe_strerror(errno
));
795 if (close(pim
->mroute_socket
)) {
796 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
797 pim
->mroute_socket
, errno
, safe_strerror(errno
));
801 mroute_read_off(pim
);
802 pim
->mroute_socket
= -1;
808 For each network interface (e.g., physical or a virtual tunnel) that
809 would be used for multicast forwarding, a corresponding multicast
810 interface must be added to the kernel.
812 int pim_mroute_add_vif(struct interface
*ifp
, pim_addr ifaddr
,
815 struct pim_interface
*pim_ifp
= ifp
->info
;
819 if (PIM_DEBUG_MROUTE
)
820 zlog_debug("%s: Add Vif %d (%s[%s])", __func__
,
821 pim_ifp
->mroute_vif_index
, ifp
->name
,
822 pim_ifp
->pim
->vrf
->name
);
824 memset(&vc
, 0, sizeof(vc
));
825 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
826 #ifdef VIFF_USE_IFINDEX
827 vc
.vifc_lcl_ifindex
= ifp
->ifindex
;
829 if (ifaddr
.s_addr
== INADDR_ANY
) {
831 "%s: unnumbered interfaces are not supported on this platform",
835 memcpy(&vc
.vifc_lcl_addr
, &ifaddr
, sizeof(vc
.vifc_lcl_addr
));
837 vc
.vifc_flags
= flags
;
838 vc
.vifc_threshold
= PIM_MROUTE_MIN_TTL
;
839 vc
.vifc_rate_limit
= 0;
841 #ifdef PIM_DVMRP_TUNNEL
842 if (vc
.vifc_flags
& VIFF_TUNNEL
) {
843 memcpy(&vc
.vifc_rmt_addr
, &vif_remote_addr
,
844 sizeof(vc
.vifc_rmt_addr
));
848 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, IPPROTO_IP
, MRT_ADD_VIF
,
849 (void *)&vc
, sizeof(vc
));
852 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
853 __func__
, pim_ifp
->pim
->mroute_socket
, ifp
->ifindex
,
854 &ifaddr
, flags
, errno
, safe_strerror(errno
));
861 int pim_mroute_del_vif(struct interface
*ifp
)
863 struct pim_interface
*pim_ifp
= ifp
->info
;
867 if (PIM_DEBUG_MROUTE
)
868 zlog_debug("%s: Del Vif %d (%s[%s])", __func__
,
869 pim_ifp
->mroute_vif_index
, ifp
->name
,
870 pim_ifp
->pim
->vrf
->name
);
872 memset(&vc
, 0, sizeof(vc
));
873 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
875 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, IPPROTO_IP
, MRT_DEL_VIF
,
876 (void *)&vc
, sizeof(vc
));
879 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
880 __FILE__
, __func__
, pim_ifp
->pim
->mroute_socket
,
881 pim_ifp
->mroute_vif_index
, errno
, safe_strerror(errno
));
889 * Prevent creating MFC entry with OIF=IIF.
891 * This is a protection against implementation mistakes.
893 * PIM protocol implicitely ensures loopfree multicast topology.
895 * IGMP must be protected against adding looped MFC entries created
896 * by both source and receiver attached to the same interface. See
898 * We shall allow igmp to create upstream when it is DR for the intf.
899 * Assume RP reachable via non DR.
901 bool pim_mroute_allow_iif_in_oil(struct channel_oil
*c_oil
,
904 #ifdef PIM_ENFORCE_LOOPFREE_MFC
905 struct interface
*ifp_out
;
906 struct pim_interface
*pim_ifp
;
909 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil
->up
->flags
))
912 ifp_out
= pim_if_find_by_vif_index(c_oil
->pim
, oif_index
);
915 pim_ifp
= ifp_out
->info
;
918 if ((c_oil
->oif_flags
[oif_index
] & PIM_OIF_FLAG_PROTO_IGMP
) &&
919 PIM_I_am_DR(pim_ifp
))
928 static inline void pim_mroute_copy(struct channel_oil
*out
,
929 struct channel_oil
*in
)
933 *oil_origin(out
) = *oil_origin(in
);
934 *oil_mcastgrp(out
) = *oil_mcastgrp(in
);
935 *oil_parent(out
) = *oil_parent(in
);
937 for (i
= 0; i
< MAXVIFS
; ++i
) {
938 if (*oil_parent(out
) == i
&&
939 !pim_mroute_allow_iif_in_oil(in
, i
)) {
940 oil_if_set(out
, i
, 0);
944 if (in
->oif_flags
[i
] & PIM_OIF_FLAG_MUTE
)
945 oil_if_set(out
, i
, 0);
947 oil_if_set(out
, i
, oil_if_has(in
, i
));
951 /* This function must not be called directly 0
952 * use pim_upstream_mroute_add or pim_static_mroute_add instead
954 static int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
956 struct pim_instance
*pim
= c_oil
->pim
;
957 struct channel_oil tmp_oil
[1] = { };
960 pim
->mroute_add_last
= pim_time_monotonic_sec();
961 ++pim
->mroute_add_events
;
963 /* Copy the oil to a temporary structure to fixup (without need to
964 * later restore) before sending the mroute add to the dataplane
966 pim_mroute_copy(tmp_oil
, c_oil
);
968 /* The linux kernel *expects* the incoming
969 * vif to be part of the outgoing list
970 * in the case of a (*,G).
972 if (pim_addr_is_any(*oil_origin(c_oil
))) {
973 oil_if_set(tmp_oil
, *oil_parent(c_oil
), 1);
977 * If we have an unresolved cache entry for the S,G
978 * it is owned by the pimreg for the incoming IIF
979 * So set pimreg as the IIF temporarily to cause
980 * the packets to be forwarded. Then set it
981 * to the correct IIF afterwords.
983 if (!c_oil
->installed
&& !pim_addr_is_any(*oil_origin(c_oil
))
984 && *oil_parent(c_oil
) != 0) {
985 *oil_parent(tmp_oil
) = 0;
987 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
, MRT_ADD_MFC
,
988 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
990 if (!err
&& !c_oil
->installed
991 && !pim_addr_is_any(*oil_origin(c_oil
))
992 && *oil_parent(c_oil
) != 0) {
993 *oil_parent(tmp_oil
) = *oil_parent(c_oil
);
994 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
, MRT_ADD_MFC
,
995 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
1000 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
1001 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1002 safe_strerror(errno
));
1006 if (PIM_DEBUG_MROUTE
) {
1008 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__
, name
,
1010 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1013 if (!c_oil
->installed
) {
1014 c_oil
->installed
= 1;
1015 c_oil
->mroute_creation
= pim_time_monotonic_sec();
1021 static int pim_upstream_get_mroute_iif(struct channel_oil
*c_oil
,
1024 vifi_t iif
= MAXVIFS
;
1025 struct interface
*ifp
= NULL
;
1026 struct pim_interface
*pim_ifp
;
1027 struct pim_upstream
*up
= c_oil
->up
;
1030 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
)) {
1032 ifp
= up
->parent
->rpf
.source_nexthop
.interface
;
1034 ifp
= up
->rpf
.source_nexthop
.interface
;
1037 pim_ifp
= (struct pim_interface
*)ifp
->info
;
1039 iif
= pim_ifp
->mroute_vif_index
;
1045 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
1050 if (*oil_parent(c_oil
) >= MAXVIFS
) {
1051 /* the c_oil cannot be installed as a mroute yet */
1052 if (PIM_DEBUG_MROUTE
)
1054 "%s(%s) %s mroute not ready to be installed; %s",
1056 pim_channel_oil_dump(c_oil
, buf
,
1059 "uninstall" : "skip");
1060 /* if already installed flush it out as we are going to stop
1061 * updates to it leaving it in a stale state
1063 if (c_oil
->installed
)
1064 pim_mroute_del(c_oil
, name
);
1065 /* return success (skipped) */
1069 return pim_mroute_add(c_oil
, name
);
1072 /* IIF associated with SGrpt entries are re-evaluated when the parent
1073 * (*,G) entries IIF changes
1075 static void pim_upstream_all_sources_iif_update(struct pim_upstream
*up
)
1077 struct listnode
*listnode
;
1078 struct pim_upstream
*child
;
1080 for (ALL_LIST_ELEMENTS_RO(up
->sources
, listnode
,
1082 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
1083 pim_upstream_mroute_iif_update(child
->channel_oil
,
1088 /* In the case of "PIM state machine" added mroutes an upstream entry
1089 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1091 int pim_upstream_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1095 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1097 if (*oil_parent(c_oil
) != iif
) {
1098 *oil_parent(c_oil
) = iif
;
1099 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1101 pim_upstream_all_sources_iif_update(c_oil
->up
);
1103 *oil_parent(c_oil
) = iif
;
1106 return pim_upstream_mroute_update(c_oil
, name
);
1109 /* Look for IIF changes and update the dateplane entry only if the IIF
1112 int pim_upstream_mroute_iif_update(struct channel_oil
*c_oil
, const char *name
)
1117 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1118 if (*oil_parent(c_oil
) == iif
) {
1122 *oil_parent(c_oil
) = iif
;
1124 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
1126 pim_upstream_all_sources_iif_update(c_oil
->up
);
1128 if (PIM_DEBUG_MROUTE_DETAIL
)
1129 zlog_debug("%s(%s) %s mroute iif update %d",
1131 pim_channel_oil_dump(c_oil
, buf
,
1133 /* XXX: is this hack needed? */
1134 c_oil
->oil_inherited_rescan
= 1;
1135 return pim_upstream_mroute_update(c_oil
, name
);
1138 int pim_static_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1140 return pim_mroute_add(c_oil
, name
);
1143 void pim_static_mroute_iif_update(struct channel_oil
*c_oil
,
1144 int input_vif_index
,
1147 if (*oil_parent(c_oil
) == input_vif_index
)
1150 *oil_parent(c_oil
) = input_vif_index
;
1151 if (input_vif_index
== MAXVIFS
)
1152 pim_mroute_del(c_oil
, name
);
1154 pim_static_mroute_add(c_oil
, name
);
1157 int pim_mroute_del(struct channel_oil
*c_oil
, const char *name
)
1159 struct pim_instance
*pim
= c_oil
->pim
;
1162 pim
->mroute_del_last
= pim_time_monotonic_sec();
1163 ++pim
->mroute_del_events
;
1165 if (!c_oil
->installed
) {
1166 if (PIM_DEBUG_MROUTE
) {
1169 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1170 __FILE__
, __func__
, *oil_parent(c_oil
),
1171 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1176 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
, MRT_DEL_MFC
,
1177 &c_oil
->oil
, sizeof(c_oil
->oil
));
1179 if (PIM_DEBUG_MROUTE
)
1181 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
1182 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1183 safe_strerror(errno
));
1187 if (PIM_DEBUG_MROUTE
) {
1189 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__
, name
,
1191 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1194 // Reset kernel installed flag
1195 c_oil
->installed
= 0;
1200 void pim_mroute_update_counters(struct channel_oil
*c_oil
)
1202 struct pim_instance
*pim
= c_oil
->pim
;
1204 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
1205 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
1206 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
1208 if (!c_oil
->installed
) {
1209 c_oil
->cc
.lastused
= 100 * pim
->keep_alive_time
;
1210 if (PIM_DEBUG_MROUTE
) {
1213 sg
.src
= *oil_origin(c_oil
);
1214 sg
.grp
= *oil_mcastgrp(c_oil
);
1215 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1222 struct sioc_sg_req sgreq
;
1224 memset(&sgreq
, 0, sizeof(sgreq
));
1225 sgreq
.src
= *oil_origin(c_oil
);
1226 sgreq
.grp
= *oil_mcastgrp(c_oil
);
1228 pim_zlookup_sg_statistics(c_oil
);
1229 if (ioctl(pim
->mroute_socket
, SIOCGETSGCNT
, &sgreq
)) {
1232 sg
.src
= *oil_origin(c_oil
);
1233 sg
.grp
= *oil_mcastgrp(c_oil
);
1235 zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1236 (unsigned long)SIOCGETSGCNT
, &sg
,
1237 errno
, safe_strerror(errno
));
1241 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
1242 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
1243 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;