]> git.proxmox.com Git - mirror_frr.git/blame_incremental - pimd/pim_mroute.c
pimd: Fix pim to use correct src address for packets
[mirror_frr.git] / pimd / pim_mroute.c
... / ...
CommitLineData
1/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
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.
9
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.
14
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,
18 MA 02110-1301 USA
19
20*/
21
22#include <zebra.h>
23#include "log.h"
24#include "privs.h"
25#include "if.h"
26#include "prefix.h"
27
28#include "pimd.h"
29#include "pim_rpf.h"
30#include "pim_mroute.h"
31#include "pim_oil.h"
32#include "pim_str.h"
33#include "pim_time.h"
34#include "pim_iface.h"
35#include "pim_macro.h"
36#include "pim_rp.h"
37#include "pim_oil.h"
38#include "pim_register.h"
39#include "pim_ifchannel.h"
40#include "pim_zlookup.h"
41
42/* GLOBAL VARS */
43extern struct zebra_privs_t pimd_privs;
44
45static void mroute_read_on(void);
46
47static int pim_mroute_set(int fd, int enable)
48{
49 int err;
50 int opt = enable ? MRT_INIT : MRT_DONE;
51 socklen_t opt_len = sizeof(opt);
52
53 err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
54 if (err) {
55 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
56 __FILE__, __PRETTY_FUNCTION__,
57 fd, enable ? "MRT_INIT" : "MRT_DONE", opt, errno, safe_strerror(errno));
58 return -1;
59 }
60
61 if (enable)
62 {
63 int upcalls = IGMPMSG_WRVIFWHOLE;
64 opt = MRT_PIM;
65
66 err = setsockopt (fd, IPPROTO_IP, opt, &upcalls, sizeof (upcalls));
67 if (err)
68 {
69 zlog_warn ("Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
70 errno, safe_strerror (errno));
71 return -1;
72 }
73 }
74
75 return 0;
76}
77
78static int
79pim_mroute_connected_to_source (struct interface *ifp, struct in_addr src)
80{
81 struct listnode *cnode;
82 struct connected *c;
83 struct prefix p;
84
85 p.family = AF_INET;
86 p.u.prefix4 = src;
87 p.prefixlen = IPV4_MAX_BITLEN;
88
89 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
90 {
91 if ((c->address->family == AF_INET) &&
92 prefix_match (CONNECTED_PREFIX (c), &p))
93 {
94 return 1;
95 }
96 }
97
98 return 0;
99}
100
101static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
102 "<unknown_upcall?>",
103 "NOCACHE",
104 "WRONGVIF",
105 "WHOLEPKT",
106 "WRVIFWHOLE" };
107
108static int
109pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg)
110{
111 struct pim_interface *pim_ifp = ifp->info;
112 struct pim_upstream *up;
113 struct pim_rpf *rpg;
114 struct prefix_sg sg;
115
116 rpg = RP(msg->im_dst);
117 /*
118 * If the incoming interface is unknown OR
119 * the Interface type is SSM we don't need to
120 * do anything here
121 */
122 if ((rpg->rpf_addr.s_addr == INADDR_NONE) ||
123 (!pim_ifp) ||
124 (!(PIM_I_am_DR(pim_ifp))) ||
125 (pim_ifp->itype == PIM_INTERFACE_SSM))
126 return 0;
127
128 /*
129 * If we've received a multicast packet that isn't connected to
130 * us
131 */
132 if (!pim_mroute_connected_to_source (ifp, msg->im_src))
133 {
134 if (PIM_DEBUG_MROUTE_DETAIL)
135 zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
136 __PRETTY_FUNCTION__);
137 return 0;
138 }
139
140 memset (&sg, 0, sizeof (struct prefix_sg));
141 sg.src = msg->im_src;
142 sg.grp = msg->im_dst;
143
144 if (PIM_DEBUG_MROUTE) {
145 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
146 __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
147 }
148
149 up = pim_upstream_add (&sg, ifp);
150 if (!up) {
151 if (PIM_DEBUG_MROUTE) {
152 zlog_debug("%s: Failure to add upstream information for %s",
153 __PRETTY_FUNCTION__,
154 pim_str_sg_dump (&sg));
155 }
156 return 0;
157 }
158
159 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
160
161 up->channel_oil = pim_channel_oil_add(&sg,
162 pim_ifp->mroute_vif_index);
163 if (!up->channel_oil) {
164 if (PIM_DEBUG_MROUTE) {
165 zlog_debug("%s: Failure to add channel oil for %s",
166 __PRETTY_FUNCTION__,
167 pim_str_sg_dump (&sg));
168 }
169 return 0;
170 }
171 up->channel_oil->cc.pktcnt++;
172 up->fhr = 1;
173 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
174 up->join_state = PIM_UPSTREAM_JOINED;
175
176 return 0;
177}
178
179static int
180pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
181{
182 struct pim_interface *pim_ifp;
183 struct prefix_sg sg;
184 struct pim_rpf *rpg;
185 const struct ip *ip_hdr;
186 struct pim_upstream *up;
187
188 ip_hdr = (const struct ip *)buf;
189
190 memset (&sg, 0, sizeof (struct prefix_sg));
191 sg.src = ip_hdr->ip_src;
192 sg.grp = ip_hdr->ip_dst;
193
194 up = pim_upstream_find(&sg);
195 if (!up) {
196 if (PIM_DEBUG_MROUTE_DETAIL) {
197 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
198 __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
199 }
200 return 0;
201 }
202
203 pim_ifp = up->rpf.source_nexthop.interface->info;
204
205 rpg = RP(sg.grp);
206
207 if ((rpg->rpf_addr.s_addr == INADDR_NONE) ||
208 (!pim_ifp) ||
209 (!(PIM_I_am_DR(pim_ifp))) ||
210 (pim_ifp->itype == PIM_INTERFACE_SSM)) {
211 if (PIM_DEBUG_MROUTE) {
212 zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
213 }
214 return 0;
215 }
216
217 /*
218 * If we've received a register suppress
219 */
220 if (!up->t_rs_timer)
221 pim_register_send((uint8_t *)buf + sizeof(struct ip), ntohs (ip_hdr->ip_len),
222 pim_ifp->primary_address, rpg, 0);
223
224 return 0;
225}
226
227static int
228pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg)
229{
230 struct pim_ifchannel *ch;
231 struct pim_interface *pim_ifp;
232 struct prefix_sg sg;
233
234 memset (&sg, 0, sizeof (struct prefix_sg));
235 sg.src = msg->im_src;
236 sg.grp = msg->im_dst;
237
238 /*
239 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
240
241 RFC 4601 4.8.2. PIM-SSM-Only Routers
242
243 iif is the incoming interface of the packet.
244 if (iif is in inherited_olist(S,G)) {
245 send Assert(S,G) on iif
246 }
247 */
248
249 if (!ifp) {
250 if (PIM_DEBUG_MROUTE) {
251 zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
252 __PRETTY_FUNCTION__,
253 pim_str_sg_dump (&sg), msg->im_vif);
254 }
255 return -1;
256 }
257
258 pim_ifp = ifp->info;
259 if (!pim_ifp) {
260 if (PIM_DEBUG_MROUTE) {
261 zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
262 __PRETTY_FUNCTION__,
263 pim_str_sg_dump (&sg), ifp->name);
264 }
265 return -2;
266 }
267
268 ch = pim_ifchannel_find(ifp, &sg);
269 if (!ch) {
270 if (PIM_DEBUG_MROUTE) {
271 zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
272 __PRETTY_FUNCTION__,
273 pim_str_sg_dump (&sg), ifp->name);
274 }
275 return -3;
276 }
277
278 /*
279 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
280
281 Transitions from NoInfo State
282
283 An (S,G) data packet arrives on interface I, AND
284 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
285 downstream interface that is in our (S,G) outgoing interface
286 list. We optimistically assume that we will be the assert
287 winner for this (S,G), and so we transition to the "I am Assert
288 Winner" state and perform Actions A1 (below), which will
289 initiate the assert negotiation for (S,G).
290 */
291
292 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
293 if (PIM_DEBUG_MROUTE) {
294 zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
295 __PRETTY_FUNCTION__,
296 pim_str_sg_dump (&sg), ifp->name);
297 }
298 return -4;
299 }
300
301 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
302 if (PIM_DEBUG_MROUTE) {
303 zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
304 __PRETTY_FUNCTION__,
305 pim_str_sg_dump (&sg), ifp->name);
306 }
307 return -5;
308 }
309
310 if (assert_action_a1(ch)) {
311 if (PIM_DEBUG_MROUTE) {
312 zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
313 __PRETTY_FUNCTION__,
314 pim_str_sg_dump (&sg), ifp->name);
315 }
316 return -6;
317 }
318
319 return 0;
320}
321
322static int
323pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
324{
325 const struct ip *ip_hdr = (const struct ip *)buf;
326 struct pim_interface *pim_ifp;
327 struct pim_ifchannel *ch;
328 struct pim_upstream *up;
329 struct prefix_sg sg;
330
331 memset (&sg, 0, sizeof (struct prefix_sg));
332 sg.src = ip_hdr->ip_src;
333 sg.grp = ip_hdr->ip_dst;
334
335 if (PIM_DEBUG_MROUTE)
336 zlog_debug ("Received WHOLEPKT Wrong Vif for %s on %s",
337 pim_str_sg_dump (&sg), ifp->name);
338
339 ch = pim_ifchannel_find(ifp, &sg);
340 if (ch)
341 {
342 if (PIM_DEBUG_MROUTE)
343 zlog_debug ("WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
344 pim_str_sg_dump (&sg), ifp->name);
345 return -1;
346 }
347
348 if (PIM_DEBUG_MROUTE)
349 zlog_debug ("If channel: %p", ch);
350
351 up = pim_upstream_find (&sg);
352 if (up)
353 {
354 /*
355 * If we are the fhr that means we are getting a callback during
356 * the pimreg period, so I believe we can ignore this packet
357 */
358 if (!up->fhr)
359 {
360 struct pim_nexthop source;
361 struct pim_rpf *rpf = RP (sg.grp);
362 pim_ifp = rpf->source_nexthop.interface->info;
363
364 //No if channel, but upstream we are at the RP.
365 pim_nexthop_lookup (&source, up->upstream_register);
366 pim_register_stop_send(source.interface, &sg, pim_ifp->primary_address, up->upstream_register);
367 //Send S bit down the join.
368 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
369 }
370 return 0;
371 }
372
373 up = pim_upstream_add (&sg, ifp);
374
375 if (!up)
376 {
377 if (PIM_DEBUG_MROUTE)
378 zlog_debug ("%s: WRONGVIF%s unable to create upstream on interface",
379 pim_str_sg_dump (&sg), ifp->name);
380 return -2;
381 }
382
383 if (pim_mroute_connected_to_source (ifp, sg.src))
384 up->fhr = 1;
385
386 pim_ifp = ifp->info;
387 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
388 up->channel_oil = pim_channel_oil_add (&sg, pim_ifp->mroute_vif_index);
389 up->channel_oil->cc.pktcnt++;
390 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
391 up->join_state = PIM_UPSTREAM_JOINED;
392 pim_upstream_inherited_olist (up);
393
394 // Send the packet to the RP
395 pim_mroute_msg_wholepkt (fd, ifp, buf);
396
397 return 0;
398}
399
400int pim_mroute_msg(int fd, const char *buf, int buf_size)
401{
402 struct interface *ifp;
403 const struct ip *ip_hdr;
404 const struct igmpmsg *msg;
405 char src_str[100] = "<src?>";
406 char grp_str[100] = "<grp?>";
407
408 ip_hdr = (const struct ip *) buf;
409
410 /* kernel upcall must have protocol=0 */
411 if (ip_hdr->ip_p) {
412 /* this is not a kernel upcall */
413 if (PIM_DEBUG_MROUTE_DETAIL) {
414 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
415 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str, sizeof(grp_str));
416 zlog_debug("%s: not a kernel upcall proto=%d src: %s dst: %s msg_size=%d",
417 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size);
418 }
419 return 0;
420 }
421
422 msg = (const struct igmpmsg *) buf;
423
424 ifp = pim_if_find_by_vif_index(msg->im_vif);
425
426 if (PIM_DEBUG_MROUTE) {
427 pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
428 pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
429 zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
430 __PRETTY_FUNCTION__,
431 igmpmsgtype2str[msg->im_msgtype],
432 msg->im_msgtype,
433 ip_hdr->ip_p,
434 fd,
435 src_str,
436 grp_str,
437 ifp->name,
438 msg->im_vif);
439 }
440
441 switch (msg->im_msgtype) {
442 case IGMPMSG_WRONGVIF:
443 return pim_mroute_msg_wrongvif(fd, ifp, msg);
444 break;
445 case IGMPMSG_NOCACHE:
446 return pim_mroute_msg_nocache(fd, ifp, msg);
447 break;
448 case IGMPMSG_WHOLEPKT:
449 return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg);
450 break;
451 case IGMPMSG_WRVIFWHOLE:
452 return pim_mroute_msg_wrvifwhole (fd, ifp, (const char *)msg);
453 break;
454 default:
455 break;
456 }
457
458 return 0;
459}
460
461static int mroute_read_msg(int fd)
462{
463 char buf[2000];
464 int rd;
465
466 rd = read(fd, buf, sizeof(buf));
467 if (rd < 0) {
468 zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
469 __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
470 return -1;
471 }
472
473 return pim_mroute_msg(fd, buf, rd);
474}
475
476static int mroute_read(struct thread *t)
477{
478 int fd;
479 int result;
480
481 zassert(t);
482 zassert(!THREAD_ARG(t));
483
484 fd = THREAD_FD(t);
485 zassert(fd == qpim_mroute_socket_fd);
486
487 result = mroute_read_msg(fd);
488
489 /* Keep reading */
490 qpim_mroute_socket_reader = 0;
491 mroute_read_on();
492
493 return result;
494}
495
496static void mroute_read_on()
497{
498 zassert(!qpim_mroute_socket_reader);
499 zassert(PIM_MROUTE_IS_ENABLED);
500
501 THREAD_READ_ON(master, qpim_mroute_socket_reader,
502 mroute_read, 0, qpim_mroute_socket_fd);
503}
504
505static void mroute_read_off()
506{
507 THREAD_OFF(qpim_mroute_socket_reader);
508}
509
510int pim_mroute_socket_enable()
511{
512 int fd;
513
514 if (PIM_MROUTE_IS_ENABLED)
515 return -1;
516
517 if ( pimd_privs.change (ZPRIVS_RAISE) )
518 zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
519 safe_strerror (errno) );
520
521 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
522
523 if ( pimd_privs.change (ZPRIVS_LOWER) )
524 zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
525 safe_strerror (errno) );
526
527 if (fd < 0) {
528 zlog_warn("Could not create mroute socket: errno=%d: %s",
529 errno, safe_strerror(errno));
530 return -2;
531 }
532
533 if (pim_mroute_set(fd, 1)) {
534 zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
535 fd, errno, safe_strerror(errno));
536 close(fd);
537 return -3;
538 }
539
540 qpim_mroute_socket_fd = fd;
541
542 qpim_mroute_socket_creation = pim_time_monotonic_sec();
543 mroute_read_on();
544
545 return 0;
546}
547
548int pim_mroute_socket_disable()
549{
550 if (PIM_MROUTE_IS_DISABLED)
551 return -1;
552
553 if (pim_mroute_set(qpim_mroute_socket_fd, 0)) {
554 zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
555 qpim_mroute_socket_fd, errno, safe_strerror(errno));
556 return -2;
557 }
558
559 if (close(qpim_mroute_socket_fd)) {
560 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
561 qpim_mroute_socket_fd, errno, safe_strerror(errno));
562 return -3;
563 }
564
565 mroute_read_off();
566 qpim_mroute_socket_fd = -1;
567
568 return 0;
569}
570
571/*
572 For each network interface (e.g., physical or a virtual tunnel) that
573 would be used for multicast forwarding, a corresponding multicast
574 interface must be added to the kernel.
575 */
576int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned char flags)
577{
578 struct pim_interface *pim_ifp = ifp->info;
579 struct vifctl vc;
580 int err;
581
582 if (PIM_MROUTE_IS_DISABLED) {
583 zlog_warn("%s: global multicast is disabled",
584 __PRETTY_FUNCTION__);
585 return -1;
586 }
587
588 memset(&vc, 0, sizeof(vc));
589 vc.vifc_vifi = pim_ifp->mroute_vif_index;
590#ifdef VIFF_USE_IFINDEX
591 vc.vifc_lcl_ifindex = ifp->ifindex;
592#else
593 if (ifaddr.s_addr == INADDR_ANY) {
594 zlog_warn("%s: unnumbered interfaces are not supported on this platform",
595 __PRETTY_FUNCTION__);
596 return -1;
597 }
598 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
599#endif
600 vc.vifc_flags = flags;
601 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
602 vc.vifc_rate_limit = 0;
603
604#ifdef PIM_DVMRP_TUNNEL
605 if (vc.vifc_flags & VIFF_TUNNEL) {
606 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr));
607 }
608#endif
609
610 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc));
611 if (err) {
612 char ifaddr_str[100];
613
614 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, sizeof(ifaddr_str));
615
616 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
617 __FILE__, __PRETTY_FUNCTION__,
618 qpim_mroute_socket_fd, ifp->ifindex, ifaddr_str, flags,
619 errno, safe_strerror(errno));
620 return -2;
621 }
622
623 return 0;
624}
625
626int pim_mroute_del_vif(int vif_index)
627{
628 struct vifctl vc;
629 int err;
630
631 if (PIM_MROUTE_IS_DISABLED) {
632 zlog_warn("%s: global multicast is disabled",
633 __PRETTY_FUNCTION__);
634 return -1;
635 }
636
637 memset(&vc, 0, sizeof(vc));
638 vc.vifc_vifi = vif_index;
639
640 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc));
641 if (err) {
642 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
643 __FILE__, __PRETTY_FUNCTION__,
644 qpim_mroute_socket_fd, vif_index,
645 errno, safe_strerror(errno));
646 return -2;
647 }
648
649 return 0;
650}
651
652int pim_mroute_add(struct channel_oil *c_oil)
653{
654 int err;
655 int orig = 0;
656 int orig_iif_vif = 0;
657
658 qpim_mroute_add_last = pim_time_monotonic_sec();
659 ++qpim_mroute_add_events;
660
661 if (PIM_MROUTE_IS_DISABLED) {
662 zlog_warn("%s: global multicast is disabled",
663 __PRETTY_FUNCTION__);
664 return -1;
665 }
666
667 /* The linux kernel *expects* the incoming
668 * vif to be part of the outgoing list
669 * in the case of a (*,G).
670 */
671 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
672 {
673 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
674 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
675 }
676
677 /*
678 * If we have an unresolved cache entry for the S,G
679 * it is owned by the pimreg for the incoming IIF
680 * So set pimreg as the IIF temporarily to cause
681 * the packets to be forwarded. Then set it
682 * to the correct IIF afterwords.
683 */
684 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY &&
685 c_oil->oil.mfcc_parent != 0)
686 {
687 orig_iif_vif = c_oil->oil.mfcc_parent;
688 c_oil->oil.mfcc_parent = 0;
689 }
690 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
691 &c_oil->oil, sizeof(c_oil->oil));
692
693 if (!err && !c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY &&
694 orig_iif_vif != 0)
695 {
696 c_oil->oil.mfcc_parent = orig_iif_vif;
697 err = setsockopt (qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
698 &c_oil->oil, sizeof (c_oil->oil));
699 }
700
701 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
702 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
703
704 if (err) {
705 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
706 __FILE__, __PRETTY_FUNCTION__,
707 qpim_mroute_socket_fd,
708 errno, safe_strerror(errno));
709 return -2;
710 }
711
712 c_oil->installed = 1;
713 return 0;
714}
715
716int pim_mroute_del (struct channel_oil *c_oil)
717{
718 int err;
719
720 qpim_mroute_del_last = pim_time_monotonic_sec();
721 ++qpim_mroute_del_events;
722
723 if (PIM_MROUTE_IS_DISABLED) {
724 zlog_warn("%s: global multicast is disabled",
725 __PRETTY_FUNCTION__);
726 return -1;
727 }
728
729 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil));
730 if (err) {
731 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
732 __FILE__, __PRETTY_FUNCTION__,
733 qpim_mroute_socket_fd,
734 errno, safe_strerror(errno));
735 return -2;
736 }
737
738 c_oil->installed = 0;
739
740 return 0;
741}
742
743void
744pim_mroute_update_counters (struct channel_oil *c_oil)
745{
746 struct sioc_sg_req sgreq;
747
748 memset (&sgreq, 0, sizeof(sgreq));
749 sgreq.src = c_oil->oil.mfcc_origin;
750 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
751
752 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
753 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
754 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
755 c_oil->cc.oldlastused = c_oil->cc.lastused;
756
757 if (ioctl (qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq))
758 {
759 char group_str[100];
760 char source_str[100];
761
762 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
763 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
764
765 zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s",
766 (unsigned long)SIOCGETSGCNT,
767 source_str,
768 group_str,
769 errno,
770 safe_strerror(errno));
771 return;
772 }
773
774 pim_zlookup_sg_statistics (c_oil);
775 c_oil->cc.pktcnt = sgreq.pktcnt;
776 c_oil->cc.bytecnt = sgreq.bytecnt;
777 c_oil->cc.wrong_if = sgreq.wrong_if;
778
779 return;
780}