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