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