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");
148 static const char *const igmpmsgtype2str
[IGMPMSG_WRVIFWHOLE
+ 1] = {
149 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
151 static int pim_mroute_msg_nocache(int fd
, struct interface
*ifp
,
152 const struct igmpmsg
*msg
)
154 struct pim_interface
*pim_ifp
= ifp
->info
;
155 struct pim_upstream
*up
;
159 rpg
= pim_ifp
? RP(pim_ifp
->pim
, msg
->im_dst
) : NULL
;
161 * If the incoming interface is unknown OR
162 * the Interface type is SSM we don't need to
165 if (!rpg
|| pim_rpf_addr_is_inaddr_none(rpg
)) {
166 if (PIM_DEBUG_MROUTE_DETAIL
)
168 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
175 * If we've received a multicast packet that isn't connected to
178 if (!pim_if_connected_to_source(ifp
, msg
->im_src
)) {
179 if (PIM_DEBUG_MROUTE_DETAIL
)
181 "%s: Received incoming packet that doesn't originate on our seg",
186 memset(&sg
, 0, sizeof(struct prefix_sg
));
187 sg
.src
= msg
->im_src
;
188 sg
.grp
= msg
->im_dst
;
190 if (!(PIM_I_am_DR(pim_ifp
))) {
191 if (PIM_DEBUG_MROUTE_DETAIL
)
193 "%s: Interface is not the DR blackholing incoming traffic for %s",
194 __func__
, pim_str_sg_dump(&sg
));
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 up
->channel_oil
->oil
.mfcc_parent
>= 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(struct prefix_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 struct prefix_sg star
= sg
;
261 star
.src
.s_addr
= INADDR_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
)
272 "%s: Unable to create upstream information for %s",
273 __func__
, pim_str_sg_dump(&sg
));
276 pim_upstream_keep_alive_timer_start(
277 up
, pim_ifp
->pim
->keep_alive_time
);
278 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
279 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
281 if (PIM_DEBUG_MROUTE
)
282 zlog_debug("%s: Creating %s upstream on LHR",
283 __func__
, up
->sg_str
);
286 if (PIM_DEBUG_MROUTE_DETAIL
) {
288 "%s: Unable to find upstream channel WHOLEPKT%s",
289 __func__
, pim_str_sg_dump(&sg
));
294 if (!up
->rpf
.source_nexthop
.interface
) {
295 if (PIM_DEBUG_PIM_TRACE
)
296 zlog_debug("%s: up %s RPF is not present", __func__
,
301 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
303 rpg
= pim_ifp
? RP(pim_ifp
->pim
, sg
.grp
) : NULL
;
305 if ((pim_rpf_addr_is_inaddr_none(rpg
)) || (!pim_ifp
)
306 || (!(PIM_I_am_DR(pim_ifp
)))) {
307 if (PIM_DEBUG_MROUTE
) {
308 zlog_debug("%s: Failed Check send packet", __func__
);
314 * If we've received a register suppress
316 if (!up
->t_rs_timer
) {
317 if (pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
318 if (PIM_DEBUG_PIM_REG
)
320 "%s register forward skipped as group is SSM",
321 pim_str_sg_dump(&sg
));
325 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
326 if (PIM_DEBUG_PIM_REG
)
328 "%s register forward skipped, not FHR",
333 pim_register_send((uint8_t *)buf
+ sizeof(struct ip
),
334 ntohs(ip_hdr
->ip_len
) - sizeof(struct ip
),
335 pim_ifp
->primary_address
, rpg
, 0, up
);
340 static int pim_mroute_msg_wrongvif(int fd
, struct interface
*ifp
,
341 const struct igmpmsg
*msg
)
343 struct pim_ifchannel
*ch
;
344 struct pim_interface
*pim_ifp
;
347 memset(&sg
, 0, sizeof(struct prefix_sg
));
348 sg
.src
= msg
->im_src
;
349 sg
.grp
= msg
->im_dst
;
352 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
354 RFC 4601 4.8.2. PIM-SSM-Only Routers
356 iif is the incoming interface of the packet.
357 if (iif is in inherited_olist(S,G)) {
358 send Assert(S,G) on iif
363 if (PIM_DEBUG_MROUTE
)
365 "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
366 __func__
, pim_str_sg_dump(&sg
), msg
->im_vif
);
372 if (PIM_DEBUG_MROUTE
)
374 "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
375 __func__
, pim_str_sg_dump(&sg
), ifp
->name
);
379 ch
= pim_ifchannel_find(ifp
, &sg
);
381 struct prefix_sg star_g
= sg
;
382 if (PIM_DEBUG_MROUTE
)
384 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
385 __func__
, pim_str_sg_dump(&sg
), ifp
->name
);
387 star_g
.src
.s_addr
= INADDR_ANY
;
388 ch
= pim_ifchannel_find(ifp
, &star_g
);
390 if (PIM_DEBUG_MROUTE
)
392 "%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
393 __func__
, pim_str_sg_dump(&star_g
),
400 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
402 Transitions from NoInfo State
404 An (S,G) data packet arrives on interface I, AND
405 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
406 downstream interface that is in our (S,G) outgoing interface
407 list. We optimistically assume that we will be the assert
408 winner for this (S,G), and so we transition to the "I am Assert
409 Winner" state and perform Actions A1 (below), which will
410 initiate the assert negotiation for (S,G).
413 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
414 if (PIM_DEBUG_MROUTE
) {
416 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
417 __func__
, ch
->sg_str
, ifp
->name
);
422 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
423 if (PIM_DEBUG_MROUTE
) {
425 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
426 __func__
, ch
->sg_str
, ifp
->name
);
431 if (assert_action_a1(ch
)) {
432 if (PIM_DEBUG_MROUTE
) {
434 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
435 __func__
, ch
->sg_str
, ifp
->name
);
443 static int pim_mroute_msg_wrvifwhole(int fd
, struct interface
*ifp
,
446 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
447 struct pim_interface
*pim_ifp
;
448 struct pim_instance
*pim
;
449 struct pim_ifchannel
*ch
;
450 struct pim_upstream
*up
;
451 struct prefix_sg star_g
;
456 memset(&sg
, 0, sizeof(struct prefix_sg
));
457 sg
.src
= ip_hdr
->ip_src
;
458 sg
.grp
= ip_hdr
->ip_dst
;
460 ch
= pim_ifchannel_find(ifp
, &sg
);
462 if (PIM_DEBUG_MROUTE
)
464 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
465 ch
->sg_str
, ifp
->name
);
470 star_g
.src
.s_addr
= INADDR_ANY
;
474 * If the incoming interface is the pimreg, then
475 * we know the callback is associated with a pim register
476 * packet and there is nothing to do here as that
477 * normal pim processing will see the packet and allow
478 * us to do the right thing.
480 if (ifp
== pim
->regiface
) {
484 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
486 struct pim_upstream
*parent
;
487 struct pim_nexthop source
;
488 struct pim_rpf
*rpf
= RP(pim_ifp
->pim
, sg
.grp
);
490 /* No RPF or No RPF interface or No mcast on RPF interface */
491 if (!rpf
|| !rpf
->source_nexthop
.interface
492 || !rpf
->source_nexthop
.interface
->info
)
496 * If we have received a WRVIFWHOLE and are at this
497 * point, we could be receiving the packet on the *,G
498 * tree, let's check and if so we can safely drop
501 parent
= pim_upstream_find(pim_ifp
->pim
, &star_g
);
502 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
505 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
507 memset(&source
, 0, sizeof(source
));
509 * If we are the fhr that means we are getting a callback during
510 * the pimreg period, so I believe we can ignore this packet
512 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
514 * No if channel, but upstream we are at the RP.
516 * This could be a anycast RP too and we may
517 * not have received a register packet from
518 * the source here at all. So gracefully
519 * bow out of doing a nexthop lookup and
520 * setting the SPTBIT to true
522 if (up
->upstream_register
.s_addr
!= INADDR_ANY
&&
523 pim_nexthop_lookup(pim_ifp
->pim
, &source
,
524 up
->upstream_register
, 0)) {
525 pim_register_stop_send(source
.interface
, &sg
,
526 pim_ifp
->primary_address
,
527 up
->upstream_register
);
528 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
531 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
532 if (!up
->channel_oil
->installed
)
533 pim_upstream_mroute_add(up
->channel_oil
,
536 if (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
)) {
537 if (pim_nexthop_lookup(pim_ifp
->pim
, &source
,
538 up
->upstream_register
,
540 pim_register_stop_send(
541 source
.interface
, &sg
,
542 pim_ifp
->primary_address
,
543 up
->upstream_register
);
544 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
546 pim_upstream_keep_alive_timer_start(
547 up
, pim_ifp
->pim
->keep_alive_time
);
548 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
549 pim_mroute_msg_wholepkt(fd
, ifp
, buf
);
555 if (pim_if_connected_to_source(ifp
, sg
.src
)) {
556 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
557 PIM_UPSTREAM_FLAG_MASK_FHR
, __func__
,
560 if (PIM_DEBUG_MROUTE
)
562 "%s: WRONGVIF%s unable to create upstream on interface",
563 pim_str_sg_dump(&sg
), ifp
->name
);
566 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
567 pim_upstream_keep_alive_timer_start(
568 up
, pim_ifp
->pim
->keep_alive_time
);
569 up
->channel_oil
->cc
.pktcnt
++;
570 pim_register_join(up
);
571 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
572 if (!up
->channel_oil
->installed
)
573 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
575 // Send the packet to the RP
576 pim_mroute_msg_wholepkt(fd
, ifp
, buf
);
578 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
579 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
,
581 if (!up
->channel_oil
->installed
)
582 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
588 static int pim_mroute_msg(struct pim_instance
*pim
, const char *buf
,
589 int buf_size
, ifindex_t ifindex
)
591 struct interface
*ifp
;
592 struct pim_interface
*pim_ifp
;
593 const struct ip
*ip_hdr
;
594 const struct igmpmsg
*msg
;
595 struct in_addr ifaddr
;
596 struct igmp_sock
*igmp
;
597 const struct prefix
*connected_src
;
599 if (buf_size
< (int)sizeof(struct ip
))
602 ip_hdr
= (const struct ip
*)buf
;
604 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
606 /* We have the IP packet but we do not know which interface this
608 * received on. Find the interface that is on the same subnet as
612 ifp
= if_lookup_by_index(ifindex
, pim
->vrf
->vrf_id
);
614 if (!ifp
|| !ifp
->info
)
617 connected_src
= pim_if_connected_to_source(ifp
, ip_hdr
->ip_src
);
619 if (!connected_src
) {
620 if (PIM_DEBUG_IGMP_PACKETS
) {
621 zlog_debug("Recv IGMP packet on interface: %s from a non-connected source: %pI4",
622 ifp
->name
, &ip_hdr
->ip_src
);
628 ifaddr
= connected_src
->u
.prefix4
;
629 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
631 if (PIM_DEBUG_IGMP_PACKETS
) {
633 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
634 __func__
, pim
->vrf
->name
, ifp
->name
, igmp
,
635 &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
);
638 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
639 else if (PIM_DEBUG_IGMP_PACKETS
) {
640 zlog_debug("No IGMP socket on interface: %s with connected source: %pFX",
641 ifp
->name
, connected_src
);
643 } else if (ip_hdr
->ip_p
) {
644 if (PIM_DEBUG_MROUTE_DETAIL
) {
646 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%d",
647 __func__
, ip_hdr
->ip_p
, &ip_hdr
->ip_src
, &ip_hdr
->ip_dst
,
652 msg
= (const struct igmpmsg
*)buf
;
654 ifp
= pim_if_find_by_vif_index(pim
, msg
->im_vif
);
658 if (PIM_DEBUG_MROUTE
) {
660 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%d",
661 __func__
, igmpmsgtype2str
[msg
->im_msgtype
],
662 msg
->im_msgtype
, ip_hdr
->ip_p
,
663 pim
->mroute_socket
, &msg
->im_src
, &msg
->im_dst
, ifp
->name
,
664 msg
->im_vif
, buf_size
);
667 switch (msg
->im_msgtype
) {
668 case IGMPMSG_WRONGVIF
:
669 return pim_mroute_msg_wrongvif(pim
->mroute_socket
, ifp
,
671 case IGMPMSG_NOCACHE
:
672 return pim_mroute_msg_nocache(pim
->mroute_socket
, ifp
,
674 case IGMPMSG_WHOLEPKT
:
675 return pim_mroute_msg_wholepkt(pim
->mroute_socket
, ifp
,
677 case IGMPMSG_WRVIFWHOLE
:
678 return pim_mroute_msg_wrvifwhole(
679 pim
->mroute_socket
, ifp
, (const char *)msg
);
688 static int mroute_read(struct thread
*t
)
690 struct pim_instance
*pim
;
691 static long long count
;
700 rd
= pim_socket_recvfromto(pim
->mroute_socket
, (uint8_t *)buf
,
701 sizeof(buf
), NULL
, NULL
, NULL
, NULL
,
706 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
710 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
711 __func__
, rd
, pim
->mroute_socket
, errno
,
712 safe_strerror(errno
));
716 result
= pim_mroute_msg(pim
, buf
, rd
, ifindex
);
719 if (count
% router
->packet_process
== 0)
729 static void mroute_read_on(struct pim_instance
*pim
)
731 thread_add_read(router
->master
, mroute_read
, pim
, pim
->mroute_socket
,
735 static void mroute_read_off(struct pim_instance
*pim
)
737 THREAD_OFF(pim
->thread
);
740 int pim_mroute_socket_enable(struct pim_instance
*pim
)
744 frr_with_privs(&pimd_privs
) {
746 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
749 zlog_warn("Could not create mroute socket: errno=%d: %s",
751 safe_strerror(errno
));
755 #ifdef SO_BINDTODEVICE
756 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
757 && setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
758 pim
->vrf
->name
, strlen(pim
->vrf
->name
))) {
759 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
760 safe_strerror(errno
));
768 pim
->mroute_socket
= fd
;
769 if (pim_mroute_set(pim
, 1)) {
771 "Could not enable mroute on socket fd=%d: errno=%d: %s",
772 fd
, errno
, safe_strerror(errno
));
774 pim
->mroute_socket
= -1;
778 pim
->mroute_socket_creation
= pim_time_monotonic_sec();
785 int pim_mroute_socket_disable(struct pim_instance
*pim
)
787 if (pim_mroute_set(pim
, 0)) {
789 "Could not disable mroute on socket fd=%d: errno=%d: %s",
790 pim
->mroute_socket
, errno
, safe_strerror(errno
));
794 if (close(pim
->mroute_socket
)) {
795 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
796 pim
->mroute_socket
, errno
, safe_strerror(errno
));
800 mroute_read_off(pim
);
801 pim
->mroute_socket
= -1;
807 For each network interface (e.g., physical or a virtual tunnel) that
808 would be used for multicast forwarding, a corresponding multicast
809 interface must be added to the kernel.
811 int pim_mroute_add_vif(struct interface
*ifp
, struct in_addr ifaddr
,
814 struct pim_interface
*pim_ifp
= ifp
->info
;
818 if (PIM_DEBUG_MROUTE
)
819 zlog_debug("%s: Add Vif %d (%s[%s])", __func__
,
820 pim_ifp
->mroute_vif_index
, ifp
->name
,
821 pim_ifp
->pim
->vrf
->name
);
823 memset(&vc
, 0, sizeof(vc
));
824 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
825 #ifdef VIFF_USE_IFINDEX
826 vc
.vifc_lcl_ifindex
= ifp
->ifindex
;
828 if (ifaddr
.s_addr
== INADDR_ANY
) {
830 "%s: unnumbered interfaces are not supported on this platform",
834 memcpy(&vc
.vifc_lcl_addr
, &ifaddr
, sizeof(vc
.vifc_lcl_addr
));
836 vc
.vifc_flags
= flags
;
837 vc
.vifc_threshold
= PIM_MROUTE_MIN_TTL
;
838 vc
.vifc_rate_limit
= 0;
840 #ifdef PIM_DVMRP_TUNNEL
841 if (vc
.vifc_flags
& VIFF_TUNNEL
) {
842 memcpy(&vc
.vifc_rmt_addr
, &vif_remote_addr
,
843 sizeof(vc
.vifc_rmt_addr
));
847 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, IPPROTO_IP
, MRT_ADD_VIF
,
848 (void *)&vc
, sizeof(vc
));
850 char ifaddr_str
[INET_ADDRSTRLEN
];
852 pim_inet4_dump("<ifaddr?>", ifaddr
, ifaddr_str
,
856 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
857 __func__
, pim_ifp
->pim
->mroute_socket
, ifp
->ifindex
,
858 ifaddr_str
, flags
, errno
, safe_strerror(errno
));
865 int pim_mroute_del_vif(struct interface
*ifp
)
867 struct pim_interface
*pim_ifp
= ifp
->info
;
871 if (PIM_DEBUG_MROUTE
)
872 zlog_debug("%s: Del Vif %d (%s[%s])", __func__
,
873 pim_ifp
->mroute_vif_index
, ifp
->name
,
874 pim_ifp
->pim
->vrf
->name
);
876 memset(&vc
, 0, sizeof(vc
));
877 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
879 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, IPPROTO_IP
, MRT_DEL_VIF
,
880 (void *)&vc
, sizeof(vc
));
883 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
884 __FILE__
, __func__
, pim_ifp
->pim
->mroute_socket
,
885 pim_ifp
->mroute_vif_index
, errno
, safe_strerror(errno
));
893 * Prevent creating MFC entry with OIF=IIF.
895 * This is a protection against implementation mistakes.
897 * PIM protocol implicitely ensures loopfree multicast topology.
899 * IGMP must be protected against adding looped MFC entries created
900 * by both source and receiver attached to the same interface. See
902 * We shall allow igmp to create upstream when it is DR for the intf.
903 * Assume RP reachable via non DR.
905 bool pim_mroute_allow_iif_in_oil(struct channel_oil
*c_oil
,
908 #ifdef PIM_ENFORCE_LOOPFREE_MFC
909 struct interface
*ifp_out
;
910 struct pim_interface
*pim_ifp
;
913 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil
->up
->flags
))
916 ifp_out
= pim_if_find_by_vif_index(c_oil
->pim
, oif_index
);
919 pim_ifp
= ifp_out
->info
;
922 if ((c_oil
->oif_flags
[oif_index
] & PIM_OIF_FLAG_PROTO_IGMP
) &&
923 PIM_I_am_DR(pim_ifp
))
932 static inline void pim_mroute_copy(struct mfcctl
*oil
,
933 struct channel_oil
*c_oil
)
937 oil
->mfcc_origin
= c_oil
->oil
.mfcc_origin
;
938 oil
->mfcc_mcastgrp
= c_oil
->oil
.mfcc_mcastgrp
;
939 oil
->mfcc_parent
= c_oil
->oil
.mfcc_parent
;
941 for (i
= 0; i
< MAXVIFS
; ++i
) {
942 if ((oil
->mfcc_parent
== i
) &&
943 !pim_mroute_allow_iif_in_oil(c_oil
, i
)) {
944 oil
->mfcc_ttls
[i
] = 0;
948 if (c_oil
->oif_flags
[i
] & PIM_OIF_FLAG_MUTE
)
949 oil
->mfcc_ttls
[i
] = 0;
951 oil
->mfcc_ttls
[i
] = c_oil
->oil
.mfcc_ttls
[i
];
955 /* This function must not be called directly 0
956 * use pim_upstream_mroute_add or pim_static_mroute_add instead
958 static int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
960 struct pim_instance
*pim
= c_oil
->pim
;
961 struct mfcctl tmp_oil
= { {0} };
964 pim
->mroute_add_last
= pim_time_monotonic_sec();
965 ++pim
->mroute_add_events
;
967 /* Copy the oil to a temporary structure to fixup (without need to
968 * later restore) before sending the mroute add to the dataplane
970 pim_mroute_copy(&tmp_oil
, c_oil
);
972 /* The linux kernel *expects* the incoming
973 * vif to be part of the outgoing list
974 * in the case of a (*,G).
976 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
) {
977 tmp_oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = 1;
981 * If we have an unresolved cache entry for the S,G
982 * it is owned by the pimreg for the incoming IIF
983 * So set pimreg as the IIF temporarily to cause
984 * the packets to be forwarded. Then set it
985 * to the correct IIF afterwords.
987 if (!c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
988 && c_oil
->oil
.mfcc_parent
!= 0) {
989 tmp_oil
.mfcc_parent
= 0;
991 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
, MRT_ADD_MFC
,
992 &tmp_oil
, sizeof(tmp_oil
));
994 if (!err
&& !c_oil
->installed
995 && c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
996 && c_oil
->oil
.mfcc_parent
!= 0) {
997 tmp_oil
.mfcc_parent
= c_oil
->oil
.mfcc_parent
;
998 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
, MRT_ADD_MFC
,
999 &tmp_oil
, sizeof(tmp_oil
));
1004 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
1005 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1006 safe_strerror(errno
));
1010 if (PIM_DEBUG_MROUTE
) {
1012 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__
, name
,
1014 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1017 if (!c_oil
->installed
) {
1018 c_oil
->installed
= 1;
1019 c_oil
->mroute_creation
= pim_time_monotonic_sec();
1025 static int pim_upstream_get_mroute_iif(struct channel_oil
*c_oil
,
1028 vifi_t iif
= MAXVIFS
;
1029 struct interface
*ifp
= NULL
;
1030 struct pim_interface
*pim_ifp
;
1031 struct pim_upstream
*up
= c_oil
->up
;
1034 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
)) {
1036 ifp
= up
->parent
->rpf
.source_nexthop
.interface
;
1038 ifp
= up
->rpf
.source_nexthop
.interface
;
1041 pim_ifp
= (struct pim_interface
*)ifp
->info
;
1043 iif
= pim_ifp
->mroute_vif_index
;
1049 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
1054 if (c_oil
->oil
.mfcc_parent
>= MAXVIFS
) {
1055 /* the c_oil cannot be installed as a mroute yet */
1056 if (PIM_DEBUG_MROUTE
)
1058 "%s(%s) %s mroute not ready to be installed; %s",
1060 pim_channel_oil_dump(c_oil
, buf
,
1063 "uninstall" : "skip");
1064 /* if already installed flush it out as we are going to stop
1065 * updates to it leaving it in a stale state
1067 if (c_oil
->installed
)
1068 pim_mroute_del(c_oil
, name
);
1069 /* return success (skipped) */
1073 return pim_mroute_add(c_oil
, name
);
1076 /* IIF associated with SGrpt entries are re-evaluated when the parent
1077 * (*,G) entries IIF changes
1079 static void pim_upstream_all_sources_iif_update(struct pim_upstream
*up
)
1081 struct listnode
*listnode
;
1082 struct pim_upstream
*child
;
1084 for (ALL_LIST_ELEMENTS_RO(up
->sources
, listnode
,
1086 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
1087 pim_upstream_mroute_iif_update(child
->channel_oil
,
1092 /* In the case of "PIM state machine" added mroutes an upstream entry
1093 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1095 int pim_upstream_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1099 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1101 if (c_oil
->oil
.mfcc_parent
!= iif
) {
1102 c_oil
->oil
.mfcc_parent
= iif
;
1103 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
&&
1105 pim_upstream_all_sources_iif_update(c_oil
->up
);
1107 c_oil
->oil
.mfcc_parent
= iif
;
1110 return pim_upstream_mroute_update(c_oil
, name
);
1113 /* Look for IIF changes and update the dateplane entry only if the IIF
1116 int pim_upstream_mroute_iif_update(struct channel_oil
*c_oil
, const char *name
)
1121 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
1122 if (c_oil
->oil
.mfcc_parent
== iif
) {
1126 c_oil
->oil
.mfcc_parent
= iif
;
1128 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
&&
1130 pim_upstream_all_sources_iif_update(c_oil
->up
);
1132 if (PIM_DEBUG_MROUTE_DETAIL
)
1133 zlog_debug("%s(%s) %s mroute iif update %d",
1135 pim_channel_oil_dump(c_oil
, buf
,
1137 /* XXX: is this hack needed? */
1138 c_oil
->oil_inherited_rescan
= 1;
1139 return pim_upstream_mroute_update(c_oil
, name
);
1142 int pim_static_mroute_add(struct channel_oil
*c_oil
, const char *name
)
1144 return pim_mroute_add(c_oil
, name
);
1147 void pim_static_mroute_iif_update(struct channel_oil
*c_oil
,
1148 int input_vif_index
,
1151 if (c_oil
->oil
.mfcc_parent
== input_vif_index
)
1154 c_oil
->oil
.mfcc_parent
= input_vif_index
;
1155 if (input_vif_index
== MAXVIFS
)
1156 pim_mroute_del(c_oil
, name
);
1158 pim_static_mroute_add(c_oil
, name
);
1161 int pim_mroute_del(struct channel_oil
*c_oil
, const char *name
)
1163 struct pim_instance
*pim
= c_oil
->pim
;
1166 pim
->mroute_del_last
= pim_time_monotonic_sec();
1167 ++pim
->mroute_del_events
;
1169 if (!c_oil
->installed
) {
1170 if (PIM_DEBUG_MROUTE
) {
1173 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1174 __FILE__
, __func__
, c_oil
->oil
.mfcc_parent
,
1175 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1180 err
= setsockopt(pim
->mroute_socket
, IPPROTO_IP
, MRT_DEL_MFC
,
1181 &c_oil
->oil
, sizeof(c_oil
->oil
));
1183 if (PIM_DEBUG_MROUTE
)
1185 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
1186 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1187 safe_strerror(errno
));
1191 if (PIM_DEBUG_MROUTE
) {
1193 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__
, name
,
1195 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1198 // Reset kernel installed flag
1199 c_oil
->installed
= 0;
1204 void pim_mroute_update_counters(struct channel_oil
*c_oil
)
1206 struct pim_instance
*pim
= c_oil
->pim
;
1207 struct sioc_sg_req sgreq
;
1209 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
1210 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
1211 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
1213 if (!c_oil
->installed
) {
1214 c_oil
->cc
.lastused
= 100 * pim
->keep_alive_time
;
1215 if (PIM_DEBUG_MROUTE
) {
1216 struct prefix_sg sg
;
1218 sg
.src
= c_oil
->oil
.mfcc_origin
;
1219 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
1221 "Channel%s is not installed no need to collect data from kernel",
1222 pim_str_sg_dump(&sg
));
1227 memset(&sgreq
, 0, sizeof(sgreq
));
1228 sgreq
.src
= c_oil
->oil
.mfcc_origin
;
1229 sgreq
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
1231 pim_zlookup_sg_statistics(c_oil
);
1232 if (ioctl(pim
->mroute_socket
, SIOCGETSGCNT
, &sgreq
)) {
1233 struct prefix_sg sg
;
1235 sg
.src
= c_oil
->oil
.mfcc_origin
;
1236 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
1238 zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
1239 (unsigned long)SIOCGETSGCNT
, pim_str_sg_dump(&sg
),
1240 errno
, safe_strerror(errno
));
1244 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
1245 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
1246 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;