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