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,
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 extern struct zebra_privs_t pimd_privs
;
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
);
55 err
= setsockopt(fd
, IPPROTO_IP
, opt
, &opt
, opt_len
);
57 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
58 __FILE__
, __PRETTY_FUNCTION__
,
59 fd
, enable
? "MRT_INIT" : "MRT_DONE", opt
, errno
, safe_strerror(errno
));
65 int upcalls
= IGMPMSG_WRVIFWHOLE
;
68 err
= setsockopt (fd
, IPPROTO_IP
, opt
, &upcalls
, sizeof (upcalls
));
71 zlog_warn ("Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
72 errno
, safe_strerror (errno
));
80 static const char *igmpmsgtype2str
[IGMPMSG_WRVIFWHOLE
+ 1] = {
88 pim_mroute_msg_nocache (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
90 struct pim_interface
*pim_ifp
= ifp
->info
;
91 struct pim_upstream
*up
;
94 struct channel_oil
*oil
;
96 rpg
= RP(msg
->im_dst
);
98 * If the incoming interface is unknown OR
99 * the Interface type is SSM we don't need to
102 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
104 (!(PIM_I_am_DR(pim_ifp
))) ||
105 (pim_ifp
->itype
== PIM_INTERFACE_SSM
))
109 * If we've received a multicast packet that isn't connected to
112 if (!pim_if_connected_to_source (ifp
, msg
->im_src
))
114 if (PIM_DEBUG_MROUTE_DETAIL
)
115 zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
116 __PRETTY_FUNCTION__
);
120 memset (&sg
, 0, sizeof (struct prefix_sg
));
121 sg
.src
= msg
->im_src
;
122 sg
.grp
= msg
->im_dst
;
124 if (PIM_DEBUG_MROUTE
) {
125 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
126 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
129 oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
131 if (PIM_DEBUG_MROUTE
) {
132 zlog_debug("%s: Failure to add channel oil for %s",
134 pim_str_sg_dump (&sg
));
139 up
= pim_upstream_add (&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
, __PRETTY_FUNCTION__
);
141 if (PIM_DEBUG_MROUTE
) {
142 zlog_debug("%s: Failure to add upstream information for %s",
144 pim_str_sg_dump (&sg
));
148 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
149 PIM_UPSTREAM_FLAG_SET_CREATED_BY_UPSTREAM(up
->flags
);
151 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
153 up
->channel_oil
= oil
;
154 up
->channel_oil
->cc
.pktcnt
++;
155 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
156 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
157 up
->join_state
= PIM_UPSTREAM_JOINED
;
163 pim_mroute_msg_wholepkt (int fd
, struct interface
*ifp
, const char *buf
)
165 struct pim_interface
*pim_ifp
;
168 const struct ip
*ip_hdr
;
169 struct pim_upstream
*up
;
171 ip_hdr
= (const struct ip
*)buf
;
173 memset (&sg
, 0, sizeof (struct prefix_sg
));
174 sg
.src
= ip_hdr
->ip_src
;
175 sg
.grp
= ip_hdr
->ip_dst
;
177 up
= pim_upstream_find(&sg
);
179 if (PIM_DEBUG_MROUTE_DETAIL
) {
180 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
181 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
186 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
190 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
192 (!(PIM_I_am_DR(pim_ifp
))) ||
193 (pim_ifp
->itype
== PIM_INTERFACE_SSM
)) {
194 if (PIM_DEBUG_MROUTE
) {
195 zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__
);
201 * If we've received a register suppress
204 pim_register_send((uint8_t *)buf
+ sizeof(struct ip
), ntohs (ip_hdr
->ip_len
),
205 pim_ifp
->primary_address
, rpg
, 0);
211 pim_mroute_msg_wrongvif (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
213 struct pim_ifchannel
*ch
;
214 struct pim_interface
*pim_ifp
;
217 memset (&sg
, 0, sizeof (struct prefix_sg
));
218 sg
.src
= msg
->im_src
;
219 sg
.grp
= msg
->im_dst
;
222 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
224 RFC 4601 4.8.2. PIM-SSM-Only Routers
226 iif is the incoming interface of the packet.
227 if (iif is in inherited_olist(S,G)) {
228 send Assert(S,G) on iif
233 if (PIM_DEBUG_MROUTE
) {
234 zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
236 pim_str_sg_dump (&sg
), msg
->im_vif
);
243 if (PIM_DEBUG_MROUTE
) {
244 zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
246 pim_str_sg_dump (&sg
), ifp
->name
);
251 ch
= pim_ifchannel_find(ifp
, &sg
);
253 if (PIM_DEBUG_MROUTE
) {
254 zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
256 pim_str_sg_dump (&sg
), ifp
->name
);
262 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
264 Transitions from NoInfo State
266 An (S,G) data packet arrives on interface I, AND
267 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
268 downstream interface that is in our (S,G) outgoing interface
269 list. We optimistically assume that we will be the assert
270 winner for this (S,G), and so we transition to the "I am Assert
271 Winner" state and perform Actions A1 (below), which will
272 initiate the assert negotiation for (S,G).
275 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
276 if (PIM_DEBUG_MROUTE
) {
277 zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
279 pim_str_sg_dump (&sg
), ifp
->name
);
284 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
285 if (PIM_DEBUG_MROUTE
) {
286 zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
288 pim_str_sg_dump (&sg
), ifp
->name
);
293 if (assert_action_a1(ch
)) {
294 if (PIM_DEBUG_MROUTE
) {
295 zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
297 pim_str_sg_dump (&sg
), ifp
->name
);
306 pim_mroute_msg_wrvifwhole (int fd
, struct interface
*ifp
, const char *buf
)
308 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
309 struct pim_interface
*pim_ifp
;
310 struct pim_ifchannel
*ch
;
311 struct pim_upstream
*up
;
313 struct channel_oil
*oil
;
315 memset (&sg
, 0, sizeof (struct prefix_sg
));
316 sg
.src
= ip_hdr
->ip_src
;
317 sg
.grp
= ip_hdr
->ip_dst
;
319 if (PIM_DEBUG_MROUTE
)
320 zlog_debug ("Received WHOLEPKT Wrong Vif for %s on %s",
321 pim_str_sg_dump (&sg
), ifp
->name
);
323 ch
= pim_ifchannel_find(ifp
, &sg
);
326 if (PIM_DEBUG_MROUTE
)
327 zlog_debug ("WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
328 pim_str_sg_dump (&sg
), ifp
->name
);
332 if (PIM_DEBUG_MROUTE
)
333 zlog_debug ("If channel: %p", ch
);
335 up
= pim_upstream_find (&sg
);
338 struct pim_nexthop source
;
339 struct pim_rpf
*rpf
= RP (sg
.grp
);
340 if (!rpf
|| !rpf
->source_nexthop
.interface
)
343 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
345 memset (&source
, 0, sizeof (source
));
347 * If we are the fhr that means we are getting a callback during
348 * the pimreg period, so I believe we can ignore this packet
350 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
352 //No if channel, but upstream we are at the RP.
353 if (pim_nexthop_lookup (&source
, up
->upstream_register
, 0) == 0)
354 pim_register_stop_send(source
.interface
, &sg
, pim_ifp
->primary_address
, up
->upstream_register
);
355 if (!up
->channel_oil
)
356 up
->channel_oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
357 pim_upstream_inherited_olist (up
);
358 if (!up
->channel_oil
->installed
)
359 pim_mroute_add (up
->channel_oil
);
360 pim_upstream_set_sptbit (up
, ifp
);
364 if (I_am_RP (up
->sg
.grp
))
366 if (pim_nexthop_lookup (&source
, up
->upstream_register
, 0) == 0)
367 pim_register_stop_send(source
.interface
, &sg
, pim_ifp
->primary_address
, up
->upstream_register
);
368 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
370 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
371 pim_upstream_inherited_olist (up
);
372 pim_mroute_msg_wholepkt (fd
, ifp
, buf
);
378 oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
380 pim_mroute_add (oil
);
381 if (pim_if_connected_to_source (ifp
, sg
.src
))
383 up
= pim_upstream_add (&sg
, ifp
, PIM_UPSTREAM_FLAG_MASK_FHR
, __PRETTY_FUNCTION__
);
386 if (PIM_DEBUG_MROUTE
)
387 zlog_debug ("%s: WRONGVIF%s unable to create upstream on interface",
388 pim_str_sg_dump (&sg
), ifp
->name
);
391 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
392 PIM_UPSTREAM_FLAG_SET_CREATED_BY_UPSTREAM(up
->flags
);
394 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
395 up
->channel_oil
= oil
;
396 up
->channel_oil
->cc
.pktcnt
++;
397 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
398 up
->join_state
= PIM_UPSTREAM_JOINED
;
399 pim_upstream_inherited_olist (up
);
401 // Send the packet to the RP
402 pim_mroute_msg_wholepkt (fd
, ifp
, buf
);
408 int pim_mroute_msg(int fd
, const char *buf
, int buf_size
)
410 struct interface
*ifp
;
411 struct pim_interface
*pim_ifp
;
412 const struct ip
*ip_hdr
;
413 const struct igmpmsg
*msg
;
414 char ip_src_str
[INET_ADDRSTRLEN
] = "";
415 char ip_dst_str
[INET_ADDRSTRLEN
] = "";
416 char src_str
[INET_ADDRSTRLEN
] = "<src?>";
417 char grp_str
[INET_ADDRSTRLEN
] = "<grp?>";
418 struct in_addr ifaddr
;
419 struct igmp_sock
*igmp
;
421 ip_hdr
= (const struct ip
*) buf
;
423 if (ip_hdr
->ip_p
== IPPROTO_IGMP
) {
425 /* We have the IP packet but we do not know which interface this packet was
426 * received on. Find the interface that is on the same subnet as the source
429 ifp
= pim_if_lookup_address_vrf (ip_hdr
->ip_src
, VRF_DEFAULT
);
432 if (PIM_DEBUG_MROUTE_DETAIL
) {
433 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, ip_src_str
, sizeof(ip_src_str
));
434 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, ip_dst_str
, sizeof(ip_dst_str
));
436 zlog_warn("%s: igmp kernel upcall could not find usable interface for %s -> %s",
444 ifaddr
= pim_find_primary_addr(ifp
);
445 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
, ifaddr
);
447 if (PIM_DEBUG_MROUTE
) {
448 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, ip_src_str
, sizeof(ip_src_str
));
449 pim_inet4_dump("<dst?>", ip_hdr
->ip_dst
, ip_dst_str
, sizeof(ip_dst_str
));
451 zlog_warn("%s: igmp kernel upcall on %s(%p) for %s -> %s",
452 __PRETTY_FUNCTION__
, ifp
->name
, igmp
, ip_src_str
, ip_dst_str
);
455 pim_igmp_packet(igmp
, (char *)buf
, buf_size
);
457 } else if (ip_hdr
->ip_p
) {
458 if (PIM_DEBUG_MROUTE_DETAIL
) {
459 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
, sizeof(src_str
));
460 pim_inet4_dump("<grp?>", ip_hdr
->ip_dst
, grp_str
, sizeof(grp_str
));
461 zlog_debug("%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
462 __PRETTY_FUNCTION__
, ip_hdr
->ip_p
, src_str
, grp_str
, buf_size
);
466 msg
= (const struct igmpmsg
*) buf
;
468 ifp
= pim_if_find_by_vif_index(msg
->im_vif
);
470 if (PIM_DEBUG_MROUTE
) {
471 pim_inet4_dump("<src?>", msg
->im_src
, src_str
, sizeof(src_str
));
472 pim_inet4_dump("<grp?>", msg
->im_dst
, grp_str
, sizeof(grp_str
));
473 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",
475 igmpmsgtype2str
[msg
->im_msgtype
],
482 msg
->im_vif
, buf_size
);
485 switch (msg
->im_msgtype
) {
486 case IGMPMSG_WRONGVIF
:
487 return pim_mroute_msg_wrongvif(fd
, ifp
, msg
);
489 case IGMPMSG_NOCACHE
:
490 return pim_mroute_msg_nocache(fd
, ifp
, msg
);
492 case IGMPMSG_WHOLEPKT
:
493 return pim_mroute_msg_wholepkt(fd
, ifp
, (const char *)msg
);
495 case IGMPMSG_WRVIFWHOLE
:
496 return pim_mroute_msg_wrvifwhole (fd
, ifp
, (const char *)msg
);
506 static int mroute_read_msg(int fd
)
511 rd
= read(fd
, buf
, sizeof(buf
));
513 zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
514 __PRETTY_FUNCTION__
, fd
, errno
, safe_strerror(errno
));
518 return pim_mroute_msg(fd
, buf
, rd
);
521 static int mroute_read(struct thread
*t
)
527 zassert(!THREAD_ARG(t
));
530 zassert(fd
== qpim_mroute_socket_fd
);
532 result
= mroute_read_msg(fd
);
535 qpim_mroute_socket_reader
= 0;
541 static void mroute_read_on()
543 zassert(!qpim_mroute_socket_reader
);
544 zassert(PIM_MROUTE_IS_ENABLED
);
546 THREAD_READ_ON(master
, qpim_mroute_socket_reader
,
547 mroute_read
, 0, qpim_mroute_socket_fd
);
550 static void mroute_read_off()
552 THREAD_OFF(qpim_mroute_socket_reader
);
555 int pim_mroute_socket_enable()
559 if (PIM_MROUTE_IS_ENABLED
)
562 if ( pimd_privs
.change (ZPRIVS_RAISE
) )
563 zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
564 safe_strerror (errno
) );
566 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
568 if ( pimd_privs
.change (ZPRIVS_LOWER
) )
569 zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
570 safe_strerror (errno
) );
573 zlog_warn("Could not create mroute socket: errno=%d: %s",
574 errno
, safe_strerror(errno
));
578 if (pim_mroute_set(fd
, 1)) {
579 zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
580 fd
, errno
, safe_strerror(errno
));
585 qpim_mroute_socket_fd
= fd
;
587 qpim_mroute_socket_creation
= pim_time_monotonic_sec();
593 int pim_mroute_socket_disable()
595 if (PIM_MROUTE_IS_DISABLED
)
598 if (pim_mroute_set(qpim_mroute_socket_fd
, 0)) {
599 zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
600 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
604 if (close(qpim_mroute_socket_fd
)) {
605 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
606 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
611 qpim_mroute_socket_fd
= -1;
617 For each network interface (e.g., physical or a virtual tunnel) that
618 would be used for multicast forwarding, a corresponding multicast
619 interface must be added to the kernel.
621 int pim_mroute_add_vif(struct interface
*ifp
, struct in_addr ifaddr
, unsigned char flags
)
623 struct pim_interface
*pim_ifp
= ifp
->info
;
627 if (PIM_MROUTE_IS_DISABLED
) {
628 zlog_warn("%s: global multicast is disabled",
629 __PRETTY_FUNCTION__
);
633 memset(&vc
, 0, sizeof(vc
));
634 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
635 #ifdef VIFF_USE_IFINDEX
636 vc
.vifc_lcl_ifindex
= ifp
->ifindex
;
638 if (ifaddr
.s_addr
== INADDR_ANY
) {
639 zlog_warn("%s: unnumbered interfaces are not supported on this platform",
640 __PRETTY_FUNCTION__
);
643 memcpy(&vc
.vifc_lcl_addr
, &ifaddr
, sizeof(vc
.vifc_lcl_addr
));
645 vc
.vifc_flags
= flags
;
646 vc
.vifc_threshold
= PIM_MROUTE_MIN_TTL
;
647 vc
.vifc_rate_limit
= 0;
649 #ifdef PIM_DVMRP_TUNNEL
650 if (vc
.vifc_flags
& VIFF_TUNNEL
) {
651 memcpy(&vc
.vifc_rmt_addr
, &vif_remote_addr
, sizeof(vc
.vifc_rmt_addr
));
655 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_VIF
, (void*) &vc
, sizeof(vc
));
657 char ifaddr_str
[INET_ADDRSTRLEN
];
659 pim_inet4_dump("<ifaddr?>", ifaddr
, ifaddr_str
, sizeof(ifaddr_str
));
661 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
662 __FILE__
, __PRETTY_FUNCTION__
,
663 qpim_mroute_socket_fd
, ifp
->ifindex
, ifaddr_str
, flags
,
664 errno
, safe_strerror(errno
));
671 int pim_mroute_del_vif(int vif_index
)
676 if (PIM_MROUTE_IS_DISABLED
) {
677 zlog_warn("%s: global multicast is disabled",
678 __PRETTY_FUNCTION__
);
682 memset(&vc
, 0, sizeof(vc
));
683 vc
.vifc_vifi
= vif_index
;
685 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_VIF
, (void*) &vc
, sizeof(vc
));
687 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
688 __FILE__
, __PRETTY_FUNCTION__
,
689 qpim_mroute_socket_fd
, vif_index
,
690 errno
, safe_strerror(errno
));
697 int pim_mroute_add(struct channel_oil
*c_oil
)
701 int orig_iif_vif
= 0;
703 qpim_mroute_add_last
= pim_time_monotonic_sec();
704 ++qpim_mroute_add_events
;
706 if (PIM_MROUTE_IS_DISABLED
) {
707 zlog_warn("%s: global multicast is disabled",
708 __PRETTY_FUNCTION__
);
712 /* The linux kernel *expects* the incoming
713 * vif to be part of the outgoing list
714 * in the case of a (*,G).
716 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
718 orig
= c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
];
719 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = 1;
723 * If we have an unresolved cache entry for the S,G
724 * it is owned by the pimreg for the incoming IIF
725 * So set pimreg as the IIF temporarily to cause
726 * the packets to be forwarded. Then set it
727 * to the correct IIF afterwords.
729 if (!c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
730 c_oil
->oil
.mfcc_parent
!= 0)
732 orig_iif_vif
= c_oil
->oil
.mfcc_parent
;
733 c_oil
->oil
.mfcc_parent
= 0;
735 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
736 &c_oil
->oil
, sizeof(c_oil
->oil
));
738 if (!err
&& !c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
741 c_oil
->oil
.mfcc_parent
= orig_iif_vif
;
742 err
= setsockopt (qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
743 &c_oil
->oil
, sizeof (c_oil
->oil
));
746 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
747 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = orig
;
750 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
751 __FILE__
, __PRETTY_FUNCTION__
,
752 qpim_mroute_socket_fd
,
753 errno
, safe_strerror(errno
));
757 c_oil
->installed
= 1;
761 int pim_mroute_del (struct channel_oil
*c_oil
)
765 qpim_mroute_del_last
= pim_time_monotonic_sec();
766 ++qpim_mroute_del_events
;
768 if (PIM_MROUTE_IS_DISABLED
) {
769 zlog_warn("%s: global multicast is disabled",
770 __PRETTY_FUNCTION__
);
774 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_MFC
, &c_oil
->oil
, sizeof(c_oil
->oil
));
776 if (PIM_DEBUG_MROUTE
)
777 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
778 __FILE__
, __PRETTY_FUNCTION__
,
779 qpim_mroute_socket_fd
,
780 errno
, safe_strerror(errno
));
784 c_oil
->installed
= 0;
790 pim_mroute_update_counters (struct channel_oil
*c_oil
)
792 struct sioc_sg_req sgreq
;
794 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
795 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
796 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
798 if (!c_oil
->installed
)
800 c_oil
->cc
.lastused
= 100 * qpim_keep_alive_time
;
801 if (PIM_DEBUG_MROUTE
)
805 sg
.src
= c_oil
->oil
.mfcc_origin
;
806 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
807 if (PIM_DEBUG_MROUTE
)
808 zlog_debug("Channel(%s) is not installed no need to collect data from kernel",
809 pim_str_sg_dump (&sg
));
814 memset (&sgreq
, 0, sizeof(sgreq
));
815 sgreq
.src
= c_oil
->oil
.mfcc_origin
;
816 sgreq
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
818 pim_zlookup_sg_statistics (c_oil
);
819 if (ioctl (qpim_mroute_socket_fd
, SIOCGETSGCNT
, &sgreq
))
821 if (PIM_DEBUG_MROUTE
)
825 sg
.src
= c_oil
->oil
.mfcc_origin
;
826 sg
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
828 zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
829 (unsigned long)SIOCGETSGCNT
,
830 pim_str_sg_dump (&sg
),
832 safe_strerror(errno
));
837 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
838 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
839 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;