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