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,
35 #include "pim_mroute.h"
39 #include "pim_iface.h"
40 #include "pim_macro.h"
43 #include "pim_register.h"
44 #include "pim_ifchannel.h"
45 #include "pim_zlookup.h"
48 extern struct zebra_privs_t pimd_privs
;
50 static struct thread
*qpim_mroute_socket_reader
= NULL
;
52 static void mroute_read_on(void);
54 static int pim_mroute_set(int fd
, int enable
)
57 int opt
= enable
? MRT_INIT
: MRT_DONE
;
58 socklen_t opt_len
= sizeof(opt
);
59 int rcvbuf
= 1024 * 1024 * 8;
62 err
= setsockopt(fd
, IPPROTO_IP
, opt
, &opt
, opt_len
);
64 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
65 __FILE__
, __PRETTY_FUNCTION__
,
66 fd
, enable
? "MRT_INIT" : "MRT_DONE", opt
, errno
, safe_strerror(errno
));
70 err
= setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
, sizeof(rcvbuf
));
72 zlog_warn("%s: failure: setsockopt(fd=%d, SOL_SOCKET, %d): errno=%d: %s",
73 __PRETTY_FUNCTION__
, fd
, rcvbuf
, errno
, safe_strerror(errno
));
76 flags
= fcntl(fd
, F_GETFL
, 0);
79 zlog_warn("Could not get flags on socket fd:%d %d %s",
80 fd
, errno
, safe_strerror(errno
));
84 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
))
86 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
87 fd
, errno
, safe_strerror(errno
));
94 int upcalls
= IGMPMSG_WRVIFWHOLE
;
97 err
= setsockopt (fd
, IPPROTO_IP
, opt
, &upcalls
, sizeof (upcalls
));
100 zlog_warn ("Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
101 errno
, safe_strerror (errno
));
109 static const char *igmpmsgtype2str
[IGMPMSG_WRVIFWHOLE
+ 1] = {
117 pim_mroute_msg_nocache (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
119 struct pim_interface
*pim_ifp
= ifp
->info
;
120 struct pim_upstream
*up
;
123 struct channel_oil
*oil
;
125 rpg
= RP(msg
->im_dst
);
127 * If the incoming interface is unknown OR
128 * the Interface type is SSM we don't need to
131 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
133 (!(PIM_I_am_DR(pim_ifp
))) ||
134 (pim_ifp
->itype
== PIM_INTERFACE_SSM
))
136 if (PIM_DEBUG_MROUTE_DETAIL
)
137 zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP",
138 __PRETTY_FUNCTION__
);
143 * If we've received a multicast packet that isn't connected to
146 if (!pim_if_connected_to_source (ifp
, msg
->im_src
))
148 if (PIM_DEBUG_MROUTE_DETAIL
)
149 zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
150 __PRETTY_FUNCTION__
);
154 memset (&sg
, 0, sizeof (struct prefix_sg
));
155 sg
.src
= msg
->im_src
;
156 sg
.grp
= msg
->im_dst
;
158 oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
160 if (PIM_DEBUG_MROUTE
) {
161 zlog_debug("%s: Failure to add channel oil for %s",
163 pim_str_sg_dump (&sg
));
168 up
= pim_upstream_add (&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
, __PRETTY_FUNCTION__
);
170 if (PIM_DEBUG_MROUTE
) {
171 zlog_debug("%s: Failure to add upstream information for %s",
173 pim_str_sg_dump (&sg
));
179 * I moved this debug till after the actual add because
180 * I want to take advantage of the up->sg_str being filled in.
182 if (PIM_DEBUG_MROUTE
) {
183 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
184 __PRETTY_FUNCTION__
, up
->sg_str
);
187 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
188 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
190 up
->channel_oil
= oil
;
191 up
->channel_oil
->cc
.pktcnt
++;
192 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
193 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
194 up
->join_state
= PIM_UPSTREAM_JOINED
;
200 pim_mroute_msg_wholepkt (int fd
, struct interface
*ifp
, const char *buf
)
202 struct pim_interface
*pim_ifp
;
205 const struct ip
*ip_hdr
;
206 struct pim_upstream
*up
;
208 ip_hdr
= (const struct ip
*)buf
;
210 memset (&sg
, 0, sizeof (struct prefix_sg
));
211 sg
.src
= ip_hdr
->ip_src
;
212 sg
.grp
= ip_hdr
->ip_dst
;
214 up
= pim_upstream_find(&sg
);
216 if (PIM_DEBUG_MROUTE_DETAIL
) {
217 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
218 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
223 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
227 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
229 (!(PIM_I_am_DR(pim_ifp
))) ||
230 (pim_ifp
->itype
== PIM_INTERFACE_SSM
)) {
231 if (PIM_DEBUG_MROUTE
) {
232 zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__
);
238 * If we've received a register suppress
241 pim_register_send((uint8_t *)buf
+ sizeof(struct ip
), ntohs (ip_hdr
->ip_len
),
242 pim_ifp
->primary_address
, rpg
, 0, up
);
247 pim_mroute_msg_wrongvif (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
249 struct pim_ifchannel
*ch
;
250 struct pim_interface
*pim_ifp
;
253 memset (&sg
, 0, sizeof (struct prefix_sg
));
254 sg
.src
= msg
->im_src
;
255 sg
.grp
= msg
->im_dst
;
258 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
260 RFC 4601 4.8.2. PIM-SSM-Only Routers
262 iif is the incoming interface of the packet.
263 if (iif is in inherited_olist(S,G)) {
264 send Assert(S,G) on iif
269 if (PIM_DEBUG_MROUTE
)
270 zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
272 pim_str_sg_dump (&sg
), msg
->im_vif
);
278 if (PIM_DEBUG_MROUTE
)
279 zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
281 pim_str_sg_dump (&sg
), ifp
->name
);
285 ch
= pim_ifchannel_find(ifp
, &sg
);
287 struct prefix_sg star_g
= sg
;
288 if (PIM_DEBUG_MROUTE
)
289 zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
291 pim_str_sg_dump(&sg
), ifp
->name
);
293 star_g
.src
.s_addr
= INADDR_ANY
;
294 ch
= pim_ifchannel_find(ifp
, &star_g
);
296 if (PIM_DEBUG_MROUTE
)
297 zlog_debug("%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
299 pim_str_sg_dump(&star_g
), ifp
->name
);
305 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
307 Transitions from NoInfo State
309 An (S,G) data packet arrives on interface I, AND
310 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
311 downstream interface that is in our (S,G) outgoing interface
312 list. We optimistically assume that we will be the assert
313 winner for this (S,G), and so we transition to the "I am Assert
314 Winner" state and perform Actions A1 (below), which will
315 initiate the assert negotiation for (S,G).
318 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
319 if (PIM_DEBUG_MROUTE
) {
320 zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
322 ch
->sg_str
, ifp
->name
);
327 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
328 if (PIM_DEBUG_MROUTE
) {
329 zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
331 ch
->sg_str
, ifp
->name
);
336 if (assert_action_a1(ch
)) {
337 if (PIM_DEBUG_MROUTE
) {
338 zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
340 ch
->sg_str
, ifp
->name
);
349 pim_mroute_msg_wrvifwhole (int fd
, struct interface
*ifp
, const char *buf
)
351 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
352 struct pim_interface
*pim_ifp
;
353 struct pim_ifchannel
*ch
;
354 struct pim_upstream
*up
;
355 //struct prefix_sg star_g;
357 struct channel_oil
*oil
;
359 memset (&sg
, 0, sizeof (struct prefix_sg
));
360 sg
.src
= ip_hdr
->ip_src
;
361 sg
.grp
= ip_hdr
->ip_dst
;
363 ch
= pim_ifchannel_find(ifp
, &sg
);
366 if (PIM_DEBUG_MROUTE
)
367 zlog_debug ("WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
368 ch
->sg_str
, ifp
->name
);
373 star_g
.src
.s_addr
= INADDR_ANY
;
374 ch
= pim_ifchannel_find(ifp
, &star_g
);
377 if (PIM_DEBUG_MROUTE
)
378 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
379 pim_str_sg_dump (&star_g
), ifp
->name
);
384 up
= pim_upstream_find (&sg
);
387 struct pim_nexthop source
;
388 struct pim_rpf
*rpf
= RP (sg
.grp
);
389 if (!rpf
|| !rpf
->source_nexthop
.interface
)
392 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
394 memset (&source
, 0, sizeof (source
));
396 * If we are the fhr that means we are getting a callback during
397 * the pimreg period, so I believe we can ignore this packet
399 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
401 //No if channel, but upstream we are at the RP.
402 if (pim_nexthop_lookup (&source
, up
->upstream_register
, 0) == 0)
403 pim_register_stop_send(source
.interface
, &sg
, pim_ifp
->primary_address
, up
->upstream_register
);
404 if (!up
->channel_oil
)
405 up
->channel_oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
406 pim_upstream_inherited_olist (up
);
407 if (!up
->channel_oil
->installed
)
408 pim_mroute_add (up
->channel_oil
, __PRETTY_FUNCTION__
);
409 pim_upstream_set_sptbit (up
, ifp
);
413 if (I_am_RP (up
->sg
.grp
))
415 if (pim_nexthop_lookup (&source
, up
->upstream_register
, 0) == 0)
416 pim_register_stop_send(source
.interface
, &sg
, pim_ifp
->primary_address
, up
->upstream_register
);
417 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
419 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
420 pim_upstream_inherited_olist (up
);
421 pim_mroute_msg_wholepkt (fd
, ifp
, buf
);
427 oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
429 pim_mroute_add (oil
, __PRETTY_FUNCTION__
);
430 if (pim_if_connected_to_source (ifp
, sg
.src
))
432 up
= pim_upstream_add (&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
, __PRETTY_FUNCTION__
);
435 if (PIM_DEBUG_MROUTE
)
436 zlog_debug ("%s: WRONGVIF%s unable to create upstream on interface",
437 pim_str_sg_dump (&sg
), ifp
->name
);
440 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
441 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
442 up
->channel_oil
= oil
;
443 up
->channel_oil
->cc
.pktcnt
++;
444 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
445 up
->join_state
= PIM_UPSTREAM_JOINED
;
446 pim_upstream_inherited_olist (up
);
448 // Send the packet to the RP
449 pim_mroute_msg_wholepkt (fd
, ifp
, buf
);
455 int pim_mroute_msg(int fd
, const char *buf
, int buf_size
)
457 struct interface
*ifp
;
458 struct pim_interface
*pim_ifp
;
459 const struct ip
*ip_hdr
;
460 const struct igmpmsg
*msg
;
461 char ip_src_str
[INET_ADDRSTRLEN
] = "";
462 char ip_dst_str
[INET_ADDRSTRLEN
] = "";
463 char src_str
[INET_ADDRSTRLEN
] = "<src?>";
464 char grp_str
[INET_ADDRSTRLEN
] = "<grp?>";
465 struct in_addr ifaddr
;
466 struct igmp_sock
*igmp
;
468 ip_hdr
= (const struct ip
*) buf
;
470 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
472 /* We have the IP packet but we do not know which interface this packet was
473 * received on. Find the interface that is on the same subnet as the source
476 ifp
= pim_if_lookup_address_vrf (ip_hdr
->ip_src
, VRF_DEFAULT
);
479 if (PIM_DEBUG_MROUTE_DETAIL
) {
480 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, ip_src_str
, sizeof(ip_src_str
));
481 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, ip_dst_str
, sizeof(ip_dst_str
));
483 zlog_warn("%s: igmp kernel upcall could not find usable interface for %s -> %s",
491 ifaddr
= pim_find_primary_addr(ifp
);
492 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
494 if (PIM_DEBUG_MROUTE
) {
495 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, ip_src_str
, sizeof(ip_src_str
));
496 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, ip_dst_str
, sizeof(ip_dst_str
));
498 zlog_warn("%s: igmp kernel upcall on %s(%p) for %s -> %s",
499 __PRETTY_FUNCTION__
, ifp
->name
, igmp
, ip_src_str
, ip_dst_str
);
502 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
504 } else if (ip_hdr
->ip_p
) {
505 if (PIM_DEBUG_MROUTE_DETAIL
) {
506 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
, sizeof(src_str
));
507 pim_inet4_dump("<grp?>", ip_hdr
->ip_dst
, grp_str
, sizeof(grp_str
));
508 zlog_debug("%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
509 __PRETTY_FUNCTION__
, ip_hdr
->ip_p
, src_str
, grp_str
, buf_size
);
513 msg
= (const struct igmpmsg
*) buf
;
515 ifp
= pim_if_find_by_vif_index(msg
->im_vif
);
519 if (PIM_DEBUG_MROUTE
) {
520 pim_inet4_dump("<src?>", msg
->im_src
, src_str
, sizeof(src_str
));
521 pim_inet4_dump("<grp?>", msg
->im_dst
, grp_str
, sizeof(grp_str
));
522 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",
524 igmpmsgtype2str
[msg
->im_msgtype
],
531 msg
->im_vif
, buf_size
);
534 switch (msg
->im_msgtype
) {
535 case IGMPMSG_WRONGVIF
:
536 return pim_mroute_msg_wrongvif(fd
, ifp
, msg
);
538 case IGMPMSG_NOCACHE
:
539 return pim_mroute_msg_nocache(fd
, ifp
, msg
);
541 case IGMPMSG_WHOLEPKT
:
542 return pim_mroute_msg_wholepkt(fd
, ifp
, (const char *)msg
);
544 case IGMPMSG_WRVIFWHOLE
:
545 return pim_mroute_msg_wrvifwhole (fd
, ifp
, (const char *)msg
);
555 static int mroute_read(struct thread
*t
)
557 static long long count
;
568 rd
= read(fd
, buf
, sizeof(buf
));
572 if (errno
== EWOULDBLOCK
|| errno
== EAGAIN
)
577 if (PIM_DEBUG_MROUTE
)
578 zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
579 __PRETTY_FUNCTION__
, fd
, errno
, safe_strerror(errno
));
583 result
= pim_mroute_msg(fd
, buf
, rd
);
586 if (count
% qpim_packet_process
== 0)
591 qpim_mroute_socket_reader
= NULL
;
597 static void mroute_read_on()
599 zassert(!qpim_mroute_socket_reader
);
600 zassert(PIM_MROUTE_IS_ENABLED
);
602 THREAD_READ_ON(master
, qpim_mroute_socket_reader
,
603 mroute_read
, 0, qpim_mroute_socket_fd
);
606 static void mroute_read_off()
608 THREAD_OFF(qpim_mroute_socket_reader
);
611 int pim_mroute_socket_enable()
615 if (PIM_MROUTE_IS_ENABLED
)
618 if ( pimd_privs
.change (ZPRIVS_RAISE
) )
619 zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
620 safe_strerror (errno
) );
622 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
624 if ( pimd_privs
.change (ZPRIVS_LOWER
) )
625 zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
626 safe_strerror (errno
) );
629 zlog_warn("Could not create mroute socket: errno=%d: %s",
630 errno
, safe_strerror(errno
));
634 if (pim_mroute_set(fd
, 1)) {
635 zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
636 fd
, errno
, safe_strerror(errno
));
641 qpim_mroute_socket_fd
= fd
;
643 qpim_mroute_socket_creation
= pim_time_monotonic_sec();
649 int pim_mroute_socket_disable()
651 if (PIM_MROUTE_IS_DISABLED
)
654 if (pim_mroute_set(qpim_mroute_socket_fd
, 0)) {
655 zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
656 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
660 if (close(qpim_mroute_socket_fd
)) {
661 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
662 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
667 qpim_mroute_socket_fd
= -1;
673 For each network interface (e.g., physical or a virtual tunnel) that
674 would be used for multicast forwarding, a corresponding multicast
675 interface must be added to the kernel.
677 int pim_mroute_add_vif(struct interface
*ifp
, struct in_addr ifaddr
, unsigned char flags
)
679 struct pim_interface
*pim_ifp
= ifp
->info
;
683 if (PIM_MROUTE_IS_DISABLED
) {
684 zlog_warn("%s: global multicast is disabled",
685 __PRETTY_FUNCTION__
);
689 memset(&vc
, 0, sizeof(vc
));
690 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
691 #ifdef VIFF_USE_IFINDEX
692 vc
.vifc_lcl_ifindex
= ifp
->ifindex
;
694 if (ifaddr
.s_addr
== INADDR_ANY
) {
695 zlog_warn("%s: unnumbered interfaces are not supported on this platform",
696 __PRETTY_FUNCTION__
);
699 memcpy(&vc
.vifc_lcl_addr
, &ifaddr
, sizeof(vc
.vifc_lcl_addr
));
701 vc
.vifc_flags
= flags
;
702 vc
.vifc_threshold
= PIM_MROUTE_MIN_TTL
;
703 vc
.vifc_rate_limit
= 0;
705 #ifdef PIM_DVMRP_TUNNEL
706 if (vc
.vifc_flags
& VIFF_TUNNEL
) {
707 memcpy(&vc
.vifc_rmt_addr
, &vif_remote_addr
, sizeof(vc
.vifc_rmt_addr
));
711 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_VIF
, (void*) &vc
, sizeof(vc
));
713 char ifaddr_str
[INET_ADDRSTRLEN
];
715 pim_inet4_dump("<ifaddr?>", ifaddr
, ifaddr_str
, sizeof(ifaddr_str
));
717 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
718 __FILE__
, __PRETTY_FUNCTION__
,
719 qpim_mroute_socket_fd
, ifp
->ifindex
, ifaddr_str
, flags
,
720 errno
, safe_strerror(errno
));
727 int pim_mroute_del_vif(int vif_index
)
732 if (PIM_MROUTE_IS_DISABLED
) {
733 zlog_warn("%s: global multicast is disabled",
734 __PRETTY_FUNCTION__
);
738 memset(&vc
, 0, sizeof(vc
));
739 vc
.vifc_vifi
= vif_index
;
741 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_VIF
, (void*) &vc
, sizeof(vc
));
743 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
744 __FILE__
, __PRETTY_FUNCTION__
,
745 qpim_mroute_socket_fd
, vif_index
,
746 errno
, safe_strerror(errno
));
753 int pim_mroute_add(struct channel_oil
*c_oil
, const char *name
)
757 int orig_iif_vif
= 0;
759 qpim_mroute_add_last
= pim_time_monotonic_sec();
760 ++qpim_mroute_add_events
;
762 if (PIM_MROUTE_IS_DISABLED
) {
763 zlog_warn("%s: global multicast is disabled",
764 __PRETTY_FUNCTION__
);
768 /* The linux kernel *expects* the incoming
769 * vif to be part of the outgoing list
770 * in the case of a (*,G).
772 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
774 orig
= c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
];
775 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = 1;
779 * If we have an unresolved cache entry for the S,G
780 * it is owned by the pimreg for the incoming IIF
781 * So set pimreg as the IIF temporarily to cause
782 * the packets to be forwarded. Then set it
783 * to the correct IIF afterwords.
785 if (!c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
786 c_oil
->oil
.mfcc_parent
!= 0)
788 orig_iif_vif
= c_oil
->oil
.mfcc_parent
;
789 c_oil
->oil
.mfcc_parent
= 0;
791 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
792 &c_oil
->oil
, sizeof(c_oil
->oil
));
794 if (!err
&& !c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
797 c_oil
->oil
.mfcc_parent
= orig_iif_vif
;
798 err
= setsockopt (qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
799 &c_oil
->oil
, sizeof (c_oil
->oil
));
802 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
803 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = orig
;
806 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
807 __FILE__
, __PRETTY_FUNCTION__
,
808 qpim_mroute_socket_fd
,
809 errno
, safe_strerror(errno
));
813 if (PIM_DEBUG_MROUTE
)
817 sg
.src
= c_oil
->oil
.mfcc_origin
;
818 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
820 zlog_debug("%s(%s), Added Route: %s to mroute table",
821 __PRETTY_FUNCTION__
, name
, pim_str_sg_dump(&sg
));
824 c_oil
->installed
= 1;
828 int pim_mroute_del (struct channel_oil
*c_oil
, const char *name
)
832 qpim_mroute_del_last
= pim_time_monotonic_sec();
833 ++qpim_mroute_del_events
;
835 if (PIM_MROUTE_IS_DISABLED
) {
836 zlog_warn("%s: global multicast is disabled",
837 __PRETTY_FUNCTION__
);
841 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_MFC
, &c_oil
->oil
, sizeof(c_oil
->oil
));
843 if (PIM_DEBUG_MROUTE
)
844 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
845 __FILE__
, __PRETTY_FUNCTION__
,
846 qpim_mroute_socket_fd
,
847 errno
, safe_strerror(errno
));
851 if (PIM_DEBUG_MROUTE
)
855 sg
.src
= c_oil
->oil
.mfcc_origin
;
856 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
858 zlog_debug("%s(%s), Deleted Route: %s from mroute table",
859 __PRETTY_FUNCTION__
, name
, pim_str_sg_dump(&sg
));
861 c_oil
->installed
= 0;
867 pim_mroute_update_counters (struct channel_oil
*c_oil
)
869 struct sioc_sg_req sgreq
;
871 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
872 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
873 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
875 if (!c_oil
->installed
)
877 c_oil
->cc
.lastused
= 100 * qpim_keep_alive_time
;
878 if (PIM_DEBUG_MROUTE
)
882 sg
.src
= c_oil
->oil
.mfcc_origin
;
883 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
884 if (PIM_DEBUG_MROUTE
)
885 zlog_debug("Channel(%s) is not installed no need to collect data from kernel",
886 pim_str_sg_dump (&sg
));
891 memset (&sgreq
, 0, sizeof(sgreq
));
892 sgreq
.src
= c_oil
->oil
.mfcc_origin
;
893 sgreq
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
895 pim_zlookup_sg_statistics (c_oil
);
896 if (ioctl (qpim_mroute_socket_fd
, SIOCGETSGCNT
, &sgreq
))
898 if (PIM_DEBUG_MROUTE
)
902 sg
.src
= c_oil
->oil
.mfcc_origin
;
903 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
905 zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
906 (unsigned long)SIOCGETSGCNT
,
907 pim_str_sg_dump (&sg
),
909 safe_strerror(errno
));
914 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
915 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
916 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;