]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_mroute.c
pimd: don't try to check RPF for incoming SSM data
[mirror_frr.git] / pimd / pim_mroute.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * PIM for Quagga
4 * Copyright (C) 2008 Everton da Silva Marques
5 */
6
7 #include <zebra.h>
8 #include "log.h"
9 #include "privs.h"
10 #include "if.h"
11 #include "prefix.h"
12 #include "vty.h"
13 #include "plist.h"
14 #include "sockopt.h"
15 #include "lib_errors.h"
16 #include "lib/network.h"
17
18 #include "pimd.h"
19 #include "pim_rpf.h"
20 #include "pim_mroute.h"
21 #include "pim_oil.h"
22 #include "pim_str.h"
23 #include "pim_time.h"
24 #include "pim_iface.h"
25 #include "pim_macro.h"
26 #include "pim_rp.h"
27 #include "pim_oil.h"
28 #include "pim_register.h"
29 #include "pim_ifchannel.h"
30 #include "pim_zlookup.h"
31 #include "pim_ssm.h"
32 #include "pim_sock.h"
33 #include "pim_vxlan.h"
34 #include "pim_msg.h"
35
36 static void mroute_read_on(struct pim_instance *pim);
37 static int pim_upstream_mroute_update(struct channel_oil *c_oil,
38 const char *name);
39
40 int pim_mroute_set(struct pim_instance *pim, int enable)
41 {
42 int err;
43 int opt, data;
44 socklen_t data_len = sizeof(data);
45
46 /*
47 * We need to create the VRF table for the pim mroute_socket
48 */
49 if (pim->vrf->vrf_id != VRF_DEFAULT) {
50 frr_with_privs (&pimd_privs) {
51
52 data = pim->vrf->data.l.table_id;
53 err = setsockopt(pim->mroute_socket, PIM_IPPROTO,
54 MRT_TABLE, &data, data_len);
55 if (err) {
56 zlog_warn(
57 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s",
58 __FILE__, __func__, pim->mroute_socket,
59 data, errno, safe_strerror(errno));
60 return -1;
61 }
62 }
63 }
64
65 frr_with_privs (&pimd_privs) {
66 opt = enable ? MRT_INIT : MRT_DONE;
67 /*
68 * *BSD *cares* about what value we pass down
69 * here
70 */
71 data = 1;
72 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data,
73 data_len);
74 if (err) {
75 zlog_warn(
76 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
77 __FILE__, __func__, pim->mroute_socket,
78 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
79 safe_strerror(errno));
80 return -1;
81 }
82 }
83
84 #if defined(HAVE_IP_PKTINFO)
85 if (enable) {
86 /* Linux and Solaris IP_PKTINFO */
87 data = 1;
88 if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IP_PKTINFO,
89 &data, data_len)) {
90 zlog_warn(
91 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
92 pim->mroute_socket, errno,
93 safe_strerror(errno));
94 }
95 }
96 #endif
97
98 #if PIM_IPV == 6
99 if (enable) {
100 /* Linux and Solaris IPV6_PKTINFO */
101 data = 1;
102 if (setsockopt(pim->mroute_socket, PIM_IPPROTO,
103 IPV6_RECVPKTINFO, &data, data_len)) {
104 zlog_warn(
105 "Could not set IPV6_RECVPKTINFO on socket fd=%d: errno=%d: %s",
106 pim->mroute_socket, errno,
107 safe_strerror(errno));
108 }
109 }
110 #endif
111 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
112
113 if (set_nonblocking(pim->mroute_socket) < 0) {
114 zlog_warn(
115 "Could not set non blocking on socket fd=%d: errno=%d: %s",
116 pim->mroute_socket, errno, safe_strerror(errno));
117 return -1;
118 }
119
120 if (enable) {
121 #if defined linux
122 int upcalls = GMMSG_WRVIFWHOLE;
123 opt = MRT_PIM;
124
125 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls,
126 sizeof(upcalls));
127 if (err) {
128 zlog_warn(
129 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
130 errno, safe_strerror(errno));
131 return -1;
132 }
133 #else
134 zlog_warn(
135 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
136 #endif
137 }
138
139 return 0;
140 }
141
142 static const char *const gmmsgtype2str[GMMSG_WRVIFWHOLE + 1] = {
143 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
144
145
146 int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
147 {
148 struct pim_interface *pim_ifp = ifp->info;
149 struct pim_upstream *up;
150 pim_sgaddr sg;
151 bool desync = false;
152
153 memset(&sg, 0, sizeof(sg));
154 sg.src = msg->msg_im_src;
155 sg.grp = msg->msg_im_dst;
156
157 if (!pim_ifp) {
158 if (PIM_DEBUG_MROUTE)
159 zlog_debug(
160 "%s: PIM not enabled on interface, dropping packet to %pSG",
161 ifp->name, &sg);
162 return 0;
163 }
164
165 if (!pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
166 /* for ASM, check that we have enough information (i.e. path
167 * to RP) to make a decision on what to do with this packet.
168 *
169 * for SSM, this is meaningless, everything is join-driven,
170 * and for NOCACHE we need to install an empty OIL MFC entry
171 * so the kernel doesn't keep nagging us.
172 */
173 struct pim_rpf *rpg;
174
175 rpg = RP(pim_ifp->pim, msg->msg_im_dst);
176 if (!rpg) {
177 if (PIM_DEBUG_MROUTE)
178 zlog_debug("%s: no RPF for packet to %pSG",
179 ifp->name, &sg);
180 return 0;
181 }
182 if (pim_rpf_addr_is_inaddr_any(rpg)) {
183 if (PIM_DEBUG_MROUTE)
184 zlog_debug("%s: null RPF for packet to %pSG",
185 ifp->name, &sg);
186 return 0;
187 }
188 }
189
190 /*
191 * If we've received a multicast packet that isn't connected to
192 * us
193 */
194 if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) {
195 if (PIM_DEBUG_MROUTE)
196 zlog_debug(
197 "%s: incoming packet to %pSG from non-connected source",
198 ifp->name, &sg);
199 return 0;
200 }
201
202 if (!(PIM_I_am_DR(pim_ifp))) {
203 /* unlike the other debug messages, this one is further in the
204 * "normal operation" category and thus under _DETAIL
205 */
206 if (PIM_DEBUG_MROUTE_DETAIL)
207 zlog_debug(
208 "%s: not DR on interface, not forwarding traffic for %pSG",
209 ifp->name, &sg);
210
211 /*
212 * We are not the DR, but we are still receiving packets
213 * Let's blackhole those packets for the moment
214 * As that they will be coming up to the cpu
215 * and causing us to consider them.
216 *
217 * This *will* create a dangling channel_oil
218 * that I see no way to get rid of. Just noting
219 * this for future reference.
220 */
221 up = pim_upstream_find_or_add(
222 &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
223 pim_upstream_mroute_add(up->channel_oil, __func__);
224
225 return 0;
226 }
227
228 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
229 __func__);
230 if (up->channel_oil->installed) {
231 zlog_warn(
232 "%s: NOCACHE for %pSG, MFC entry disappeared - reinstalling",
233 ifp->name, &sg);
234 desync = true;
235 }
236
237 /*
238 * I moved this debug till after the actual add because
239 * I want to take advantage of the up->sg_str being filled in.
240 */
241 if (PIM_DEBUG_MROUTE) {
242 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
243 __func__, up->sg_str);
244 }
245
246 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
247 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
248
249 up->channel_oil->cc.pktcnt++;
250 // resolve mfcc_parent prior to mroute_add in channel_add_oif
251 if (up->rpf.source_nexthop.interface &&
252 *oil_parent(up->channel_oil) >= MAXVIFS) {
253 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
254 }
255 pim_register_join(up);
256 /* if we have receiver, inherit from parent */
257 pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
258
259 /* we just got NOCACHE from the kernel, so... MFC is not in the
260 * kernel for some reason or another. Try installing again.
261 */
262 if (desync)
263 pim_upstream_mroute_update(up->channel_oil, __func__);
264 return 0;
265 }
266
267 int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf,
268 size_t len)
269 {
270 struct pim_interface *pim_ifp;
271 pim_sgaddr sg;
272 struct pim_rpf *rpg;
273 const ipv_hdr *ip_hdr;
274 struct pim_upstream *up;
275
276 pim_ifp = ifp->info;
277
278 ip_hdr = (const ipv_hdr *)buf;
279
280 memset(&sg, 0, sizeof(sg));
281 sg.src = IPV_SRC(ip_hdr);
282 sg.grp = IPV_DST(ip_hdr);
283
284 up = pim_upstream_find(pim_ifp->pim, &sg);
285 if (!up) {
286 pim_sgaddr star = sg;
287 star.src = PIMADDR_ANY;
288
289 up = pim_upstream_find(pim_ifp->pim, &star);
290
291 if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) {
292 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
293 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
294 __func__, NULL);
295 if (!up) {
296 if (PIM_DEBUG_MROUTE)
297 zlog_debug(
298 "%s: Unable to create upstream information for %pSG",
299 __func__, &sg);
300 return 0;
301 }
302 pim_upstream_keep_alive_timer_start(
303 up, pim_ifp->pim->keep_alive_time);
304 pim_upstream_inherited_olist(pim_ifp->pim, up);
305 pim_upstream_update_join_desired(pim_ifp->pim, up);
306
307 if (PIM_DEBUG_MROUTE)
308 zlog_debug("%s: Creating %s upstream on LHR",
309 __func__, up->sg_str);
310 return 0;
311 }
312 if (PIM_DEBUG_MROUTE_DETAIL) {
313 zlog_debug(
314 "%s: Unable to find upstream channel WHOLEPKT%pSG",
315 __func__, &sg);
316 }
317 return 0;
318 }
319
320 if (!up->rpf.source_nexthop.interface) {
321 if (PIM_DEBUG_PIM_TRACE)
322 zlog_debug("%s: up %s RPF is not present", __func__,
323 up->sg_str);
324 return 0;
325 }
326
327 pim_ifp = up->rpf.source_nexthop.interface->info;
328
329 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
330
331 if ((pim_rpf_addr_is_inaddr_any(rpg)) || (!pim_ifp) ||
332 (!(PIM_I_am_DR(pim_ifp)))) {
333 if (PIM_DEBUG_MROUTE) {
334 zlog_debug("%s: Failed Check send packet", __func__);
335 }
336 return 0;
337 }
338
339 /*
340 * If we've received a register suppress
341 */
342 if (!up->t_rs_timer) {
343 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
344 if (PIM_DEBUG_PIM_REG)
345 zlog_debug(
346 "%pSG register forward skipped as group is SSM",
347 &sg);
348 return 0;
349 }
350
351 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
352 if (PIM_DEBUG_PIM_REG)
353 zlog_debug(
354 "%s register forward skipped, not FHR",
355 up->sg_str);
356 return 0;
357 }
358
359 pim_register_send((uint8_t *)buf + sizeof(ipv_hdr),
360 len - sizeof(ipv_hdr),
361 pim_ifp->primary_address, rpg, 0, up);
362 }
363 return 0;
364 }
365
366 int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, const kernmsg *msg)
367 {
368 struct pim_ifchannel *ch;
369 struct pim_interface *pim_ifp;
370 pim_sgaddr sg;
371
372 memset(&sg, 0, sizeof(sg));
373 sg.src = msg->msg_im_src;
374 sg.grp = msg->msg_im_dst;
375
376 /*
377 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
378
379 RFC 4601 4.8.2. PIM-SSM-Only Routers
380
381 iif is the incoming interface of the packet.
382 if (iif is in inherited_olist(S,G)) {
383 send Assert(S,G) on iif
384 }
385 */
386
387 if (!ifp) {
388 if (PIM_DEBUG_MROUTE)
389 zlog_debug(
390 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
391 __func__, &sg, msg->msg_im_vif);
392 return -1;
393 }
394
395 pim_ifp = ifp->info;
396 if (!pim_ifp) {
397 if (PIM_DEBUG_MROUTE)
398 zlog_debug(
399 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
400 __func__, &sg, ifp->name);
401 return -2;
402 }
403
404 ch = pim_ifchannel_find(ifp, &sg);
405 if (!ch) {
406 pim_sgaddr star_g = sg;
407 if (PIM_DEBUG_MROUTE)
408 zlog_debug(
409 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
410 __func__, &sg, ifp->name);
411
412 star_g.src = PIMADDR_ANY;
413 ch = pim_ifchannel_find(ifp, &star_g);
414 if (!ch) {
415 if (PIM_DEBUG_MROUTE)
416 zlog_debug(
417 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
418 __func__, &star_g, ifp->name);
419 return -3;
420 }
421 }
422
423 /*
424 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
425
426 Transitions from NoInfo State
427
428 An (S,G) data packet arrives on interface I, AND
429 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
430 downstream interface that is in our (S,G) outgoing interface
431 list. We optimistically assume that we will be the assert
432 winner for this (S,G), and so we transition to the "I am Assert
433 Winner" state and perform Actions A1 (below), which will
434 initiate the assert negotiation for (S,G).
435 */
436
437 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
438 if (PIM_DEBUG_MROUTE) {
439 zlog_debug(
440 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
441 __func__, ch->sg_str, ifp->name);
442 }
443 return -4;
444 }
445
446 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
447 if (PIM_DEBUG_MROUTE) {
448 zlog_debug(
449 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
450 __func__, ch->sg_str, ifp->name);
451 }
452 return -5;
453 }
454
455 if (assert_action_a1(ch)) {
456 if (PIM_DEBUG_MROUTE) {
457 zlog_debug(
458 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
459 __func__, ch->sg_str, ifp->name);
460 }
461 return -6;
462 }
463
464 return 0;
465 }
466
467 int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf,
468 size_t len)
469 {
470 const ipv_hdr *ip_hdr = (const ipv_hdr *)buf;
471 struct pim_interface *pim_ifp;
472 struct pim_instance *pim;
473 struct pim_ifchannel *ch;
474 struct pim_upstream *up;
475 pim_sgaddr star_g;
476 pim_sgaddr sg;
477
478 pim_ifp = ifp->info;
479
480 memset(&sg, 0, sizeof(sg));
481 sg.src = IPV_SRC(ip_hdr);
482 sg.grp = IPV_DST(ip_hdr);
483
484 ch = pim_ifchannel_find(ifp, &sg);
485 if (ch) {
486 if (PIM_DEBUG_MROUTE)
487 zlog_debug(
488 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
489 ch->sg_str, ifp->name);
490 return -1;
491 }
492
493 star_g = sg;
494 star_g.src = PIMADDR_ANY;
495
496 pim = pim_ifp->pim;
497 /*
498 * If the incoming interface is the pimreg, then
499 * we know the callback is associated with a pim register
500 * packet and there is nothing to do here as that
501 * normal pim processing will see the packet and allow
502 * us to do the right thing.
503 */
504 if (ifp == pim->regiface) {
505 return 0;
506 }
507
508 up = pim_upstream_find(pim_ifp->pim, &sg);
509 if (up) {
510 struct pim_upstream *parent;
511 struct pim_nexthop source;
512 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
513
514 /* No RPF or No RPF interface or No mcast on RPF interface */
515 if (!rpf || !rpf->source_nexthop.interface ||
516 !rpf->source_nexthop.interface->info)
517 return 0;
518
519 /*
520 * If we have received a WRVIFWHOLE and are at this
521 * point, we could be receiving the packet on the *,G
522 * tree, let's check and if so we can safely drop
523 * it.
524 */
525 parent = pim_upstream_find(pim_ifp->pim, &star_g);
526 if (parent && parent->rpf.source_nexthop.interface == ifp)
527 return 0;
528
529 pim_ifp = rpf->source_nexthop.interface->info;
530
531 memset(&source, 0, sizeof(source));
532 /*
533 * If we are the fhr that means we are getting a callback during
534 * the pimreg period, so I believe we can ignore this packet
535 */
536 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
537 /*
538 * No if channel, but upstream we are at the RP.
539 *
540 * This could be a anycast RP too and we may
541 * not have received a register packet from
542 * the source here at all. So gracefully
543 * bow out of doing a nexthop lookup and
544 * setting the SPTBIT to true
545 */
546 if (!(pim_addr_is_any(up->upstream_register)) &&
547 pim_nexthop_lookup(pim_ifp->pim, &source,
548 up->upstream_register, 0)) {
549 pim_register_stop_send(source.interface, &sg,
550 pim_ifp->primary_address,
551 up->upstream_register);
552 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
553 }
554
555 pim_upstream_inherited_olist(pim_ifp->pim, up);
556 if (!up->channel_oil->installed)
557 pim_upstream_mroute_add(up->channel_oil,
558 __func__);
559 } else {
560 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
561 if (pim_nexthop_lookup(pim_ifp->pim, &source,
562 up->upstream_register,
563 0))
564 pim_register_stop_send(
565 source.interface, &sg,
566 pim_ifp->primary_address,
567 up->upstream_register);
568 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
569 } else {
570 /*
571 * At this point pimd is connected to
572 * the source, it has a parent, we are not
573 * the RP and the SPTBIT should be set
574 * since we know *the* S,G is on the SPT.
575 * The first time this happens, let's cause
576 * an immediate join to go out so that
577 * the RP can trim this guy immediately
578 * if necessary, instead of waiting
579 * one join/prune send cycle
580 */
581 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE &&
582 up->parent &&
583 up->rpf.source_nexthop.interface !=
584 up->parent->rpf.source_nexthop
585 .interface) {
586 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
587 pim_jp_agg_single_upstream_send(
588 &up->parent->rpf, up->parent,
589 true);
590 }
591 }
592 pim_upstream_keep_alive_timer_start(
593 up, pim_ifp->pim->keep_alive_time);
594 pim_upstream_inherited_olist(pim_ifp->pim, up);
595 pim_mroute_msg_wholepkt(fd, ifp, buf, len);
596 }
597 return 0;
598 }
599
600 pim_ifp = ifp->info;
601 if (pim_if_connected_to_source(ifp, sg.src)) {
602 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
603 PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
604 NULL);
605 if (!up) {
606 if (PIM_DEBUG_MROUTE)
607 zlog_debug(
608 "%pSG: WRONGVIF%s unable to create upstream on interface",
609 &sg, ifp->name);
610 return -2;
611 }
612 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
613 pim_upstream_keep_alive_timer_start(
614 up, pim_ifp->pim->keep_alive_time);
615 up->channel_oil->cc.pktcnt++;
616 pim_register_join(up);
617 pim_upstream_inherited_olist(pim_ifp->pim, up);
618 if (!up->channel_oil->installed)
619 pim_upstream_mroute_add(up->channel_oil, __func__);
620
621 // Send the packet to the RP
622 pim_mroute_msg_wholepkt(fd, ifp, buf, len);
623 } else {
624 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
625 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
626 __func__, NULL);
627 if (!up->channel_oil->installed)
628 pim_upstream_mroute_add(up->channel_oil, __func__);
629 }
630
631 return 0;
632 }
633
634 #if PIM_IPV == 4
635 static int process_igmp_packet(struct pim_instance *pim, const char *buf,
636 size_t buf_size, ifindex_t ifindex)
637 {
638 struct interface *ifp;
639 struct pim_interface *pim_ifp;
640 struct in_addr ifaddr;
641 struct gm_sock *igmp;
642 const struct prefix *connected_src;
643 const struct ip *ip_hdr = (const struct ip *)buf;
644
645 /* We have the IP packet but we do not know which interface this
646 * packet was
647 * received on. Find the interface that is on the same subnet as
648 * the source
649 * of the IP packet.
650 */
651 ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
652
653 if (!ifp || !ifp->info)
654 return 0;
655
656 connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src);
657
658 if (!connected_src && !pim_addr_is_any(ip_hdr->ip_src)) {
659 if (PIM_DEBUG_GM_PACKETS) {
660 zlog_debug(
661 "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
662 ifp->name, &ip_hdr->ip_src);
663 }
664 return 0;
665 }
666
667 pim_ifp = ifp->info;
668 ifaddr = connected_src ? connected_src->u.prefix4
669 : pim_ifp->primary_address;
670 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
671
672 if (PIM_DEBUG_GM_PACKETS) {
673 zlog_debug(
674 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
675 __func__, pim->vrf->name, ifp->name, igmp,
676 &ip_hdr->ip_src, &ip_hdr->ip_dst);
677 }
678 if (igmp)
679 pim_igmp_packet(igmp, (char *)buf, buf_size);
680 else if (PIM_DEBUG_GM_PACKETS)
681 zlog_debug(
682 "No IGMP socket on interface: %s with connected source: %pI4",
683 ifp->name, &ifaddr);
684
685 return 0;
686 }
687 #endif
688
689 int pim_mroute_msg(struct pim_instance *pim, const char *buf, size_t buf_size,
690 ifindex_t ifindex)
691 {
692 struct interface *ifp;
693 const ipv_hdr *ip_hdr;
694 const kernmsg *msg;
695
696 if (buf_size < (int)sizeof(ipv_hdr))
697 return 0;
698
699 ip_hdr = (const ipv_hdr *)buf;
700
701 #if PIM_IPV == 4
702 if (ip_hdr->ip_p == IPPROTO_IGMP) {
703 process_igmp_packet(pim, buf, buf_size, ifindex);
704 } else if (ip_hdr->ip_p) {
705 if (PIM_DEBUG_MROUTE_DETAIL) {
706 zlog_debug(
707 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
708 __func__, ip_hdr->ip_p, &ip_hdr->ip_src,
709 &ip_hdr->ip_dst, (long int)buf_size);
710 }
711
712 } else {
713 #else
714
715 if ((ip_hdr->ip6_vfc & 0xf) == 0) {
716 #endif
717 msg = (const kernmsg *)buf;
718
719 ifp = pim_if_find_by_vif_index(pim, msg->msg_im_vif);
720
721 if (!ifp)
722 return 0;
723 if (PIM_DEBUG_MROUTE) {
724 #if PIM_IPV == 4
725 zlog_debug(
726 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld",
727 __func__, gmmsgtype2str[msg->msg_im_msgtype],
728 msg->msg_im_msgtype, ip_hdr->ip_p,
729 pim->mroute_socket, &msg->msg_im_src,
730 &msg->msg_im_dst, ifp->name, msg->msg_im_vif,
731 (long int)buf_size);
732 #else
733 zlog_debug(
734 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld",
735 __func__, gmmsgtype2str[msg->msg_im_msgtype],
736 msg->msg_im_msgtype, ip_hdr->ip6_nxt,
737 pim->mroute_socket, &msg->msg_im_src,
738 &msg->msg_im_dst, ifp->name, msg->msg_im_vif,
739 (long int)buf_size);
740 #endif
741 }
742
743 switch (msg->msg_im_msgtype) {
744 case GMMSG_WRONGVIF:
745 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
746 msg);
747 case GMMSG_NOCACHE:
748 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
749 msg);
750 case GMMSG_WHOLEPKT:
751 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
752 (const char *)msg,
753 buf_size);
754 case GMMSG_WRVIFWHOLE:
755 return pim_mroute_msg_wrvifwhole(pim->mroute_socket,
756 ifp, (const char *)msg,
757 buf_size);
758 default:
759 break;
760 }
761 }
762
763 return 0;
764 }
765
766 static void mroute_read(struct thread *t)
767 {
768 struct pim_instance *pim;
769 static long long count;
770 char buf[10000];
771 int cont = 1;
772 int rd;
773 ifindex_t ifindex;
774 pim = THREAD_ARG(t);
775
776 while (cont) {
777 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
778 sizeof(buf), NULL, NULL, NULL, NULL,
779 &ifindex);
780 if (rd <= 0) {
781 if (errno == EINTR)
782 continue;
783 if (errno == EWOULDBLOCK || errno == EAGAIN)
784 break;
785
786 zlog_warn(
787 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
788 __func__, rd, pim->mroute_socket, errno,
789 safe_strerror(errno));
790 goto done;
791 }
792
793 pim_mroute_msg(pim, buf, rd, ifindex);
794
795 count++;
796 if (count % router->packet_process == 0)
797 cont = 0;
798 }
799 /* Keep reading */
800 done:
801 mroute_read_on(pim);
802
803 return;
804 }
805
806 static void mroute_read_on(struct pim_instance *pim)
807 {
808 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
809 &pim->thread);
810 }
811
812 static void mroute_read_off(struct pim_instance *pim)
813 {
814 THREAD_OFF(pim->thread);
815 }
816
817 int pim_mroute_socket_enable(struct pim_instance *pim)
818 {
819 int fd;
820
821 frr_with_privs(&pimd_privs) {
822
823 #if PIM_IPV == 4
824 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
825 #else
826 fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
827 #endif
828 if (fd < 0) {
829 zlog_warn("Could not create mroute socket: errno=%d: %s",
830 errno,
831 safe_strerror(errno));
832 return -2;
833 }
834
835 #if PIM_IPV == 6
836 struct icmp6_filter filter[1];
837 int ret;
838
839 /* Unlike IPv4, this socket is not used for MLD, so just drop
840 * everything with an empty ICMP6 filter. Otherwise we get
841 * all kinds of garbage here, possibly even non-multicast
842 * related ICMPv6 traffic (e.g. ping)
843 *
844 * (mroute kernel upcall "packets" are injected directly on the
845 * socket, this sockopt -or any other- has no effect on them)
846 */
847 ICMP6_FILTER_SETBLOCKALL(filter);
848 ret = setsockopt(fd, SOL_ICMPV6, ICMP6_FILTER, filter,
849 sizeof(filter));
850 if (ret)
851 zlog_err(
852 "(VRF %s) failed to set mroute control filter: %m",
853 pim->vrf->name);
854 #endif
855
856 #ifdef SO_BINDTODEVICE
857 if (pim->vrf->vrf_id != VRF_DEFAULT
858 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
859 pim->vrf->name, strlen(pim->vrf->name))) {
860 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
861 safe_strerror(errno));
862 close(fd);
863 return -3;
864 }
865 #endif
866
867 }
868
869 pim->mroute_socket = fd;
870 if (pim_mroute_set(pim, 1)) {
871 zlog_warn(
872 "Could not enable mroute on socket fd=%d: errno=%d: %s",
873 fd, errno, safe_strerror(errno));
874 close(fd);
875 pim->mroute_socket = -1;
876 return -3;
877 }
878
879 pim->mroute_socket_creation = pim_time_monotonic_sec();
880
881 mroute_read_on(pim);
882
883 return 0;
884 }
885
886 int pim_mroute_socket_disable(struct pim_instance *pim)
887 {
888 if (pim_mroute_set(pim, 0)) {
889 zlog_warn(
890 "Could not disable mroute on socket fd=%d: errno=%d: %s",
891 pim->mroute_socket, errno, safe_strerror(errno));
892 return -2;
893 }
894
895 if (close(pim->mroute_socket)) {
896 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
897 pim->mroute_socket, errno, safe_strerror(errno));
898 return -3;
899 }
900
901 mroute_read_off(pim);
902 pim->mroute_socket = -1;
903
904 return 0;
905 }
906
907 /*
908 For each network interface (e.g., physical or a virtual tunnel) that
909 would be used for multicast forwarding, a corresponding multicast
910 interface must be added to the kernel.
911 */
912 int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
913 unsigned char flags)
914 {
915 struct pim_interface *pim_ifp = ifp->info;
916 pim_vifctl vc;
917 int err;
918
919 if (PIM_DEBUG_MROUTE)
920 zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
921 pim_ifp->mroute_vif_index, ifp->name,
922 pim_ifp->pim->vrf->name);
923
924 memset(&vc, 0, sizeof(vc));
925 vc.vc_vifi = pim_ifp->mroute_vif_index;
926 #if PIM_IPV == 4
927 #ifdef VIFF_USE_IFINDEX
928 vc.vc_lcl_ifindex = ifp->ifindex;
929 #else
930 if (ifaddr.s_addr == INADDR_ANY) {
931 zlog_warn(
932 "%s: unnumbered interfaces are not supported on this platform",
933 __func__);
934 return -1;
935 }
936 memcpy(&vc.vc_lcl_addr, &ifaddr, sizeof(vc.vc_lcl_addr));
937 #endif
938 #else
939 vc.vc_pifi = ifp->ifindex;
940 #endif
941 vc.vc_flags = flags;
942 vc.vc_threshold = PIM_MROUTE_MIN_TTL;
943 vc.vc_rate_limit = 0;
944
945 #if PIM_IPV == 4
946 #ifdef PIM_DVMRP_TUNNEL
947 if (vc.vc_flags & VIFF_TUNNEL) {
948 memcpy(&vc.vc_rmt_addr, &vif_remote_addr,
949 sizeof(vc.vc_rmt_addr));
950 }
951 #endif
952 #endif
953
954 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
955 (void *)&vc, sizeof(vc));
956 if (err) {
957 zlog_warn(
958 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
959 __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
960 &ifaddr, flags, errno, safe_strerror(errno));
961 return -2;
962 }
963
964 return 0;
965 }
966
967 int pim_mroute_del_vif(struct interface *ifp)
968 {
969 struct pim_interface *pim_ifp = ifp->info;
970 pim_vifctl vc;
971 int err;
972
973 if (PIM_DEBUG_MROUTE)
974 zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
975 pim_ifp->mroute_vif_index, ifp->name,
976 pim_ifp->pim->vrf->name);
977
978 memset(&vc, 0, sizeof(vc));
979 vc.vc_vifi = pim_ifp->mroute_vif_index;
980
981 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_DEL_VIF,
982 (void *)&vc, sizeof(vc));
983 if (err) {
984 zlog_warn(
985 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
986 __FILE__, __func__, pim_ifp->pim->mroute_socket,
987 pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
988 return -2;
989 }
990
991 return 0;
992 }
993
994 /*
995 * Prevent creating MFC entry with OIF=IIF.
996 *
997 * This is a protection against implementation mistakes.
998 *
999 * PIM protocol implicitely ensures loopfree multicast topology.
1000 *
1001 * IGMP must be protected against adding looped MFC entries created
1002 * by both source and receiver attached to the same interface. See
1003 * TODO T22.
1004 * We shall allow igmp to create upstream when it is DR for the intf.
1005 * Assume RP reachable via non DR.
1006 */
1007 bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
1008 int oif_index)
1009 {
1010 #ifdef PIM_ENFORCE_LOOPFREE_MFC
1011 struct interface *ifp_out;
1012 struct pim_interface *pim_ifp;
1013
1014 if (c_oil->up &&
1015 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
1016 return true;
1017
1018 ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
1019 if (!ifp_out)
1020 return false;
1021 pim_ifp = ifp_out->info;
1022 if (!pim_ifp)
1023 return false;
1024 if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_GM) &&
1025 PIM_I_am_DR(pim_ifp))
1026 return true;
1027
1028 return false;
1029 #else
1030 return true;
1031 #endif
1032 }
1033
1034 static inline void pim_mroute_copy(struct channel_oil *out,
1035 struct channel_oil *in)
1036 {
1037 int i;
1038
1039 *oil_origin(out) = *oil_origin(in);
1040 *oil_mcastgrp(out) = *oil_mcastgrp(in);
1041 *oil_parent(out) = *oil_parent(in);
1042
1043 for (i = 0; i < MAXVIFS; ++i) {
1044 if (*oil_parent(out) == i &&
1045 !pim_mroute_allow_iif_in_oil(in, i)) {
1046 oil_if_set(out, i, 0);
1047 continue;
1048 }
1049
1050 if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
1051 oil_if_set(out, i, 0);
1052 else
1053 oil_if_set(out, i, oil_if_has(in, i));
1054 }
1055 }
1056
1057 /* This function must not be called directly 0
1058 * use pim_upstream_mroute_add or pim_static_mroute_add instead
1059 */
1060 static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
1061 {
1062 struct pim_instance *pim = c_oil->pim;
1063 struct channel_oil tmp_oil[1] = { };
1064 int err;
1065
1066 pim->mroute_add_last = pim_time_monotonic_sec();
1067 ++pim->mroute_add_events;
1068
1069 /* Copy the oil to a temporary structure to fixup (without need to
1070 * later restore) before sending the mroute add to the dataplane
1071 */
1072 pim_mroute_copy(tmp_oil, c_oil);
1073
1074 /* The linux kernel *expects* the incoming
1075 * vif to be part of the outgoing list
1076 * in the case of a (*,G).
1077 */
1078 if (pim_addr_is_any(*oil_origin(c_oil))) {
1079 oil_if_set(tmp_oil, *oil_parent(c_oil), 1);
1080 }
1081
1082 /*
1083 * If we have an unresolved cache entry for the S,G
1084 * it is owned by the pimreg for the incoming IIF
1085 * So set pimreg as the IIF temporarily to cause
1086 * the packets to be forwarded. Then set it
1087 * to the correct IIF afterwords.
1088 */
1089 if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil))
1090 && *oil_parent(c_oil) != 0) {
1091 *oil_parent(tmp_oil) = 0;
1092 }
1093 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
1094 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
1095 &tmp_oil->oil, sizeof(tmp_oil->oil));
1096
1097 if (!err && !c_oil->installed
1098 && !pim_addr_is_any(*oil_origin(c_oil))
1099 && *oil_parent(c_oil) != 0) {
1100 *oil_parent(tmp_oil) = *oil_parent(c_oil);
1101 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
1102 &tmp_oil->oil, sizeof(tmp_oil->oil));
1103 }
1104
1105 if (err) {
1106 zlog_warn(
1107 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
1108 __FILE__, __func__, pim->mroute_socket, errno,
1109 safe_strerror(errno));
1110 return -2;
1111 }
1112
1113 if (PIM_DEBUG_MROUTE) {
1114 char buf[1000];
1115 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
1116 pim->vrf->name,
1117 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1118 }
1119
1120 if (!c_oil->installed) {
1121 c_oil->installed = 1;
1122 c_oil->mroute_creation = pim_time_monotonic_sec();
1123 }
1124
1125 return 0;
1126 }
1127
1128 static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
1129 const char *name)
1130 {
1131 vifi_t iif = MAXVIFS;
1132 struct interface *ifp = NULL;
1133 struct pim_interface *pim_ifp;
1134 struct pim_upstream *up = c_oil->up;
1135
1136 if (up) {
1137 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
1138 if (up->parent)
1139 ifp = up->parent->rpf.source_nexthop.interface;
1140 } else {
1141 ifp = up->rpf.source_nexthop.interface;
1142 }
1143 if (ifp) {
1144 pim_ifp = (struct pim_interface *)ifp->info;
1145 if (pim_ifp)
1146 iif = pim_ifp->mroute_vif_index;
1147 }
1148 }
1149 return iif;
1150 }
1151
1152 static int pim_upstream_mroute_update(struct channel_oil *c_oil,
1153 const char *name)
1154 {
1155 char buf[1000];
1156
1157 if (*oil_parent(c_oil) >= MAXVIFS) {
1158 /* the c_oil cannot be installed as a mroute yet */
1159 if (PIM_DEBUG_MROUTE)
1160 zlog_debug(
1161 "%s(%s) %s mroute not ready to be installed; %s",
1162 __func__, name,
1163 pim_channel_oil_dump(c_oil, buf,
1164 sizeof(buf)),
1165 c_oil->installed ?
1166 "uninstall" : "skip");
1167 /* if already installed flush it out as we are going to stop
1168 * updates to it leaving it in a stale state
1169 */
1170 if (c_oil->installed)
1171 pim_mroute_del(c_oil, name);
1172 /* return success (skipped) */
1173 return 0;
1174 }
1175
1176 return pim_mroute_add(c_oil, name);
1177 }
1178
1179 /* IIF associated with SGrpt entries are re-evaluated when the parent
1180 * (*,G) entries IIF changes
1181 */
1182 static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
1183 {
1184 struct listnode *listnode;
1185 struct pim_upstream *child;
1186
1187 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
1188 child)) {
1189 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
1190 pim_upstream_mroute_iif_update(child->channel_oil,
1191 __func__);
1192 }
1193 }
1194
1195 /* In the case of "PIM state machine" added mroutes an upstream entry
1196 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1197 */
1198 int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
1199 {
1200 vifi_t iif;
1201
1202 iif = pim_upstream_get_mroute_iif(c_oil, name);
1203
1204 if (*oil_parent(c_oil) != iif) {
1205 *oil_parent(c_oil) = iif;
1206 if (pim_addr_is_any(*oil_origin(c_oil)) &&
1207 c_oil->up)
1208 pim_upstream_all_sources_iif_update(c_oil->up);
1209 } else {
1210 *oil_parent(c_oil) = iif;
1211 }
1212
1213 return pim_upstream_mroute_update(c_oil, name);
1214 }
1215
1216 /* Look for IIF changes and update the dateplane entry only if the IIF
1217 * has changed.
1218 */
1219 int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
1220 {
1221 vifi_t iif;
1222 char buf[1000];
1223
1224 iif = pim_upstream_get_mroute_iif(c_oil, name);
1225 if (*oil_parent(c_oil) == iif) {
1226 /* no change */
1227 return 0;
1228 }
1229 *oil_parent(c_oil) = iif;
1230
1231 if (pim_addr_is_any(*oil_origin(c_oil)) &&
1232 c_oil->up)
1233 pim_upstream_all_sources_iif_update(c_oil->up);
1234
1235 if (PIM_DEBUG_MROUTE_DETAIL)
1236 zlog_debug("%s(%s) %s mroute iif update %d",
1237 __func__, name,
1238 pim_channel_oil_dump(c_oil, buf,
1239 sizeof(buf)), iif);
1240 /* XXX: is this hack needed? */
1241 c_oil->oil_inherited_rescan = 1;
1242 return pim_upstream_mroute_update(c_oil, name);
1243 }
1244
1245 int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
1246 {
1247 return pim_mroute_add(c_oil, name);
1248 }
1249
1250 void pim_static_mroute_iif_update(struct channel_oil *c_oil,
1251 int input_vif_index,
1252 const char *name)
1253 {
1254 if (*oil_parent(c_oil) == input_vif_index)
1255 return;
1256
1257 *oil_parent(c_oil) = input_vif_index;
1258 if (input_vif_index == MAXVIFS)
1259 pim_mroute_del(c_oil, name);
1260 else
1261 pim_static_mroute_add(c_oil, name);
1262 }
1263
1264 int pim_mroute_del(struct channel_oil *c_oil, const char *name)
1265 {
1266 struct pim_instance *pim = c_oil->pim;
1267 int err;
1268
1269 pim->mroute_del_last = pim_time_monotonic_sec();
1270 ++pim->mroute_del_events;
1271
1272 if (!c_oil->installed) {
1273 if (PIM_DEBUG_MROUTE) {
1274 char buf[1000];
1275 zlog_debug(
1276 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1277 __FILE__, __func__, *oil_parent(c_oil),
1278 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1279 }
1280 return -2;
1281 }
1282
1283 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_DEL_MFC,
1284 &c_oil->oil, sizeof(c_oil->oil));
1285 if (err) {
1286 if (PIM_DEBUG_MROUTE)
1287 zlog_warn(
1288 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
1289 __FILE__, __func__, pim->mroute_socket, errno,
1290 safe_strerror(errno));
1291 return -2;
1292 }
1293
1294 if (PIM_DEBUG_MROUTE) {
1295 char buf[1000];
1296 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
1297 pim->vrf->name,
1298 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1299 }
1300
1301 // Reset kernel installed flag
1302 c_oil->installed = 0;
1303
1304 return 0;
1305 }
1306
1307 void pim_mroute_update_counters(struct channel_oil *c_oil)
1308 {
1309 struct pim_instance *pim = c_oil->pim;
1310 pim_sioc_sg_req sgreq;
1311
1312 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1313 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1314 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1315
1316 if (!c_oil->installed) {
1317 c_oil->cc.lastused = 100 * pim->keep_alive_time;
1318 if (PIM_DEBUG_MROUTE) {
1319 pim_sgaddr sg;
1320
1321 sg.src = *oil_origin(c_oil);
1322 sg.grp = *oil_mcastgrp(c_oil);
1323 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1324 &sg);
1325 }
1326 return;
1327 }
1328
1329
1330 memset(&sgreq, 0, sizeof(sgreq));
1331
1332 pim_zlookup_sg_statistics(c_oil);
1333
1334 #if PIM_IPV == 4
1335 sgreq.src = *oil_origin(c_oil);
1336 sgreq.grp = *oil_mcastgrp(c_oil);
1337 #else
1338 sgreq.src = c_oil->oil.mf6cc_origin;
1339 sgreq.grp = c_oil->oil.mf6cc_mcastgrp;
1340 #endif
1341 if (ioctl(pim->mroute_socket, PIM_SIOCGETSGCNT, &sgreq)) {
1342 pim_sgaddr sg;
1343
1344 sg.src = *oil_origin(c_oil);
1345 sg.grp = *oil_mcastgrp(c_oil);
1346
1347 zlog_warn(
1348 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1349 (unsigned long)PIM_SIOCGETSGCNT, &sg, errno,
1350 safe_strerror(errno));
1351 return;
1352 }
1353
1354 c_oil->cc.pktcnt = sgreq.pktcnt;
1355 c_oil->cc.bytecnt = sgreq.bytecnt;
1356 c_oil->cc.wrong_if = sgreq.wrong_if;
1357 return;
1358 }