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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
31 #include "pim_mroute.h"
35 #include "pim_iface.h"
36 #include "pim_macro.h"
39 #include "pim_register.h"
40 #include "pim_ifchannel.h"
41 #include "pim_zlookup.h"
45 static struct thread
*qpim_mroute_socket_reader
= NULL
;
47 static void mroute_read_on(void);
49 static int pim_mroute_set(int fd
, int enable
)
52 int opt
= enable
? MRT_INIT
: MRT_DONE
;
53 socklen_t opt_len
= sizeof(opt
);
54 int rcvbuf
= 1024 * 1024 * 8;
57 err
= setsockopt(fd
, IPPROTO_IP
, opt
, &opt
, opt_len
);
59 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
60 __FILE__
, __PRETTY_FUNCTION__
,
61 fd
, enable
? "MRT_INIT" : "MRT_DONE", opt
, errno
, safe_strerror(errno
));
65 err
= setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
, sizeof(rcvbuf
));
67 zlog_warn("%s: failure: setsockopt(fd=%d, SOL_SOCKET, %d): errno=%d: %s",
68 __PRETTY_FUNCTION__
, fd
, rcvbuf
, errno
, safe_strerror(errno
));
71 flags
= fcntl(fd
, F_GETFL
, 0);
74 zlog_warn("Could not get flags on socket fd:%d %d %s",
75 fd
, errno
, safe_strerror(errno
));
79 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
))
81 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
82 fd
, errno
, safe_strerror(errno
));
90 int upcalls
= IGMPMSG_WRVIFWHOLE
;
93 err
= setsockopt (fd
, IPPROTO_IP
, opt
, &upcalls
, sizeof (upcalls
));
96 zlog_warn ("Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
97 errno
, safe_strerror (errno
));
101 zlog_warn ("PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
108 static const char *igmpmsgtype2str
[IGMPMSG_WRVIFWHOLE
+ 1] = {
116 pim_mroute_msg_nocache (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
118 struct pim_interface
*pim_ifp
= ifp
->info
;
119 struct pim_upstream
*up
;
123 rpg
= RP(msg
->im_dst
);
125 * If the incoming interface is unknown OR
126 * the Interface type is SSM we don't need to
129 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
131 (!(PIM_I_am_DR(pim_ifp
))))
133 if (PIM_DEBUG_MROUTE_DETAIL
)
134 zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP",
135 __PRETTY_FUNCTION__
);
140 * If we've received a multicast packet that isn't connected to
143 if (!pim_if_connected_to_source (ifp
, msg
->im_src
))
145 if (PIM_DEBUG_MROUTE_DETAIL
)
146 zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
147 __PRETTY_FUNCTION__
);
151 memset (&sg
, 0, sizeof (struct prefix_sg
));
152 sg
.src
= msg
->im_src
;
153 sg
.grp
= msg
->im_dst
;
155 up
= pim_upstream_find_or_add (&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
, __PRETTY_FUNCTION__
);
158 if (PIM_DEBUG_MROUTE
)
160 zlog_debug("%s: Failure to add upstream information for %s",
162 pim_str_sg_dump (&sg
));
168 * I moved this debug till after the actual add because
169 * I want to take advantage of the up->sg_str being filled in.
171 if (PIM_DEBUG_MROUTE
) {
172 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
173 __PRETTY_FUNCTION__
, up
->sg_str
);
176 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
177 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
179 up
->channel_oil
->cc
.pktcnt
++;
180 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
181 // resolve mfcc_parent prior to mroute_add in channel_add_oif
182 if (up
->channel_oil
->oil
.mfcc_parent
>= MAXVIFS
)
186 pim_if_find_vifindex_by_ifindex (up
->rpf
.source_nexthop
.
188 up
->channel_oil
->oil
.mfcc_parent
= vif_index
;
190 pim_register_join (up
);
196 pim_mroute_msg_wholepkt (int fd
, struct interface
*ifp
, const char *buf
)
198 struct pim_interface
*pim_ifp
;
201 const struct ip
*ip_hdr
;
202 struct pim_upstream
*up
;
204 ip_hdr
= (const struct ip
*)buf
;
206 memset (&sg
, 0, sizeof (struct prefix_sg
));
207 sg
.src
= ip_hdr
->ip_src
;
208 sg
.grp
= ip_hdr
->ip_dst
;
210 up
= pim_upstream_find(&sg
);
212 struct prefix_sg star
= sg
;
213 star
.src
.s_addr
= INADDR_ANY
;
215 up
= pim_upstream_find(&star
);
217 if (up
&& PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up
->flags
))
219 up
= pim_upstream_add (&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_SRC_LHR
, __PRETTY_FUNCTION__
);
222 if (PIM_DEBUG_MROUTE
)
223 zlog_debug ("%s: Unable to create upstream information for %s",
224 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
227 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
228 pim_upstream_inherited_olist (up
);
229 pim_upstream_switch(up
, PIM_UPSTREAM_JOINED
);
231 if (PIM_DEBUG_MROUTE
)
232 zlog_debug ("%s: Creating %s upstream on LHR",
233 __PRETTY_FUNCTION__
, up
->sg_str
);
236 if (PIM_DEBUG_MROUTE_DETAIL
) {
237 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
238 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
243 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
247 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
249 (!(PIM_I_am_DR(pim_ifp
)))) {
250 if (PIM_DEBUG_MROUTE
) {
251 zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__
);
257 * If we've received a register suppress
261 if (pim_is_grp_ssm (sg
.grp
))
263 if (PIM_DEBUG_PIM_REG
)
264 zlog_debug ("%s register forward skipped as group is SSM",
265 pim_str_sg_dump (&sg
));
268 pim_register_send((uint8_t *)buf
+ sizeof(struct ip
),
269 ntohs (ip_hdr
->ip_len
) - sizeof (struct ip
),
270 pim_ifp
->primary_address
, rpg
, 0, up
);
276 pim_mroute_msg_wrongvif (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
278 struct pim_ifchannel
*ch
;
279 struct pim_interface
*pim_ifp
;
282 memset (&sg
, 0, sizeof (struct prefix_sg
));
283 sg
.src
= msg
->im_src
;
284 sg
.grp
= msg
->im_dst
;
287 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
289 RFC 4601 4.8.2. PIM-SSM-Only Routers
291 iif is the incoming interface of the packet.
292 if (iif is in inherited_olist(S,G)) {
293 send Assert(S,G) on iif
298 if (PIM_DEBUG_MROUTE
)
299 zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
301 pim_str_sg_dump (&sg
), msg
->im_vif
);
307 if (PIM_DEBUG_MROUTE
)
308 zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
310 pim_str_sg_dump (&sg
), ifp
->name
);
314 ch
= pim_ifchannel_find(ifp
, &sg
);
316 struct prefix_sg star_g
= sg
;
317 if (PIM_DEBUG_MROUTE
)
318 zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
320 pim_str_sg_dump(&sg
), ifp
->name
);
322 star_g
.src
.s_addr
= INADDR_ANY
;
323 ch
= pim_ifchannel_find(ifp
, &star_g
);
325 if (PIM_DEBUG_MROUTE
)
326 zlog_debug("%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
328 pim_str_sg_dump(&star_g
), ifp
->name
);
334 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
336 Transitions from NoInfo State
338 An (S,G) data packet arrives on interface I, AND
339 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
340 downstream interface that is in our (S,G) outgoing interface
341 list. We optimistically assume that we will be the assert
342 winner for this (S,G), and so we transition to the "I am Assert
343 Winner" state and perform Actions A1 (below), which will
344 initiate the assert negotiation for (S,G).
347 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
348 if (PIM_DEBUG_MROUTE
) {
349 zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
351 ch
->sg_str
, ifp
->name
);
356 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
357 if (PIM_DEBUG_MROUTE
) {
358 zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
360 ch
->sg_str
, ifp
->name
);
365 if (assert_action_a1(ch
)) {
366 if (PIM_DEBUG_MROUTE
) {
367 zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
369 ch
->sg_str
, ifp
->name
);
378 pim_mroute_msg_wrvifwhole (int fd
, struct interface
*ifp
, const char *buf
)
380 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
381 struct pim_interface
*pim_ifp
;
382 struct pim_ifchannel
*ch
;
383 struct pim_upstream
*up
;
384 struct prefix_sg star_g
;
386 struct channel_oil
*oil
;
388 memset (&sg
, 0, sizeof (struct prefix_sg
));
389 sg
.src
= ip_hdr
->ip_src
;
390 sg
.grp
= ip_hdr
->ip_dst
;
392 ch
= pim_ifchannel_find(ifp
, &sg
);
395 if (PIM_DEBUG_MROUTE
)
396 zlog_debug ("WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
397 ch
->sg_str
, ifp
->name
);
402 star_g
.src
.s_addr
= INADDR_ANY
;
404 ch
= pim_ifchannel_find(ifp
, &star_g
);
407 if (PIM_DEBUG_MROUTE
)
408 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
409 pim_str_sg_dump (&star_g
), ifp
->name
);
414 up
= pim_upstream_find (&sg
);
417 struct pim_upstream
*parent
;
418 struct pim_nexthop source
;
419 struct pim_rpf
*rpf
= RP (sg
.grp
);
420 if (!rpf
|| !rpf
->source_nexthop
.interface
)
424 * If we have received a WRVIFWHOLE and are at this
425 * point, we could be receiving the packet on the *,G
426 * tree, let's check and if so we can safely drop
429 parent
= pim_upstream_find (&star_g
);
430 if (parent
&& parent
->rpf
.source_nexthop
.interface
== ifp
)
433 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
435 memset (&source
, 0, sizeof (source
));
437 * If we are the fhr that means we are getting a callback during
438 * the pimreg period, so I believe we can ignore this packet
440 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
442 //No if channel, but upstream we are at the RP.
443 if (pim_nexthop_lookup (&source
, up
->upstream_register
, 0) == 0)
444 pim_register_stop_send(source
.interface
, &sg
, pim_ifp
->primary_address
, up
->upstream_register
);
445 if (!up
->channel_oil
)
446 up
->channel_oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
447 pim_upstream_inherited_olist (up
);
448 if (!up
->channel_oil
->installed
)
449 pim_mroute_add (up
->channel_oil
, __PRETTY_FUNCTION__
);
450 pim_upstream_set_sptbit (up
, ifp
);
454 if (I_am_RP (up
->sg
.grp
))
456 if (pim_nexthop_lookup (&source
, up
->upstream_register
, 0) == 0)
457 pim_register_stop_send(source
.interface
, &sg
, pim_ifp
->primary_address
, up
->upstream_register
);
458 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
460 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
461 pim_upstream_inherited_olist (up
);
462 pim_mroute_msg_wholepkt (fd
, ifp
, buf
);
468 oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
470 pim_mroute_add (oil
, __PRETTY_FUNCTION__
);
471 if (pim_if_connected_to_source (ifp
, sg
.src
))
473 up
= pim_upstream_add (&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
, __PRETTY_FUNCTION__
);
476 if (PIM_DEBUG_MROUTE
)
477 zlog_debug ("%s: WRONGVIF%s unable to create upstream on interface",
478 pim_str_sg_dump (&sg
), ifp
->name
);
481 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
482 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
483 up
->channel_oil
= oil
;
484 up
->channel_oil
->cc
.pktcnt
++;
485 pim_register_join (up
);
486 pim_upstream_inherited_olist (up
);
488 // Send the packet to the RP
489 pim_mroute_msg_wholepkt (fd
, ifp
, buf
);
495 int pim_mroute_msg(int fd
, const char *buf
, int buf_size
)
497 struct interface
*ifp
;
498 struct pim_interface
*pim_ifp
;
499 const struct ip
*ip_hdr
;
500 const struct igmpmsg
*msg
;
501 char ip_src_str
[INET_ADDRSTRLEN
] = "";
502 char ip_dst_str
[INET_ADDRSTRLEN
] = "";
503 char src_str
[INET_ADDRSTRLEN
] = "<src?>";
504 char grp_str
[INET_ADDRSTRLEN
] = "<grp?>";
505 struct in_addr ifaddr
;
506 struct igmp_sock
*igmp
;
508 ip_hdr
= (const struct ip
*) buf
;
510 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
512 /* We have the IP packet but we do not know which interface this packet was
513 * received on. Find the interface that is on the same subnet as the source
516 ifp
= pim_if_lookup_address_vrf (ip_hdr
->ip_src
, VRF_DEFAULT
);
519 if (PIM_DEBUG_MROUTE_DETAIL
) {
520 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, ip_src_str
, sizeof(ip_src_str
));
521 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, ip_dst_str
, sizeof(ip_dst_str
));
523 zlog_warn("%s: igmp kernel upcall could not find usable interface for %s -> %s",
531 ifaddr
= pim_find_primary_addr(ifp
);
532 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
534 if (PIM_DEBUG_MROUTE
) {
535 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, ip_src_str
, sizeof(ip_src_str
));
536 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, ip_dst_str
, sizeof(ip_dst_str
));
538 zlog_warn("%s: igmp kernel upcall on %s(%p) for %s -> %s",
539 __PRETTY_FUNCTION__
, ifp
->name
, igmp
, ip_src_str
, ip_dst_str
);
542 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
544 } else if (ip_hdr
->ip_p
) {
545 if (PIM_DEBUG_MROUTE_DETAIL
) {
546 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
, sizeof(src_str
));
547 pim_inet4_dump("<grp?>", ip_hdr
->ip_dst
, grp_str
, sizeof(grp_str
));
548 zlog_debug("%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
549 __PRETTY_FUNCTION__
, ip_hdr
->ip_p
, src_str
, grp_str
, buf_size
);
553 msg
= (const struct igmpmsg
*) buf
;
555 ifp
= pim_if_find_by_vif_index(msg
->im_vif
);
559 if (PIM_DEBUG_MROUTE
) {
560 pim_inet4_dump("<src?>", msg
->im_src
, src_str
, sizeof(src_str
));
561 pim_inet4_dump("<grp?>", msg
->im_dst
, grp_str
, sizeof(grp_str
));
562 zlog_warn("%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
564 igmpmsgtype2str
[msg
->im_msgtype
],
571 msg
->im_vif
, buf_size
);
574 switch (msg
->im_msgtype
) {
575 case IGMPMSG_WRONGVIF
:
576 return pim_mroute_msg_wrongvif(fd
, ifp
, msg
);
578 case IGMPMSG_NOCACHE
:
579 return pim_mroute_msg_nocache(fd
, ifp
, msg
);
581 case IGMPMSG_WHOLEPKT
:
582 return pim_mroute_msg_wholepkt(fd
, ifp
, (const char *)msg
);
584 case IGMPMSG_WRVIFWHOLE
:
585 return pim_mroute_msg_wrvifwhole (fd
, ifp
, (const char *)msg
);
595 static int mroute_read(struct thread
*t
)
597 static long long count
;
608 rd
= read(fd
, buf
, sizeof(buf
));
612 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
615 if (PIM_DEBUG_MROUTE
)
616 zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
617 __PRETTY_FUNCTION__
, fd
, errno
, safe_strerror(errno
));
621 result
= pim_mroute_msg(fd
, buf
, rd
);
624 if (count
% qpim_packet_process
== 0)
629 qpim_mroute_socket_reader
= NULL
;
635 static void mroute_read_on()
637 zassert(!qpim_mroute_socket_reader
);
639 THREAD_READ_ON(master
, qpim_mroute_socket_reader
,
640 mroute_read
, 0, qpim_mroute_socket_fd
);
643 static void mroute_read_off()
645 THREAD_OFF(qpim_mroute_socket_reader
);
648 int pim_mroute_socket_enable()
652 if ( pimd_privs
.change (ZPRIVS_RAISE
) )
653 zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
654 safe_strerror (errno
) );
656 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
658 if ( pimd_privs
.change (ZPRIVS_LOWER
) )
659 zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
660 safe_strerror (errno
) );
663 zlog_warn("Could not create mroute socket: errno=%d: %s",
664 errno
, safe_strerror(errno
));
668 if (pim_mroute_set(fd
, 1)) {
669 zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
670 fd
, errno
, safe_strerror(errno
));
675 qpim_mroute_socket_fd
= fd
;
677 qpim_mroute_socket_creation
= pim_time_monotonic_sec();
683 int pim_mroute_socket_disable()
685 if (pim_mroute_set(qpim_mroute_socket_fd
, 0)) {
686 zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
687 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
691 if (close(qpim_mroute_socket_fd
)) {
692 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
693 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
698 qpim_mroute_socket_fd
= -1;
704 For each network interface (e.g., physical or a virtual tunnel) that
705 would be used for multicast forwarding, a corresponding multicast
706 interface must be added to the kernel.
708 int pim_mroute_add_vif(struct interface
*ifp
, struct in_addr ifaddr
, unsigned char flags
)
710 struct pim_interface
*pim_ifp
= ifp
->info
;
714 memset(&vc
, 0, sizeof(vc
));
715 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
716 #ifdef VIFF_USE_IFINDEX
717 vc
.vifc_lcl_ifindex
= ifp
->ifindex
;
719 if (ifaddr
.s_addr
== INADDR_ANY
) {
720 zlog_warn("%s: unnumbered interfaces are not supported on this platform",
721 __PRETTY_FUNCTION__
);
724 memcpy(&vc
.vifc_lcl_addr
, &ifaddr
, sizeof(vc
.vifc_lcl_addr
));
726 vc
.vifc_flags
= flags
;
727 vc
.vifc_threshold
= PIM_MROUTE_MIN_TTL
;
728 vc
.vifc_rate_limit
= 0;
730 #ifdef PIM_DVMRP_TUNNEL
731 if (vc
.vifc_flags
& VIFF_TUNNEL
) {
732 memcpy(&vc
.vifc_rmt_addr
, &vif_remote_addr
, sizeof(vc
.vifc_rmt_addr
));
736 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_VIF
, (void*) &vc
, sizeof(vc
));
738 char ifaddr_str
[INET_ADDRSTRLEN
];
740 pim_inet4_dump("<ifaddr?>", ifaddr
, ifaddr_str
, sizeof(ifaddr_str
));
742 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
743 __FILE__
, __PRETTY_FUNCTION__
,
744 qpim_mroute_socket_fd
, ifp
->ifindex
, ifaddr_str
, flags
,
745 errno
, safe_strerror(errno
));
752 int pim_mroute_del_vif(int vif_index
)
757 if (PIM_DEBUG_MROUTE
)
759 struct interface
*ifp
= pim_if_find_by_vif_index (vif_index
);
760 zlog_debug ("%s %s: Del Vif %d (%s) ", __FILE__
,
761 __PRETTY_FUNCTION__
, vif_index
, ifp
? ifp
->name
: "NULL");
764 memset(&vc
, 0, sizeof(vc
));
765 vc
.vifc_vifi
= vif_index
;
767 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_VIF
, (void*) &vc
, sizeof(vc
));
769 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
770 __FILE__
, __PRETTY_FUNCTION__
,
771 qpim_mroute_socket_fd
, vif_index
,
772 errno
, safe_strerror(errno
));
779 int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
783 int orig_iif_vif
= 0;
785 qpim_mroute_add_last
= pim_time_monotonic_sec();
786 ++qpim_mroute_add_events
;
788 /* Do not install route if incoming interface is undefined. */
789 if (c_oil
->oil
.mfcc_parent
>= MAXVIFS
)
791 if (PIM_DEBUG_MROUTE
)
794 zlog_debug("%s(%s) %s Attempting to add vifi that is invalid to mroute table",
795 __PRETTY_FUNCTION__
, name
, pim_channel_oil_dump (c_oil
, buf
, sizeof(buf
)));
800 /* The linux kernel *expects* the incoming
801 * vif to be part of the outgoing list
802 * in the case of a (*,G).
804 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
806 orig
= c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
];
807 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = 1;
811 * If we have an unresolved cache entry for the S,G
812 * it is owned by the pimreg for the incoming IIF
813 * So set pimreg as the IIF temporarily to cause
814 * the packets to be forwarded. Then set it
815 * to the correct IIF afterwords.
817 if (!c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
818 c_oil
->oil
.mfcc_parent
!= 0)
820 orig_iif_vif
= c_oil
->oil
.mfcc_parent
;
821 c_oil
->oil
.mfcc_parent
= 0;
823 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
824 &c_oil
->oil
, sizeof(c_oil
->oil
));
826 if (!err
&& !c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
829 c_oil
->oil
.mfcc_parent
= orig_iif_vif
;
830 err
= setsockopt (qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
831 &c_oil
->oil
, sizeof (c_oil
->oil
));
834 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
835 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = orig
;
838 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
839 __FILE__
, __PRETTY_FUNCTION__
,
840 qpim_mroute_socket_fd
,
841 errno
, safe_strerror(errno
));
845 if (PIM_DEBUG_MROUTE
)
848 zlog_debug("%s(%s), Added Route: %s",
849 __PRETTY_FUNCTION__
, name
,
850 pim_channel_oil_dump (c_oil
, buf
, sizeof(buf
)));
853 c_oil
->installed
= 1;
857 int pim_mroute_del (struct channel_oil
*c_oil
, const char *name
)
861 qpim_mroute_del_last
= pim_time_monotonic_sec();
862 ++qpim_mroute_del_events
;
864 if (!c_oil
->installed
)
866 if (PIM_DEBUG_MROUTE
)
869 zlog_debug("%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
870 __FILE__
, __PRETTY_FUNCTION__
, c_oil
->oil
.mfcc_parent
,
871 pim_channel_oil_dump (c_oil
, buf
, sizeof(buf
)));
876 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_MFC
, &c_oil
->oil
, sizeof(c_oil
->oil
));
878 if (PIM_DEBUG_MROUTE
)
879 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
880 __FILE__
, __PRETTY_FUNCTION__
,
881 qpim_mroute_socket_fd
,
882 errno
, safe_strerror(errno
));
886 if (PIM_DEBUG_MROUTE
)
889 zlog_debug("%s(%s), Deleted Route: %s",
890 __PRETTY_FUNCTION__
, name
,
891 pim_channel_oil_dump (c_oil
, buf
, sizeof(buf
)));
894 //Reset kernel installed flag
895 c_oil
->installed
= 0;
901 pim_mroute_update_counters (struct channel_oil
*c_oil
)
903 struct sioc_sg_req sgreq
;
905 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
906 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
907 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
909 if (!c_oil
->installed
)
911 c_oil
->cc
.lastused
= 100 * qpim_keep_alive_time
;
912 if (PIM_DEBUG_MROUTE
)
916 sg
.src
= c_oil
->oil
.mfcc_origin
;
917 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
918 if (PIM_DEBUG_MROUTE
)
919 zlog_debug("Channel(%s) is not installed no need to collect data from kernel",
920 pim_str_sg_dump (&sg
));
925 memset (&sgreq
, 0, sizeof(sgreq
));
926 sgreq
.src
= c_oil
->oil
.mfcc_origin
;
927 sgreq
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
929 pim_zlookup_sg_statistics (c_oil
);
930 if (ioctl (qpim_mroute_socket_fd
, SIOCGETSGCNT
, &sgreq
))
932 if (PIM_DEBUG_MROUTE
)
936 sg
.src
= c_oil
->oil
.mfcc_origin
;
937 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
939 zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
940 (unsigned long)SIOCGETSGCNT
,
941 pim_str_sg_dump (&sg
),
943 safe_strerror(errno
));
948 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
949 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
950 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;