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