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