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