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