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"
48 static void mroute_read_on(struct pim_instance
*pim
);
51 int pim_mroute_msg_nocache(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
53 struct pim_interface
*pim_ifp
= ifp
->info
;
54 struct pim_upstream
*up
;
58 rpg
= pim_ifp
? RP(pim_ifp
->pim
, msg
->msg_im_dst
) : NULL
;
60 * If the incoming interface is unknown OR
61 * the Interface type is SSM we don't need to
64 if (!rpg
|| pim_rpf_addr_is_inaddr_any(rpg
)) {
65 if (PIM_DEBUG_MROUTE_DETAIL
)
67 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
74 * If we've received a multicast packet that isn't connected to
77 if (!pim_if_connected_to_source(ifp
, msg
->msg_im_src
)) {
78 if (PIM_DEBUG_MROUTE_DETAIL
)
80 "%s: Received incoming packet that doesn't originate on our seg",
85 memset(&sg
, 0, sizeof(sg
));
86 sg
.src
= msg
->msg_im_src
;
87 sg
.grp
= msg
->msg_im_dst
;
89 if (!(PIM_I_am_DR(pim_ifp
))) {
90 if (PIM_DEBUG_MROUTE_DETAIL
)
92 "%s: Interface is not the DR blackholing incoming traffic for %pSG",
96 * We are not the DR, but we are still receiving packets
97 * Let's blackhole those packets for the moment
98 * As that they will be coming up to the cpu
99 * and causing us to consider them.
101 * This *will* create a dangling channel_oil
102 * that I see no way to get rid of. Just noting
103 * this for future reference.
105 up
= pim_upstream_find_or_add(
106 &sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
, __func__
);
107 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
112 up
= pim_upstream_find_or_add(&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
,
116 * I moved this debug till after the actual add because
117 * I want to take advantage of the up->sg_str being filled in.
119 if (PIM_DEBUG_MROUTE
) {
120 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
121 __func__
, up
->sg_str
);
124 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
125 pim_upstream_keep_alive_timer_start(up
, pim_ifp
->pim
->keep_alive_time
);
127 up
->channel_oil
->cc
.pktcnt
++;
128 // resolve mfcc_parent prior to mroute_add in channel_add_oif
129 if (up
->rpf
.source_nexthop
.interface
&&
130 *oil_parent(up
->channel_oil
) >= MAXVIFS
) {
131 pim_upstream_mroute_iif_update(up
->channel_oil
, __func__
);
133 pim_register_join(up
);
134 /* if we have receiver, inherit from parent */
135 pim_upstream_inherited_olist_decide(pim_ifp
->pim
, up
);
140 int pim_mroute_msg_wholepkt(int fd
, struct interface
*ifp
, const char *buf
)
142 struct pim_interface
*pim_ifp
;
145 const ipv_hdr
*ip_hdr
;
146 struct pim_upstream
*up
;
150 ip_hdr
= (const ipv_hdr
*)buf
;
152 memset(&sg
, 0, sizeof(sg
));
153 sg
.src
= IPV_SRC(ip_hdr
);
154 sg
.grp
= IPV_DST(ip_hdr
);
156 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
158 pim_sgaddr star
= sg
;
159 star
.src
= PIMADDR_ANY
;
161 up
= pim_upstream_find(pim_ifp
->pim
, &star
);
163 if (up
&& PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up
->flags
)) {
164 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
165 PIM_UPSTREAM_FLAG_MASK_SRC_LHR
,
168 if (PIM_DEBUG_MROUTE
)
170 "%s: Unable to create upstream information for %pSG",
174 pim_upstream_keep_alive_timer_start(
175 up
, pim_ifp
->pim
->keep_alive_time
);
176 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
177 pim_upstream_update_join_desired(pim_ifp
->pim
, up
);
179 if (PIM_DEBUG_MROUTE
)
180 zlog_debug("%s: Creating %s upstream on LHR",
181 __func__
, up
->sg_str
);
184 if (PIM_DEBUG_MROUTE_DETAIL
) {
186 "%s: Unable to find upstream channel WHOLEPKT%pSG",
192 if (!up
->rpf
.source_nexthop
.interface
) {
193 if (PIM_DEBUG_PIM_TRACE
)
194 zlog_debug("%s: up %s RPF is not present", __func__
,
199 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
201 rpg
= pim_ifp
? RP(pim_ifp
->pim
, sg
.grp
) : NULL
;
203 if ((pim_rpf_addr_is_inaddr_any(rpg
)) || (!pim_ifp
) ||
204 (!(PIM_I_am_DR(pim_ifp
)))) {
205 if (PIM_DEBUG_MROUTE
) {
206 zlog_debug("%s: Failed Check send packet", __func__
);
212 * If we've received a register suppress
214 if (!up
->t_rs_timer
) {
215 if (pim_is_grp_ssm(pim_ifp
->pim
, sg
.grp
)) {
216 if (PIM_DEBUG_PIM_REG
)
218 "%pSG register forward skipped as group is SSM",
223 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
224 if (PIM_DEBUG_PIM_REG
)
226 "%s register forward skipped, not FHR",
231 pim_register_send((uint8_t *)buf
+ sizeof(ipv_hdr
),
232 ntohs(IPV_LEN(ip_hdr
)) - sizeof(ipv_hdr
),
233 pim_ifp
->primary_address
, rpg
, 0, up
);
238 int pim_mroute_msg_wrongvif(int fd
, struct interface
*ifp
, const kernmsg
*msg
)
240 struct pim_ifchannel
*ch
;
241 struct pim_interface
*pim_ifp
;
244 memset(&sg
, 0, sizeof(sg
));
245 sg
.src
= msg
->msg_im_src
;
246 sg
.grp
= msg
->msg_im_dst
;
249 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
251 RFC 4601 4.8.2. PIM-SSM-Only Routers
253 iif is the incoming interface of the packet.
254 if (iif is in inherited_olist(S,G)) {
255 send Assert(S,G) on iif
260 if (PIM_DEBUG_MROUTE
)
262 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
263 __func__
, &sg
, msg
->msg_im_vif
);
269 if (PIM_DEBUG_MROUTE
)
271 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
272 __func__
, &sg
, ifp
->name
);
276 ch
= pim_ifchannel_find(ifp
, &sg
);
278 pim_sgaddr star_g
= sg
;
279 if (PIM_DEBUG_MROUTE
)
281 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
282 __func__
, &sg
, ifp
->name
);
284 star_g
.src
= PIMADDR_ANY
;
285 ch
= pim_ifchannel_find(ifp
, &star_g
);
287 if (PIM_DEBUG_MROUTE
)
289 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
290 __func__
, &star_g
, ifp
->name
);
296 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
298 Transitions from NoInfo State
300 An (S,G) data packet arrives on interface I, AND
301 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
302 downstream interface that is in our (S,G) outgoing interface
303 list. We optimistically assume that we will be the assert
304 winner for this (S,G), and so we transition to the "I am Assert
305 Winner" state and perform Actions A1 (below), which will
306 initiate the assert negotiation for (S,G).
309 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
310 if (PIM_DEBUG_MROUTE
) {
312 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
313 __func__
, ch
->sg_str
, ifp
->name
);
318 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
319 if (PIM_DEBUG_MROUTE
) {
321 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
322 __func__
, ch
->sg_str
, ifp
->name
);
327 if (assert_action_a1(ch
)) {
328 if (PIM_DEBUG_MROUTE
) {
330 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
331 __func__
, ch
->sg_str
, ifp
->name
);
339 int pim_mroute_msg_wrvifwhole(int fd
, struct interface
*ifp
, const char *buf
)
341 const ipv_hdr
*ip_hdr
= (const ipv_hdr
*)buf
;
342 struct pim_interface
*pim_ifp
;
343 struct pim_instance
*pim
;
344 struct pim_ifchannel
*ch
;
345 struct pim_upstream
*up
;
351 memset(&sg
, 0, sizeof(sg
));
352 sg
.src
= IPV_SRC(ip_hdr
);
353 sg
.grp
= IPV_DST(ip_hdr
);
355 ch
= pim_ifchannel_find(ifp
, &sg
);
357 if (PIM_DEBUG_MROUTE
)
359 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
360 ch
->sg_str
, ifp
->name
);
365 star_g
.src
= PIMADDR_ANY
;
369 * If the incoming interface is the pimreg, then
370 * we know the callback is associated with a pim register
371 * packet and there is nothing to do here as that
372 * normal pim processing will see the packet and allow
373 * us to do the right thing.
375 if (ifp
== pim
->regiface
) {
379 up
= pim_upstream_find(pim_ifp
->pim
, &sg
);
381 struct pim_upstream
*parent
;
382 struct pim_nexthop source
;
383 struct pim_rpf
*rpf
= RP(pim_ifp
->pim
, sg
.grp
);
385 /* No RPF or No RPF interface or No mcast on RPF interface */
386 if (!rpf
|| !rpf
->source_nexthop
.interface
||
387 !rpf
->source_nexthop
.interface
->info
)
391 * If we have received a WRVIFWHOLE and are at this
392 * point, we could be receiving the packet on the *,G
393 * tree, let's check and if so we can safely drop
396 parent
= pim_upstream_find(pim_ifp
->pim
, &star_g
);
397 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
400 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
402 memset(&source
, 0, sizeof(source
));
404 * If we are the fhr that means we are getting a callback during
405 * the pimreg period, so I believe we can ignore this packet
407 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
)) {
409 * No if channel, but upstream we are at the RP.
411 * This could be a anycast RP too and we may
412 * not have received a register packet from
413 * the source here at all. So gracefully
414 * bow out of doing a nexthop lookup and
415 * setting the SPTBIT to true
417 if (!(pim_addr_is_any(up
->upstream_register
)) &&
418 pim_nexthop_lookup(pim_ifp
->pim
, &source
,
419 up
->upstream_register
, 0)) {
420 pim_register_stop_send(source
.interface
, &sg
,
421 pim_ifp
->primary_address
,
422 up
->upstream_register
);
423 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
426 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
427 if (!up
->channel_oil
->installed
)
428 pim_upstream_mroute_add(up
->channel_oil
,
431 if (I_am_RP(pim_ifp
->pim
, up
->sg
.grp
)) {
432 if (pim_nexthop_lookup(pim_ifp
->pim
, &source
,
433 up
->upstream_register
,
435 pim_register_stop_send(
436 source
.interface
, &sg
,
437 pim_ifp
->primary_address
,
438 up
->upstream_register
);
439 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
442 * At this point pimd is connected to
443 * the source, it has a parent, we are not
444 * the RP and the SPTBIT should be set
445 * since we know *the* S,G is on the SPT.
446 * The first time this happens, let's cause
447 * an immediate join to go out so that
448 * the RP can trim this guy immediately
449 * if necessary, instead of waiting
450 * one join/prune send cycle
452 if (up
->sptbit
!= PIM_UPSTREAM_SPTBIT_TRUE
&&
454 up
->rpf
.source_nexthop
.interface
!=
455 up
->parent
->rpf
.source_nexthop
457 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
458 pim_jp_agg_single_upstream_send(
459 &up
->parent
->rpf
, up
->parent
,
463 pim_upstream_keep_alive_timer_start(
464 up
, pim_ifp
->pim
->keep_alive_time
);
465 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
466 pim_mroute_msg_wholepkt(fd
, ifp
, buf
);
472 if (pim_if_connected_to_source(ifp
, sg
.src
)) {
473 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
474 PIM_UPSTREAM_FLAG_MASK_FHR
, __func__
,
477 if (PIM_DEBUG_MROUTE
)
479 "%pSG: WRONGVIF%s unable to create upstream on interface",
483 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
484 pim_upstream_keep_alive_timer_start(
485 up
, pim_ifp
->pim
->keep_alive_time
);
486 up
->channel_oil
->cc
.pktcnt
++;
487 pim_register_join(up
);
488 pim_upstream_inherited_olist(pim_ifp
->pim
, up
);
489 if (!up
->channel_oil
->installed
)
490 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
492 // Send the packet to the RP
493 pim_mroute_msg_wholepkt(fd
, ifp
, buf
);
495 up
= pim_upstream_add(pim_ifp
->pim
, &sg
, ifp
,
496 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE
,
498 if (!up
->channel_oil
->installed
)
499 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
505 static void mroute_read(struct thread
*t
)
507 struct pim_instance
*pim
;
508 static long long count
;
516 rd
= pim_socket_recvfromto(pim
->mroute_socket
, (uint8_t *)buf
,
517 sizeof(buf
), NULL
, NULL
, NULL
, NULL
,
522 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
526 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
527 __func__
, rd
, pim
->mroute_socket
, errno
,
528 safe_strerror(errno
));
532 pim_mroute_msg(pim
, buf
, rd
, ifindex
);
535 if (count
% router
->packet_process
== 0)
545 static void mroute_read_on(struct pim_instance
*pim
)
547 thread_add_read(router
->master
, mroute_read
, pim
, pim
->mroute_socket
,
551 static void mroute_read_off(struct pim_instance
*pim
)
553 THREAD_OFF(pim
->thread
);
556 int pim_mroute_socket_enable(struct pim_instance
*pim
)
560 frr_with_privs(&pimd_privs
) {
563 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
565 fd
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
568 zlog_warn("Could not create mroute socket: errno=%d: %s",
570 safe_strerror(errno
));
574 #ifdef SO_BINDTODEVICE
575 if (pim
->vrf
->vrf_id
!= VRF_DEFAULT
576 && setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
,
577 pim
->vrf
->name
, strlen(pim
->vrf
->name
))) {
578 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
579 safe_strerror(errno
));
587 pim
->mroute_socket
= fd
;
588 if (pim_mroute_set(pim
, 1)) {
590 "Could not enable mroute on socket fd=%d: errno=%d: %s",
591 fd
, errno
, safe_strerror(errno
));
593 pim
->mroute_socket
= -1;
597 pim
->mroute_socket_creation
= pim_time_monotonic_sec();
604 int pim_mroute_socket_disable(struct pim_instance
*pim
)
606 if (pim_mroute_set(pim
, 0)) {
608 "Could not disable mroute on socket fd=%d: errno=%d: %s",
609 pim
->mroute_socket
, errno
, safe_strerror(errno
));
613 if (close(pim
->mroute_socket
)) {
614 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
615 pim
->mroute_socket
, errno
, safe_strerror(errno
));
619 mroute_read_off(pim
);
620 pim
->mroute_socket
= -1;
626 For each network interface (e.g., physical or a virtual tunnel) that
627 would be used for multicast forwarding, a corresponding multicast
628 interface must be added to the kernel.
630 int pim_mroute_add_vif(struct interface
*ifp
, pim_addr ifaddr
,
633 struct pim_interface
*pim_ifp
= ifp
->info
;
637 if (PIM_DEBUG_MROUTE
)
638 zlog_debug("%s: Add Vif %d (%s[%s])", __func__
,
639 pim_ifp
->mroute_vif_index
, ifp
->name
,
640 pim_ifp
->pim
->vrf
->name
);
642 memset(&vc
, 0, sizeof(vc
));
643 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
645 #ifdef VIFF_USE_IFINDEX
646 vc
.vc_lcl_ifindex
= ifp
->ifindex
;
648 if (ifaddr
.s_addr
== INADDR_ANY
) {
650 "%s: unnumbered interfaces are not supported on this platform",
654 memcpy(&vc
.vc_lcl_addr
, &ifaddr
, sizeof(vc
.vc_lcl_addr
));
657 vc
.vc_pifi
= ifp
->ifindex
;
660 vc
.vc_threshold
= PIM_MROUTE_MIN_TTL
;
661 vc
.vc_rate_limit
= 0;
664 #ifdef PIM_DVMRP_TUNNEL
665 if (vc
.vc_flags
& VIFF_TUNNEL
) {
666 memcpy(&vc
.vc_rmt_addr
, &vif_remote_addr
,
667 sizeof(vc
.vc_rmt_addr
));
672 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_VIF
,
673 (void *)&vc
, sizeof(vc
));
676 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
677 __func__
, pim_ifp
->pim
->mroute_socket
, ifp
->ifindex
,
678 &ifaddr
, flags
, errno
, safe_strerror(errno
));
685 int pim_mroute_del_vif(struct interface
*ifp
)
687 struct pim_interface
*pim_ifp
= ifp
->info
;
691 if (PIM_DEBUG_MROUTE
)
692 zlog_debug("%s: Del Vif %d (%s[%s])", __func__
,
693 pim_ifp
->mroute_vif_index
, ifp
->name
,
694 pim_ifp
->pim
->vrf
->name
);
696 memset(&vc
, 0, sizeof(vc
));
697 vc
.vc_vifi
= pim_ifp
->mroute_vif_index
;
699 err
= setsockopt(pim_ifp
->pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_VIF
,
700 (void *)&vc
, sizeof(vc
));
703 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
704 __FILE__
, __func__
, pim_ifp
->pim
->mroute_socket
,
705 pim_ifp
->mroute_vif_index
, errno
, safe_strerror(errno
));
713 * Prevent creating MFC entry with OIF=IIF.
715 * This is a protection against implementation mistakes.
717 * PIM protocol implicitely ensures loopfree multicast topology.
719 * IGMP must be protected against adding looped MFC entries created
720 * by both source and receiver attached to the same interface. See
722 * We shall allow igmp to create upstream when it is DR for the intf.
723 * Assume RP reachable via non DR.
725 bool pim_mroute_allow_iif_in_oil(struct channel_oil
*c_oil
,
728 #ifdef PIM_ENFORCE_LOOPFREE_MFC
729 struct interface
*ifp_out
;
730 struct pim_interface
*pim_ifp
;
733 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil
->up
->flags
))
736 ifp_out
= pim_if_find_by_vif_index(c_oil
->pim
, oif_index
);
739 pim_ifp
= ifp_out
->info
;
742 if ((c_oil
->oif_flags
[oif_index
] & PIM_OIF_FLAG_PROTO_GM
) &&
743 PIM_I_am_DR(pim_ifp
))
752 static inline void pim_mroute_copy(struct channel_oil
*out
,
753 struct channel_oil
*in
)
757 *oil_origin(out
) = *oil_origin(in
);
758 *oil_mcastgrp(out
) = *oil_mcastgrp(in
);
759 *oil_parent(out
) = *oil_parent(in
);
761 for (i
= 0; i
< MAXVIFS
; ++i
) {
762 if (*oil_parent(out
) == i
&&
763 !pim_mroute_allow_iif_in_oil(in
, i
)) {
764 oil_if_set(out
, i
, 0);
768 if (in
->oif_flags
[i
] & PIM_OIF_FLAG_MUTE
)
769 oil_if_set(out
, i
, 0);
771 oil_if_set(out
, i
, oil_if_has(in
, i
));
775 /* This function must not be called directly 0
776 * use pim_upstream_mroute_add or pim_static_mroute_add instead
778 static int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
780 struct pim_instance
*pim
= c_oil
->pim
;
781 struct channel_oil tmp_oil
[1] = { };
784 pim
->mroute_add_last
= pim_time_monotonic_sec();
785 ++pim
->mroute_add_events
;
787 /* Copy the oil to a temporary structure to fixup (without need to
788 * later restore) before sending the mroute add to the dataplane
790 pim_mroute_copy(tmp_oil
, c_oil
);
792 /* The linux kernel *expects* the incoming
793 * vif to be part of the outgoing list
794 * in the case of a (*,G).
796 if (pim_addr_is_any(*oil_origin(c_oil
))) {
797 oil_if_set(tmp_oil
, *oil_parent(c_oil
), 1);
801 * If we have an unresolved cache entry for the S,G
802 * it is owned by the pimreg for the incoming IIF
803 * So set pimreg as the IIF temporarily to cause
804 * the packets to be forwarded. Then set it
805 * to the correct IIF afterwords.
807 if (!c_oil
->installed
&& !pim_addr_is_any(*oil_origin(c_oil
))
808 && *oil_parent(c_oil
) != 0) {
809 *oil_parent(tmp_oil
) = 0;
811 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
812 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
813 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
815 if (!err
&& !c_oil
->installed
816 && !pim_addr_is_any(*oil_origin(c_oil
))
817 && *oil_parent(c_oil
) != 0) {
818 *oil_parent(tmp_oil
) = *oil_parent(c_oil
);
819 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_ADD_MFC
,
820 &tmp_oil
->oil
, sizeof(tmp_oil
->oil
));
825 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
826 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
827 safe_strerror(errno
));
831 if (PIM_DEBUG_MROUTE
) {
833 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__
, name
,
835 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
838 if (!c_oil
->installed
) {
839 c_oil
->installed
= 1;
840 c_oil
->mroute_creation
= pim_time_monotonic_sec();
846 static int pim_upstream_get_mroute_iif(struct channel_oil
*c_oil
,
849 vifi_t iif
= MAXVIFS
;
850 struct interface
*ifp
= NULL
;
851 struct pim_interface
*pim_ifp
;
852 struct pim_upstream
*up
= c_oil
->up
;
855 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up
->flags
)) {
857 ifp
= up
->parent
->rpf
.source_nexthop
.interface
;
859 ifp
= up
->rpf
.source_nexthop
.interface
;
862 pim_ifp
= (struct pim_interface
*)ifp
->info
;
864 iif
= pim_ifp
->mroute_vif_index
;
870 static int pim_upstream_mroute_update(struct channel_oil
*c_oil
,
875 if (*oil_parent(c_oil
) >= MAXVIFS
) {
876 /* the c_oil cannot be installed as a mroute yet */
877 if (PIM_DEBUG_MROUTE
)
879 "%s(%s) %s mroute not ready to be installed; %s",
881 pim_channel_oil_dump(c_oil
, buf
,
884 "uninstall" : "skip");
885 /* if already installed flush it out as we are going to stop
886 * updates to it leaving it in a stale state
888 if (c_oil
->installed
)
889 pim_mroute_del(c_oil
, name
);
890 /* return success (skipped) */
894 return pim_mroute_add(c_oil
, name
);
897 /* IIF associated with SGrpt entries are re-evaluated when the parent
898 * (*,G) entries IIF changes
900 static void pim_upstream_all_sources_iif_update(struct pim_upstream
*up
)
902 struct listnode
*listnode
;
903 struct pim_upstream
*child
;
905 for (ALL_LIST_ELEMENTS_RO(up
->sources
, listnode
,
907 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child
->flags
))
908 pim_upstream_mroute_iif_update(child
->channel_oil
,
913 /* In the case of "PIM state machine" added mroutes an upstream entry
914 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
916 int pim_upstream_mroute_add(struct channel_oil
*c_oil
, const char *name
)
920 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
922 if (*oil_parent(c_oil
) != iif
) {
923 *oil_parent(c_oil
) = iif
;
924 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
926 pim_upstream_all_sources_iif_update(c_oil
->up
);
928 *oil_parent(c_oil
) = iif
;
931 return pim_upstream_mroute_update(c_oil
, name
);
934 /* Look for IIF changes and update the dateplane entry only if the IIF
937 int pim_upstream_mroute_iif_update(struct channel_oil
*c_oil
, const char *name
)
942 iif
= pim_upstream_get_mroute_iif(c_oil
, name
);
943 if (*oil_parent(c_oil
) == iif
) {
947 *oil_parent(c_oil
) = iif
;
949 if (pim_addr_is_any(*oil_origin(c_oil
)) &&
951 pim_upstream_all_sources_iif_update(c_oil
->up
);
953 if (PIM_DEBUG_MROUTE_DETAIL
)
954 zlog_debug("%s(%s) %s mroute iif update %d",
956 pim_channel_oil_dump(c_oil
, buf
,
958 /* XXX: is this hack needed? */
959 c_oil
->oil_inherited_rescan
= 1;
960 return pim_upstream_mroute_update(c_oil
, name
);
963 int pim_static_mroute_add(struct channel_oil
*c_oil
, const char *name
)
965 return pim_mroute_add(c_oil
, name
);
968 void pim_static_mroute_iif_update(struct channel_oil
*c_oil
,
972 if (*oil_parent(c_oil
) == input_vif_index
)
975 *oil_parent(c_oil
) = input_vif_index
;
976 if (input_vif_index
== MAXVIFS
)
977 pim_mroute_del(c_oil
, name
);
979 pim_static_mroute_add(c_oil
, name
);
982 int pim_mroute_del(struct channel_oil
*c_oil
, const char *name
)
984 struct pim_instance
*pim
= c_oil
->pim
;
987 pim
->mroute_del_last
= pim_time_monotonic_sec();
988 ++pim
->mroute_del_events
;
990 if (!c_oil
->installed
) {
991 if (PIM_DEBUG_MROUTE
) {
994 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
995 __FILE__
, __func__
, *oil_parent(c_oil
),
996 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1001 err
= setsockopt(pim
->mroute_socket
, PIM_IPPROTO
, MRT_DEL_MFC
,
1002 &c_oil
->oil
, sizeof(c_oil
->oil
));
1004 if (PIM_DEBUG_MROUTE
)
1006 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
1007 __FILE__
, __func__
, pim
->mroute_socket
, errno
,
1008 safe_strerror(errno
));
1012 if (PIM_DEBUG_MROUTE
) {
1014 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__
, name
,
1016 pim_channel_oil_dump(c_oil
, buf
, sizeof(buf
)));
1019 // Reset kernel installed flag
1020 c_oil
->installed
= 0;
1025 void pim_mroute_update_counters(struct channel_oil
*c_oil
)
1027 struct pim_instance
*pim
= c_oil
->pim
;
1028 pim_sioc_sg_req sgreq
;
1030 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
1031 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
1032 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
1034 if (!c_oil
->installed
) {
1035 c_oil
->cc
.lastused
= 100 * pim
->keep_alive_time
;
1036 if (PIM_DEBUG_MROUTE
) {
1039 sg
.src
= *oil_origin(c_oil
);
1040 sg
.grp
= *oil_mcastgrp(c_oil
);
1041 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1048 memset(&sgreq
, 0, sizeof(sgreq
));
1051 sgreq
.src
= *oil_origin(c_oil
);
1052 sgreq
.grp
= *oil_mcastgrp(c_oil
);
1053 pim_zlookup_sg_statistics(c_oil
);
1055 sgreq
.src
= c_oil
->oil
.mf6cc_origin
;
1056 sgreq
.grp
= c_oil
->oil
.mf6cc_mcastgrp
;
1057 /* TODO Zlookup_sg_statistics for V6 to be added */
1059 if (ioctl(pim
->mroute_socket
, PIM_SIOCGETSGCNT
, &sgreq
)) {
1062 sg
.src
= *oil_origin(c_oil
);
1063 sg
.grp
= *oil_mcastgrp(c_oil
);
1066 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1067 (unsigned long)PIM_SIOCGETSGCNT
, &sg
, errno
,
1068 safe_strerror(errno
));
1072 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
1073 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
1074 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;