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