]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
pimd: Ignore igmp queries from itself
[mirror_frr.git] / pimd / pim_mroute.c
CommitLineData
12e41d03 1/*
896014f4
DL
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 along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
12e41d03
DL
19
20#include <zebra.h>
21#include "log.h"
22#include "privs.h"
744d91b3 23#include "if.h"
065bee4b 24#include "prefix.h"
dfe43e25
DW
25#include "vty.h"
26#include "plist.h"
fe232c19 27#include "sockopt.h"
3613d898 28#include "lib_errors.h"
12e41d03
DL
29
30#include "pimd.h"
8e38a2cf 31#include "pim_rpf.h"
12e41d03 32#include "pim_mroute.h"
37653d4f 33#include "pim_oil.h"
12e41d03
DL
34#include "pim_str.h"
35#include "pim_time.h"
36#include "pim_iface.h"
37#include "pim_macro.h"
c8ae3ce8 38#include "pim_rp.h"
59471fb8 39#include "pim_oil.h"
998af219 40#include "pim_register.h"
56638739 41#include "pim_ifchannel.h"
e3be0432 42#include "pim_zlookup.h"
15a5dafe 43#include "pim_ssm.h"
2002dcdb 44#include "pim_sock.h"
37c3fd98 45#include "pim_vxlan.h"
12e41d03 46
8ea5d944 47static void mroute_read_on(struct pim_instance *pim);
12e41d03 48
cdbfaec5 49static int pim_mroute_set(struct pim_instance *pim, int enable)
12e41d03 50{
d62a17ae 51 int err;
e5a2ebe6
DS
52 int opt, data;
53 socklen_t data_len = sizeof(data);
d62a17ae 54 long flags;
55
cdbfaec5
DS
56 /*
57 * We need to create the VRF table for the pim mroute_socket
58 */
59 if (pim->vrf_id != VRF_DEFAULT) {
0cf6db21 60 frr_with_privs(&pimd_privs) {
f507c196 61
e5a2ebe6 62 data = pim->vrf->data.l.table_id;
01b9e3fd
DL
63 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
64 MRT_TABLE,
e5a2ebe6 65 &data, data_len);
01b9e3fd
DL
66 if (err) {
67 zlog_warn(
68 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
69 __FILE__, __PRETTY_FUNCTION__,
e5a2ebe6 70 pim->mroute_socket, data, errno,
01b9e3fd
DL
71 safe_strerror(errno));
72 return -1;
73 }
f507c196 74
01b9e3fd 75 }
f507c196
DS
76 }
77
0cf6db21 78 frr_with_privs(&pimd_privs) {
f0b009a4 79 opt = enable ? MRT_INIT : MRT_DONE;
e5a2ebe6
DS
80 /*
81 * *BSD *cares* about what value we pass down
82 * here
83 */
84 data = 1;
f0b009a4 85 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
e5a2ebe6 86 opt, &data, data_len);
f0b009a4
DS
87 if (err) {
88 zlog_warn(
89 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
90 __FILE__, __PRETTY_FUNCTION__,
91 pim->mroute_socket,
e5a2ebe6 92 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
f0b009a4
DS
93 safe_strerror(errno));
94 return -1;
95 }
cdbfaec5
DS
96 }
97
466e4e5b
DS
98#if defined(HAVE_IP_PKTINFO)
99 if (enable) {
100 /* Linux and Solaris IP_PKTINFO */
e5a2ebe6
DS
101 data = 1;
102 if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
103 &data, data_len)) {
466e4e5b
DS
104 zlog_warn(
105 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
106 pim->mroute_socket, errno,
107 safe_strerror(errno));
108 }
109 }
110#endif
111
cdbfaec5 112 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
d62a17ae 113
cdbfaec5 114 flags = fcntl(pim->mroute_socket, F_GETFL, 0);
d62a17ae 115 if (flags < 0) {
cdbfaec5
DS
116 zlog_warn("Could not get flags on socket fd:%d %d %s",
117 pim->mroute_socket, errno, safe_strerror(errno));
118 close(pim->mroute_socket);
d62a17ae 119 return -1;
120 }
cdbfaec5
DS
121 if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
122 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
123 pim->mroute_socket, errno, safe_strerror(errno));
124 close(pim->mroute_socket);
d62a17ae 125 return -1;
126 }
127
128 if (enable) {
77b7d90b 129#if defined linux
d62a17ae 130 int upcalls = IGMPMSG_WRVIFWHOLE;
131 opt = MRT_PIM;
132
cdbfaec5 133 err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
d62a17ae 134 sizeof(upcalls));
135 if (err) {
136 zlog_warn(
137 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
138 errno, safe_strerror(errno));
139 return -1;
140 }
77b7d90b 141#else
d62a17ae 142 zlog_warn(
143 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
77b7d90b 144#endif
d62a17ae 145 }
146
147 return 0;
12e41d03
DL
148}
149
08e1fe76 150static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
d62a17ae 151 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
152
153static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
154 const struct igmpmsg *msg)
12e41d03 155{
d62a17ae 156 struct pim_interface *pim_ifp = ifp->info;
157 struct pim_upstream *up;
158 struct pim_rpf *rpg;
159 struct prefix_sg sg;
160
b575a12c 161 rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
d62a17ae 162 /*
163 * If the incoming interface is unknown OR
164 * the Interface type is SSM we don't need to
165 * do anything here
166 */
b5469d02 167 if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) {
d62a17ae 168 if (PIM_DEBUG_MROUTE_DETAIL)
169 zlog_debug(
b5469d02 170 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
d62a17ae 171 __PRETTY_FUNCTION__);
b5469d02 172
d62a17ae 173 return 0;
174 }
04b40f02 175
d62a17ae 176 /*
177 * If we've received a multicast packet that isn't connected to
178 * us
179 */
180 if (!pim_if_connected_to_source(ifp, msg->im_src)) {
181 if (PIM_DEBUG_MROUTE_DETAIL)
182 zlog_debug(
183 "%s: Received incoming packet that doesn't originate on our seg",
184 __PRETTY_FUNCTION__);
185 return 0;
186 }
065bee4b 187
d62a17ae 188 memset(&sg, 0, sizeof(struct prefix_sg));
189 sg.src = msg->im_src;
190 sg.grp = msg->im_dst;
191
b5469d02 192 if (!(PIM_I_am_DR(pim_ifp))) {
b5469d02
DS
193 if (PIM_DEBUG_MROUTE_DETAIL)
194 zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %s",
195 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
196
197 /*
198 * We are not the DR, but we are still receiving packets
199 * Let's blackhole those packets for the moment
200 * As that they will be coming up to the cpu
201 * and causing us to consider them.
9e132a49
DS
202 *
203 * This *will* create a dangling channel_oil
204 * that I see no way to get rid of. Just noting
205 * this for future reference.
b5469d02 206 */
02434c43
DS
207 up = pim_upstream_find_or_add(
208 &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
209 __PRETTY_FUNCTION__);
210 pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
b5469d02
DS
211
212 return 0;
213 }
214
d62a17ae 215 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
216 __PRETTY_FUNCTION__);
c29a5806 217
d62a17ae 218 /*
219 * I moved this debug till after the actual add because
220 * I want to take advantage of the up->sg_str being filled in.
221 */
222 if (PIM_DEBUG_MROUTE) {
223 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
224 __PRETTY_FUNCTION__, up->sg_str);
225 }
8bfb8b67 226
d62a17ae 227 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
19b807ca 228 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
d62a17ae 229
230 up->channel_oil->cc.pktcnt++;
231 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
232 // resolve mfcc_parent prior to mroute_add in channel_add_oif
957d93ea
SP
233 if (up->rpf.source_nexthop.interface &&
234 up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
d62a17ae 235 int vif_index = 0;
236 vif_index = pim_if_find_vifindex_by_ifindex(
7cfc7bcf 237 pim_ifp->pim,
d62a17ae 238 up->rpf.source_nexthop.interface->ifindex);
afb2f470
DS
239 pim_channel_oil_change_iif(pim_ifp->pim, up->channel_oil,
240 vif_index, __PRETTY_FUNCTION__);
d62a17ae 241 }
242 pim_register_join(up);
59471fb8 243
d62a17ae 244 return 0;
e355e30f 245}
12e41d03 246
d62a17ae 247static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
248 const char *buf)
e355e30f 249{
d62a17ae 250 struct pim_interface *pim_ifp;
251 struct prefix_sg sg;
252 struct pim_rpf *rpg;
253 const struct ip *ip_hdr;
254 struct pim_upstream *up;
255
9b29ea95
DS
256 pim_ifp = ifp->info;
257
d62a17ae 258 ip_hdr = (const struct ip *)buf;
259
260 memset(&sg, 0, sizeof(struct prefix_sg));
261 sg.src = ip_hdr->ip_src;
262 sg.grp = ip_hdr->ip_dst;
263
9b29ea95 264 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 265 if (!up) {
266 struct prefix_sg star = sg;
267 star.src.s_addr = INADDR_ANY;
268
9b29ea95 269 up = pim_upstream_find(pim_ifp->pim, &star);
d62a17ae 270
271 if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) {
2002dcdb 272 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
d62a17ae 273 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
0885a9f1 274 __PRETTY_FUNCTION__, NULL);
d62a17ae 275 if (!up) {
276 if (PIM_DEBUG_MROUTE)
277 zlog_debug(
278 "%s: Unable to create upstream information for %s",
279 __PRETTY_FUNCTION__,
280 pim_str_sg_dump(&sg));
281 return 0;
282 }
283 pim_upstream_keep_alive_timer_start(
19b807ca 284 up, pim_ifp->pim->keep_alive_time);
9b29ea95 285 pim_upstream_inherited_olist(pim_ifp->pim, up);
1eca8576
DS
286 pim_upstream_switch(pim_ifp->pim, up,
287 PIM_UPSTREAM_JOINED);
d62a17ae 288
289 if (PIM_DEBUG_MROUTE)
290 zlog_debug("%s: Creating %s upstream on LHR",
291 __PRETTY_FUNCTION__, up->sg_str);
292 return 0;
293 }
294 if (PIM_DEBUG_MROUTE_DETAIL) {
295 zlog_debug(
296 "%s: Unable to find upstream channel WHOLEPKT%s",
297 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
298 }
299 return 0;
300 }
59471fb8 301
957d93ea
SP
302 if (!up->rpf.source_nexthop.interface) {
303 if (PIM_DEBUG_TRACE)
304 zlog_debug("%s: up %s RPF is not present",
305 __PRETTY_FUNCTION__, up->sg_str);
306 return 0;
307 }
308
d62a17ae 309 pim_ifp = up->rpf.source_nexthop.interface->info;
998af219 310
b575a12c 311 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
c8ae3ce8 312
d62a17ae 313 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
314 || (!(PIM_I_am_DR(pim_ifp)))) {
315 if (PIM_DEBUG_MROUTE) {
316 zlog_debug("%s: Failed Check send packet",
317 __PRETTY_FUNCTION__);
318 }
319 return 0;
320 }
84366c7e 321
d62a17ae 322 /*
323 * If we've received a register suppress
324 */
325 if (!up->t_rs_timer) {
6f439a70 326 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
d62a17ae 327 if (PIM_DEBUG_PIM_REG)
328 zlog_debug(
329 "%s register forward skipped as group is SSM",
330 pim_str_sg_dump(&sg));
331 return 0;
332 }
333 pim_register_send((uint8_t *)buf + sizeof(struct ip),
334 ntohs(ip_hdr->ip_len) - sizeof(struct ip),
335 pim_ifp->primary_address, rpg, 0, up);
336 }
337 return 0;
e355e30f 338}
12e41d03 339
d62a17ae 340static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
341 const struct igmpmsg *msg)
e355e30f 342{
d62a17ae 343 struct pim_ifchannel *ch;
344 struct pim_interface *pim_ifp;
345 struct prefix_sg sg;
346
347 memset(&sg, 0, sizeof(struct prefix_sg));
348 sg.src = msg->im_src;
349 sg.grp = msg->im_dst;
350
351 /*
352 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
353
354 RFC 4601 4.8.2. PIM-SSM-Only Routers
355
356 iif is the incoming interface of the packet.
357 if (iif is in inherited_olist(S,G)) {
358 send Assert(S,G) on iif
359 }
360 */
361
362 if (!ifp) {
363 if (PIM_DEBUG_MROUTE)
364 zlog_debug(
365 "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
366 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
367 msg->im_vif);
368 return -1;
369 }
12e41d03 370
d62a17ae 371 pim_ifp = ifp->info;
372 if (!pim_ifp) {
373 if (PIM_DEBUG_MROUTE)
374 zlog_debug(
375 "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
376 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
377 ifp->name);
378 return -2;
379 }
c29a5806 380
d62a17ae 381 ch = pim_ifchannel_find(ifp, &sg);
382 if (!ch) {
383 struct prefix_sg star_g = sg;
384 if (PIM_DEBUG_MROUTE)
385 zlog_debug(
386 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
387 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
388 ifp->name);
389
390 star_g.src.s_addr = INADDR_ANY;
391 ch = pim_ifchannel_find(ifp, &star_g);
392 if (!ch) {
393 if (PIM_DEBUG_MROUTE)
394 zlog_debug(
395 "%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
396 __PRETTY_FUNCTION__,
397 pim_str_sg_dump(&star_g), ifp->name);
398 return -3;
399 }
400 }
12e41d03 401
d62a17ae 402 /*
403 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
404
405 Transitions from NoInfo State
406
407 An (S,G) data packet arrives on interface I, AND
408 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
409 downstream interface that is in our (S,G) outgoing interface
410 list. We optimistically assume that we will be the assert
411 winner for this (S,G), and so we transition to the "I am Assert
412 Winner" state and perform Actions A1 (below), which will
413 initiate the assert negotiation for (S,G).
414 */
415
416 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
417 if (PIM_DEBUG_MROUTE) {
418 zlog_debug(
419 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
420 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
421 }
422 return -4;
423 }
e355e30f 424
d62a17ae 425 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
426 if (PIM_DEBUG_MROUTE) {
427 zlog_debug(
428 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
429 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
430 }
431 return -5;
432 }
433
434 if (assert_action_a1(ch)) {
435 if (PIM_DEBUG_MROUTE) {
436 zlog_debug(
437 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
438 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
439 }
440 return -6;
441 }
e355e30f 442
d62a17ae 443 return 0;
e355e30f
DS
444}
445
d62a17ae 446static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
447 const char *buf)
08e1fe76 448{
d62a17ae 449 const struct ip *ip_hdr = (const struct ip *)buf;
450 struct pim_interface *pim_ifp;
451 struct pim_ifchannel *ch;
452 struct pim_upstream *up;
453 struct prefix_sg star_g;
454 struct prefix_sg sg;
d62a17ae 455
fec883d9
DS
456 pim_ifp = ifp->info;
457
d62a17ae 458 memset(&sg, 0, sizeof(struct prefix_sg));
459 sg.src = ip_hdr->ip_src;
460 sg.grp = ip_hdr->ip_dst;
461
462 ch = pim_ifchannel_find(ifp, &sg);
463 if (ch) {
464 if (PIM_DEBUG_MROUTE)
465 zlog_debug(
466 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
467 ch->sg_str, ifp->name);
468 return -1;
469 }
b7ddd2ec 470
d62a17ae 471 star_g = sg;
472 star_g.src.s_addr = INADDR_ANY;
b7ddd2ec 473#if 0
0490c22d
DS
474 ch = pim_ifchannel_find(ifp, &star_g);
475 if (ch)
476 {
477 if (PIM_DEBUG_MROUTE)
478 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
479 pim_str_sg_dump (&star_g), ifp->name);
480 return -1;
481 }
5cd11e3c 482#endif
08e1fe76 483
9b29ea95 484 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 485 if (up) {
486 struct pim_upstream *parent;
487 struct pim_nexthop source;
fec883d9 488 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
d62a17ae 489 if (!rpf || !rpf->source_nexthop.interface)
490 return 0;
491
492 /*
493 * If we have received a WRVIFWHOLE and are at this
494 * point, we could be receiving the packet on the *,G
495 * tree, let's check and if so we can safely drop
496 * it.
497 */
9b29ea95 498 parent = pim_upstream_find(pim_ifp->pim, &star_g);
d62a17ae 499 if (parent && parent->rpf.source_nexthop.interface == ifp)
500 return 0;
501
502 pim_ifp = rpf->source_nexthop.interface->info;
503
504 memset(&source, 0, sizeof(source));
505 /*
506 * If we are the fhr that means we are getting a callback during
507 * the pimreg period, so I believe we can ignore this packet
508 */
509 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
510 // No if channel, but upstream we are at the RP.
d9c9a9ee 511 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1 512 up->upstream_register, 0)) {
d62a17ae 513 pim_register_stop_send(source.interface, &sg,
514 pim_ifp->primary_address,
515 up->upstream_register);
df766618
DS
516 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
517 }
46dd6edb 518
9b29ea95 519 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 520 if (!up->channel_oil->installed)
521 pim_mroute_add(up->channel_oil,
522 __PRETTY_FUNCTION__);
d62a17ae 523 } else {
d9c9a9ee
DS
524 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
525 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1
DS
526 up->upstream_register,
527 0))
d62a17ae 528 pim_register_stop_send(
529 source.interface, &sg,
530 pim_ifp->primary_address,
531 up->upstream_register);
532 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
533 }
534 pim_upstream_keep_alive_timer_start(
19b807ca 535 up, pim_ifp->pim->keep_alive_time);
9b29ea95 536 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 537 pim_mroute_msg_wholepkt(fd, ifp, buf);
538 }
539 return 0;
540 }
8e38a2cf 541
d62a17ae 542 pim_ifp = ifp->info;
d62a17ae 543 if (pim_if_connected_to_source(ifp, sg.src)) {
2002dcdb
DS
544 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
545 PIM_UPSTREAM_FLAG_MASK_FHR,
0885a9f1 546 __PRETTY_FUNCTION__, NULL);
d62a17ae 547 if (!up) {
548 if (PIM_DEBUG_MROUTE)
549 zlog_debug(
550 "%s: WRONGVIF%s unable to create upstream on interface",
551 pim_str_sg_dump(&sg), ifp->name);
552 return -2;
553 }
554 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
996c9314
LB
555 pim_upstream_keep_alive_timer_start(
556 up, pim_ifp->pim->keep_alive_time);
d62a17ae 557 up->channel_oil->cc.pktcnt++;
558 pim_register_join(up);
9b29ea95 559 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 560
561 // Send the packet to the RP
562 pim_mroute_msg_wholepkt(fd, ifp, buf);
02434c43
DS
563 } else {
564 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
565 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
566 __PRETTY_FUNCTION__, NULL);
567 if (!up->channel_oil->installed)
568 pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
d62a17ae 569 }
08e1fe76 570
d62a17ae 571 return 0;
08e1fe76
DS
572}
573
405d6357 574static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
90450a3d 575 int buf_size, ifindex_t ifindex)
e355e30f 576{
d62a17ae 577 struct interface *ifp;
578 struct pim_interface *pim_ifp;
579 const struct ip *ip_hdr;
580 const struct igmpmsg *msg;
581 char ip_src_str[INET_ADDRSTRLEN] = "";
582 char ip_dst_str[INET_ADDRSTRLEN] = "";
583 char src_str[INET_ADDRSTRLEN] = "<src?>";
584 char grp_str[INET_ADDRSTRLEN] = "<grp?>";
585 struct in_addr ifaddr;
586 struct igmp_sock *igmp;
587
588 ip_hdr = (const struct ip *)buf;
589
590 if (ip_hdr->ip_p == IPPROTO_IGMP) {
591
592 /* We have the IP packet but we do not know which interface this
593 * packet was
594 * received on. Find the interface that is on the same subnet as
595 * the source
596 * of the IP packet.
597 */
90450a3d 598 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
d62a17ae 599
1ef8c24e 600 if (!ifp || !ifp->info)
d62a17ae 601 return 0;
90450a3d 602
d62a17ae 603 pim_ifp = ifp->info;
604 ifaddr = pim_find_primary_addr(ifp);
605 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
606 ifaddr);
607
608 if (PIM_DEBUG_MROUTE) {
609 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
610 sizeof(ip_src_str));
611 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
612 sizeof(ip_dst_str));
613
fb9670aa 614 zlog_debug(
7c2bfc2a
DS
615 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
616 __PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
617 igmp, ip_src_str, ip_dst_str);
d62a17ae 618 }
619 if (igmp)
620 pim_igmp_packet(igmp, (char *)buf, buf_size);
621
622 } else if (ip_hdr->ip_p) {
623 if (PIM_DEBUG_MROUTE_DETAIL) {
624 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
625 sizeof(src_str));
626 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
627 sizeof(grp_str));
628 zlog_debug(
629 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
630 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str,
631 grp_str, buf_size);
632 }
633
634 } else {
635 msg = (const struct igmpmsg *)buf;
636
7cfc7bcf 637 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
d62a17ae 638
639 if (!ifp)
640 return 0;
641 if (PIM_DEBUG_MROUTE) {
642 pim_inet4_dump("<src?>", msg->im_src, src_str,
643 sizeof(src_str));
644 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
645 sizeof(grp_str));
fb9670aa 646 zlog_debug(
d62a17ae 647 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
648 __PRETTY_FUNCTION__,
649 igmpmsgtype2str[msg->im_msgtype],
405d6357
DS
650 msg->im_msgtype, ip_hdr->ip_p,
651 pim->mroute_socket, src_str, grp_str, ifp->name,
652 msg->im_vif, buf_size);
d62a17ae 653 }
654
655 switch (msg->im_msgtype) {
656 case IGMPMSG_WRONGVIF:
405d6357
DS
657 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
658 msg);
d62a17ae 659 break;
660 case IGMPMSG_NOCACHE:
405d6357
DS
661 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
662 msg);
d62a17ae 663 break;
664 case IGMPMSG_WHOLEPKT:
405d6357 665 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
d62a17ae 666 (const char *)msg);
667 break;
668 case IGMPMSG_WRVIFWHOLE:
405d6357
DS
669 return pim_mroute_msg_wrvifwhole(
670 pim->mroute_socket, ifp, (const char *)msg);
d62a17ae 671 break;
672 default:
673 break;
674 }
675 }
12e41d03 676
d62a17ae 677 return 0;
12e41d03
DL
678}
679
12e41d03
DL
680static int mroute_read(struct thread *t)
681{
8ea5d944 682 struct pim_instance *pim;
d62a17ae 683 static long long count;
684 char buf[10000];
685 int result = 0;
686 int cont = 1;
d62a17ae 687 int rd;
90450a3d 688 ifindex_t ifindex;
8ea5d944 689 pim = THREAD_ARG(t);
d62a17ae 690
691 while (cont) {
90450a3d
DS
692 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
693 sizeof(buf), NULL, NULL, NULL, NULL,
694 &ifindex);
61e99c94 695 if (rd <= 0) {
d62a17ae 696 if (errno == EINTR)
697 continue;
698 if (errno == EWOULDBLOCK || errno == EAGAIN)
699 break;
700
fb9670aa
DS
701 zlog_warn("%s: failure reading rd=%d: fd=%d: errno=%d: %s",
702 __PRETTY_FUNCTION__, rd, pim->mroute_socket,
703 errno, safe_strerror(errno));
d62a17ae 704 goto done;
705 }
706
90450a3d 707 result = pim_mroute_msg(pim, buf, rd, ifindex);
d62a17ae 708
709 count++;
75373cca 710 if (count % router->packet_process == 0)
d62a17ae 711 cont = 0;
712 }
713/* Keep reading */
714done:
8ea5d944 715 mroute_read_on(pim);
12e41d03 716
d62a17ae 717 return result;
12e41d03
DL
718}
719
8ea5d944 720static void mroute_read_on(struct pim_instance *pim)
12e41d03 721{
36417fcc 722 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
8ea5d944 723 &pim->thread);
12e41d03
DL
724}
725
8ea5d944 726static void mroute_read_off(struct pim_instance *pim)
12e41d03 727{
8ea5d944 728 THREAD_OFF(pim->thread);
12e41d03
DL
729}
730
6beed987 731int pim_mroute_socket_enable(struct pim_instance *pim)
12e41d03 732{
d62a17ae 733 int fd;
12e41d03 734
0cf6db21 735 frr_with_privs(&pimd_privs) {
12e41d03 736
01b9e3fd 737 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
12e41d03 738
01b9e3fd
DL
739 if (fd < 0) {
740 zlog_warn("Could not create mroute socket: errno=%d: %s",
741 errno,
742 safe_strerror(errno));
743 return -2;
744 }
e691f179 745
466e4e5b 746#ifdef SO_BINDTODEVICE
01b9e3fd 747 if (pim->vrf->vrf_id != VRF_DEFAULT
633fc9b1
DL
748 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
749 pim->vrf->name, strlen(pim->vrf->name))) {
01b9e3fd
DL
750 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
751 safe_strerror(errno));
752 close(fd);
753 return -3;
754 }
466e4e5b 755#endif
90450a3d 756
01b9e3fd 757 }
12e41d03 758
cdbfaec5
DS
759 pim->mroute_socket = fd;
760 if (pim_mroute_set(pim, 1)) {
d62a17ae 761 zlog_warn(
762 "Could not enable mroute on socket fd=%d: errno=%d: %s",
763 fd, errno, safe_strerror(errno));
764 close(fd);
cdbfaec5 765 pim->mroute_socket = -1;
d62a17ae 766 return -3;
767 }
12e41d03 768
6beed987 769 pim->mroute_socket_creation = pim_time_monotonic_sec();
b45cefcb 770
8ea5d944 771 mroute_read_on(pim);
12e41d03 772
d62a17ae 773 return 0;
12e41d03
DL
774}
775
6beed987 776int pim_mroute_socket_disable(struct pim_instance *pim)
12e41d03 777{
cdbfaec5 778 if (pim_mroute_set(pim, 0)) {
d62a17ae 779 zlog_warn(
780 "Could not disable mroute on socket fd=%d: errno=%d: %s",
405d6357 781 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 782 return -2;
783 }
784
6beed987 785 if (close(pim->mroute_socket)) {
d62a17ae 786 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
405d6357 787 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 788 return -3;
789 }
790
8ea5d944 791 mroute_read_off(pim);
6beed987 792 pim->mroute_socket = -1;
d62a17ae 793
794 return 0;
12e41d03
DL
795}
796
797/*
798 For each network interface (e.g., physical or a virtual tunnel) that
799 would be used for multicast forwarding, a corresponding multicast
800 interface must be added to the kernel.
801 */
d62a17ae 802int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
803 unsigned char flags)
12e41d03 804{
d62a17ae 805 struct pim_interface *pim_ifp = ifp->info;
806 struct vifctl vc;
807 int err;
12e41d03 808
08f4f901 809 if (PIM_DEBUG_MROUTE)
d62fd596 810 zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__,
996c9314
LB
811 pim_ifp->mroute_vif_index, ifp->name,
812 pim_ifp->pim->vrf->name);
08f4f901 813
d62a17ae 814 memset(&vc, 0, sizeof(vc));
815 vc.vifc_vifi = pim_ifp->mroute_vif_index;
b3f2bf7c 816#ifdef VIFF_USE_IFINDEX
d62a17ae 817 vc.vifc_lcl_ifindex = ifp->ifindex;
b3f2bf7c 818#else
d62a17ae 819 if (ifaddr.s_addr == INADDR_ANY) {
820 zlog_warn(
821 "%s: unnumbered interfaces are not supported on this platform",
822 __PRETTY_FUNCTION__);
823 return -1;
824 }
825 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
b3f2bf7c 826#endif
d62a17ae 827 vc.vifc_flags = flags;
828 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
829 vc.vifc_rate_limit = 0;
830
831#ifdef PIM_DVMRP_TUNNEL
832 if (vc.vifc_flags & VIFF_TUNNEL) {
833 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
834 sizeof(vc.vifc_rmt_addr));
835 }
12e41d03
DL
836#endif
837
ea3d967b 838 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
d62a17ae 839 (void *)&vc, sizeof(vc));
840 if (err) {
841 char ifaddr_str[INET_ADDRSTRLEN];
12e41d03 842
d62a17ae 843 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
844 sizeof(ifaddr_str));
12e41d03 845
d62a17ae 846 zlog_warn(
08f4f901 847 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
996c9314
LB
848 __PRETTY_FUNCTION__, pim_ifp->pim->mroute_socket,
849 ifp->ifindex, ifaddr_str, flags, errno,
850 safe_strerror(errno));
d62a17ae 851 return -2;
852 }
12e41d03 853
d62a17ae 854 return 0;
12e41d03
DL
855}
856
ea3d967b 857int pim_mroute_del_vif(struct interface *ifp)
12e41d03 858{
ea3d967b 859 struct pim_interface *pim_ifp = ifp->info;
d62a17ae 860 struct vifctl vc;
861 int err;
862
ea3d967b 863 if (PIM_DEBUG_MROUTE)
996c9314
LB
864 zlog_debug("%s: Del Vif %d (%s[%s])", __PRETTY_FUNCTION__,
865 pim_ifp->mroute_vif_index, ifp->name,
866 pim_ifp->pim->vrf->name);
12e41d03 867
d62a17ae 868 memset(&vc, 0, sizeof(vc));
ea3d967b 869 vc.vifc_vifi = pim_ifp->mroute_vif_index;
d62a17ae 870
ea3d967b 871 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
d62a17ae 872 (void *)&vc, sizeof(vc));
873 if (err) {
874 zlog_warn(
875 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
ea3d967b
DS
876 __FILE__, __PRETTY_FUNCTION__,
877 pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index,
878 errno, safe_strerror(errno));
d62a17ae 879 return -2;
880 }
12e41d03 881
d62a17ae 882 return 0;
12e41d03
DL
883}
884
6a78764e 885int pim_mroute_add(struct channel_oil *c_oil, const char *name)
12e41d03 886{
9a0f71c9 887 struct pim_instance *pim = c_oil->pim;
d62a17ae 888 int err;
889 int orig = 0;
890 int orig_iif_vif = 0;
42e01756
DS
891 struct pim_interface *pim_reg_ifp = NULL;
892 int orig_pimreg_ttl = 0;
76e4825a 893 bool pimreg_ttl_reset = false;
42e01756
DS
894 struct pim_interface *vxlan_ifp = NULL;
895 int orig_term_ttl = 0;
37c3fd98 896 bool orig_term_ttl_reset = false;
d62a17ae 897
856e863f
DS
898 pim->mroute_add_last = pim_time_monotonic_sec();
899 ++pim->mroute_add_events;
d62a17ae 900
901 /* Do not install route if incoming interface is undefined. */
902 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
903 if (PIM_DEBUG_MROUTE) {
904 char buf[1000];
905 zlog_debug(
906 "%s(%s) %s Attempting to add vifi that is invalid to mroute table",
907 __PRETTY_FUNCTION__, name,
908 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
909 }
910 return -2;
911 }
d3aded99 912
d62a17ae 913 /* The linux kernel *expects* the incoming
914 * vif to be part of the outgoing list
915 * in the case of a (*,G).
916 */
917 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
918 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
919 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
920 }
d3aded99 921
76e4825a
AK
922 if (c_oil->up) {
923 /* suppress pimreg in the OIL if the mroute is not supposed to
924 * trigger register encapsulated data
925 */
926 if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags)) {
927 pim_reg_ifp = pim->regiface->info;
928 orig_pimreg_ttl =
929 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index];
930 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] = 0;
931 /* remember to flip it back after MFC programming */
932 pimreg_ttl_reset = true;
933 }
37c3fd98
AK
934
935 vxlan_ifp = pim_vxlan_get_term_ifp(pim);
936 /* 1. vxlan termination device must never be added to the
937 * origination mroute (and that can actually happen because
938 * of XG inheritance from the termination mroute) otherwise
939 * traffic will end up looping.
940 * 2. vxlan termination device should be removed from the non-DF
941 * to prevent duplicates to the overlay rxer
942 */
943 if (vxlan_ifp &&
944 (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
945 PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags))) {
946 orig_term_ttl_reset = true;
947 orig_term_ttl =
948 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index];
949 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] = 0;
950 }
76e4825a
AK
951 }
952
d62a17ae 953 /*
954 * If we have an unresolved cache entry for the S,G
955 * it is owned by the pimreg for the incoming IIF
956 * So set pimreg as the IIF temporarily to cause
957 * the packets to be forwarded. Then set it
958 * to the correct IIF afterwords.
959 */
960 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
961 && c_oil->oil.mfcc_parent != 0) {
962 orig_iif_vif = c_oil->oil.mfcc_parent;
963 c_oil->oil.mfcc_parent = 0;
964 }
856e863f 965 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
d62a17ae 966 &c_oil->oil, sizeof(c_oil->oil));
967
968 if (!err && !c_oil->installed
969 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
970 && orig_iif_vif != 0) {
971 c_oil->oil.mfcc_parent = orig_iif_vif;
856e863f 972 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
d62a17ae 973 &c_oil->oil, sizeof(c_oil->oil));
974 }
0365f56b 975
d62a17ae 976 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
977 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
d3aded99 978
42e01756
DS
979 if (pimreg_ttl_reset) {
980 assert(pim_reg_ifp);
76e4825a
AK
981 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] =
982 orig_pimreg_ttl;
42e01756 983 }
37c3fd98
AK
984
985 if (orig_term_ttl_reset)
986 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] =
987 orig_term_ttl;
988
d62a17ae 989 if (err) {
990 zlog_warn(
991 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
856e863f 992 __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
d62a17ae 993 errno, safe_strerror(errno));
994 return -2;
995 }
12e41d03 996
d62a17ae 997 if (PIM_DEBUG_MROUTE) {
998 char buf[1000];
996c9314
LB
999 zlog_debug("%s(%s), vrf %s Added Route: %s",
1000 __PRETTY_FUNCTION__, name, pim->vrf->name,
d62a17ae 1001 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1002 }
6a78764e 1003
d62a17ae 1004 c_oil->installed = 1;
e7cd85bd
SP
1005 c_oil->mroute_creation = pim_time_monotonic_sec();
1006
d62a17ae 1007 return 0;
12e41d03
DL
1008}
1009
d62a17ae 1010int pim_mroute_del(struct channel_oil *c_oil, const char *name)
12e41d03 1011{
9a0f71c9 1012 struct pim_instance *pim = c_oil->pim;
d62a17ae 1013 int err;
1014
856e863f
DS
1015 pim->mroute_del_last = pim_time_monotonic_sec();
1016 ++pim->mroute_del_events;
d62a17ae 1017
1018 if (!c_oil->installed) {
1019 if (PIM_DEBUG_MROUTE) {
1020 char buf[1000];
1021 zlog_debug(
1022 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1023 __FILE__, __PRETTY_FUNCTION__,
1024 c_oil->oil.mfcc_parent,
1025 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1026 }
1027 return -2;
1028 }
12e41d03 1029
856e863f 1030 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
d62a17ae 1031 &c_oil->oil, sizeof(c_oil->oil));
1032 if (err) {
1033 if (PIM_DEBUG_MROUTE)
1034 zlog_warn(
1035 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
1036 __FILE__, __PRETTY_FUNCTION__,
856e863f 1037 pim->mroute_socket, errno,
d62a17ae 1038 safe_strerror(errno));
1039 return -2;
1040 }
429a291b 1041
d62a17ae 1042 if (PIM_DEBUG_MROUTE) {
1043 char buf[1000];
996c9314
LB
1044 zlog_debug("%s(%s), vrf %s Deleted Route: %s",
1045 __PRETTY_FUNCTION__, name, pim->vrf->name,
d62fd596 1046 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
d62a17ae 1047 }
781a1745 1048
d62a17ae 1049 // Reset kernel installed flag
1050 c_oil->installed = 0;
58302dc7 1051
d62a17ae 1052 return 0;
12e41d03 1053}
3667e8a0 1054
d62a17ae 1055void pim_mroute_update_counters(struct channel_oil *c_oil)
3667e8a0 1056{
9a0f71c9 1057 struct pim_instance *pim = c_oil->pim;
d62a17ae 1058 struct sioc_sg_req sgreq;
1059
1060 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1061 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1062 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1063
1064 if (!c_oil->installed) {
19b807ca 1065 c_oil->cc.lastused = 100 * pim->keep_alive_time;
d62a17ae 1066 if (PIM_DEBUG_MROUTE) {
1067 struct prefix_sg sg;
1068
1069 sg.src = c_oil->oil.mfcc_origin;
1070 sg.grp = c_oil->oil.mfcc_mcastgrp;
1071 if (PIM_DEBUG_MROUTE)
1072 zlog_debug(
41714081 1073 "Channel%s is not installed no need to collect data from kernel",
d62a17ae 1074 pim_str_sg_dump(&sg));
1075 }
1076 return;
c7b1183f 1077 }
c7b1183f 1078
d62a17ae 1079 memset(&sgreq, 0, sizeof(sgreq));
1080 sgreq.src = c_oil->oil.mfcc_origin;
1081 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1082
1083 pim_zlookup_sg_statistics(c_oil);
856e863f 1084 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
fb9670aa 1085 struct prefix_sg sg;
d62a17ae 1086
fb9670aa
DS
1087 sg.src = c_oil->oil.mfcc_origin;
1088 sg.grp = c_oil->oil.mfcc_mcastgrp;
d62a17ae 1089
fb9670aa
DS
1090 zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
1091 (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg),
1092 errno, safe_strerror(errno));
d62a17ae 1093 return;
c7b1183f 1094 }
3667e8a0 1095
d62a17ae 1096 c_oil->cc.pktcnt = sgreq.pktcnt;
1097 c_oil->cc.bytecnt = sgreq.bytecnt;
1098 c_oil->cc.wrong_if = sgreq.wrong_if;
3667e8a0 1099
d62a17ae 1100 return;
3667e8a0 1101}