]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
pimd: Add accidently missed code during upstreaming process
[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(
5e81f5dd
DS
68 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
69 __FILE__, __func__, pim->mroute_socket,
70 data, errno, safe_strerror(errno));
01b9e3fd
DL
71 return -1;
72 }
f507c196 73
01b9e3fd 74 }
f507c196
DS
75 }
76
0cf6db21 77 frr_with_privs(&pimd_privs) {
f0b009a4 78 opt = enable ? MRT_INIT : MRT_DONE;
e5a2ebe6
DS
79 /*
80 * *BSD *cares* about what value we pass down
81 * here
82 */
83 data = 1;
f0b009a4 84 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
e5a2ebe6 85 opt, &data, data_len);
f0b009a4
DS
86 if (err) {
87 zlog_warn(
5e81f5dd
DS
88 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
89 __FILE__, __func__, pim->mroute_socket,
90 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
91 safe_strerror(errno));
f0b009a4
DS
92 return -1;
93 }
cdbfaec5
DS
94 }
95
466e4e5b
DS
96#if defined(HAVE_IP_PKTINFO)
97 if (enable) {
98 /* Linux and Solaris IP_PKTINFO */
e5a2ebe6
DS
99 data = 1;
100 if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
101 &data, data_len)) {
466e4e5b
DS
102 zlog_warn(
103 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
104 pim->mroute_socket, errno,
105 safe_strerror(errno));
106 }
107 }
108#endif
109
cdbfaec5 110 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
d62a17ae 111
cdbfaec5 112 flags = fcntl(pim->mroute_socket, F_GETFL, 0);
d62a17ae 113 if (flags < 0) {
cdbfaec5
DS
114 zlog_warn("Could not get flags on socket fd:%d %d %s",
115 pim->mroute_socket, errno, safe_strerror(errno));
116 close(pim->mroute_socket);
d62a17ae 117 return -1;
118 }
cdbfaec5
DS
119 if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
120 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
121 pim->mroute_socket, errno, safe_strerror(errno));
122 close(pim->mroute_socket);
d62a17ae 123 return -1;
124 }
125
126 if (enable) {
77b7d90b 127#if defined linux
d62a17ae 128 int upcalls = IGMPMSG_WRVIFWHOLE;
129 opt = MRT_PIM;
130
cdbfaec5 131 err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
d62a17ae 132 sizeof(upcalls));
133 if (err) {
134 zlog_warn(
135 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
136 errno, safe_strerror(errno));
137 return -1;
138 }
77b7d90b 139#else
d62a17ae 140 zlog_warn(
141 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
77b7d90b 142#endif
d62a17ae 143 }
144
145 return 0;
12e41d03
DL
146}
147
2b64873d 148static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
d62a17ae 149 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
150
151static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
152 const struct igmpmsg *msg)
12e41d03 153{
d62a17ae 154 struct pim_interface *pim_ifp = ifp->info;
155 struct pim_upstream *up;
156 struct pim_rpf *rpg;
157 struct prefix_sg sg;
158
b575a12c 159 rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
d62a17ae 160 /*
161 * If the incoming interface is unknown OR
162 * the Interface type is SSM we don't need to
163 * do anything here
164 */
b5469d02 165 if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) {
d62a17ae 166 if (PIM_DEBUG_MROUTE_DETAIL)
167 zlog_debug(
b5469d02 168 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
15569c58 169 __func__);
b5469d02 170
d62a17ae 171 return 0;
172 }
04b40f02 173
d62a17ae 174 /*
175 * If we've received a multicast packet that isn't connected to
176 * us
177 */
178 if (!pim_if_connected_to_source(ifp, msg->im_src)) {
179 if (PIM_DEBUG_MROUTE_DETAIL)
180 zlog_debug(
181 "%s: Received incoming packet that doesn't originate on our seg",
15569c58 182 __func__);
d62a17ae 183 return 0;
184 }
065bee4b 185
d62a17ae 186 memset(&sg, 0, sizeof(struct prefix_sg));
187 sg.src = msg->im_src;
188 sg.grp = msg->im_dst;
189
b5469d02 190 if (!(PIM_I_am_DR(pim_ifp))) {
b5469d02 191 if (PIM_DEBUG_MROUTE_DETAIL)
15569c58
DA
192 zlog_debug(
193 "%s: Interface is not the DR blackholing incoming traffic for %s",
194 __func__, pim_str_sg_dump(&sg));
b5469d02
DS
195
196 /*
197 * We are not the DR, but we are still receiving packets
198 * Let's blackhole those packets for the moment
199 * As that they will be coming up to the cpu
200 * and causing us to consider them.
9e132a49
DS
201 *
202 * This *will* create a dangling channel_oil
203 * that I see no way to get rid of. Just noting
204 * this for future reference.
b5469d02 205 */
02434c43 206 up = pim_upstream_find_or_add(
15569c58
DA
207 &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
208 pim_upstream_mroute_add(up->channel_oil, __func__);
b5469d02
DS
209
210 return 0;
211 }
212
d62a17ae 213 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
15569c58 214 __func__);
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",
15569c58 222 __func__, up->sg_str);
d62a17ae 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++;
d62a17ae 229 // resolve mfcc_parent prior to mroute_add in channel_add_oif
957d93ea
SP
230 if (up->rpf.source_nexthop.interface &&
231 up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
7984af18 232 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
d62a17ae 233 }
234 pim_register_join(up);
59471fb8 235
d62a17ae 236 return 0;
e355e30f 237}
12e41d03 238
d62a17ae 239static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
240 const char *buf)
e355e30f 241{
d62a17ae 242 struct pim_interface *pim_ifp;
243 struct prefix_sg sg;
244 struct pim_rpf *rpg;
245 const struct ip *ip_hdr;
246 struct pim_upstream *up;
247
9b29ea95
DS
248 pim_ifp = ifp->info;
249
d62a17ae 250 ip_hdr = (const struct ip *)buf;
251
252 memset(&sg, 0, sizeof(struct prefix_sg));
253 sg.src = ip_hdr->ip_src;
254 sg.grp = ip_hdr->ip_dst;
255
9b29ea95 256 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 257 if (!up) {
258 struct prefix_sg star = sg;
259 star.src.s_addr = INADDR_ANY;
260
9b29ea95 261 up = pim_upstream_find(pim_ifp->pim, &star);
d62a17ae 262
448139e7 263 if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) {
2002dcdb 264 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
d62a17ae 265 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
15569c58 266 __func__, NULL);
d62a17ae 267 if (!up) {
268 if (PIM_DEBUG_MROUTE)
269 zlog_debug(
270 "%s: Unable to create upstream information for %s",
15569c58 271 __func__, pim_str_sg_dump(&sg));
d62a17ae 272 return 0;
273 }
274 pim_upstream_keep_alive_timer_start(
19b807ca 275 up, pim_ifp->pim->keep_alive_time);
9b29ea95 276 pim_upstream_inherited_olist(pim_ifp->pim, up);
a53a9b3e 277 pim_upstream_update_join_desired(pim_ifp->pim, up);
d62a17ae 278
279 if (PIM_DEBUG_MROUTE)
280 zlog_debug("%s: Creating %s upstream on LHR",
15569c58 281 __func__, up->sg_str);
d62a17ae 282 return 0;
283 }
284 if (PIM_DEBUG_MROUTE_DETAIL) {
285 zlog_debug(
286 "%s: Unable to find upstream channel WHOLEPKT%s",
15569c58 287 __func__, pim_str_sg_dump(&sg));
d62a17ae 288 }
289 return 0;
290 }
59471fb8 291
957d93ea 292 if (!up->rpf.source_nexthop.interface) {
23fc858a 293 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
294 zlog_debug("%s: up %s RPF is not present", __func__,
295 up->sg_str);
957d93ea
SP
296 return 0;
297 }
298
d62a17ae 299 pim_ifp = up->rpf.source_nexthop.interface->info;
998af219 300
b575a12c 301 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
c8ae3ce8 302
d62a17ae 303 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
304 || (!(PIM_I_am_DR(pim_ifp)))) {
305 if (PIM_DEBUG_MROUTE) {
15569c58 306 zlog_debug("%s: Failed Check send packet", __func__);
d62a17ae 307 }
308 return 0;
309 }
84366c7e 310
d62a17ae 311 /*
312 * If we've received a register suppress
313 */
314 if (!up->t_rs_timer) {
6f439a70 315 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
d62a17ae 316 if (PIM_DEBUG_PIM_REG)
317 zlog_debug(
318 "%s register forward skipped as group is SSM",
319 pim_str_sg_dump(&sg));
320 return 0;
321 }
2bc31c44
AK
322
323 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
324 if (PIM_DEBUG_PIM_REG)
325 zlog_debug(
326 "%s register forward skipped, not FHR",
327 up->sg_str);
328 return 0;
329 }
330
d62a17ae 331 pim_register_send((uint8_t *)buf + sizeof(struct ip),
332 ntohs(ip_hdr->ip_len) - sizeof(struct ip),
333 pim_ifp->primary_address, rpg, 0, up);
334 }
335 return 0;
e355e30f 336}
12e41d03 337
d62a17ae 338static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
339 const struct igmpmsg *msg)
e355e30f 340{
d62a17ae 341 struct pim_ifchannel *ch;
342 struct pim_interface *pim_ifp;
343 struct prefix_sg sg;
344
345 memset(&sg, 0, sizeof(struct prefix_sg));
346 sg.src = msg->im_src;
347 sg.grp = msg->im_dst;
348
349 /*
350 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
351
352 RFC 4601 4.8.2. PIM-SSM-Only Routers
353
354 iif is the incoming interface of the packet.
355 if (iif is in inherited_olist(S,G)) {
356 send Assert(S,G) on iif
357 }
358 */
359
360 if (!ifp) {
361 if (PIM_DEBUG_MROUTE)
362 zlog_debug(
363 "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
15569c58 364 __func__, pim_str_sg_dump(&sg), msg->im_vif);
d62a17ae 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",
15569c58 373 __func__, pim_str_sg_dump(&sg), ifp->name);
d62a17ae 374 return -2;
375 }
c29a5806 376
d62a17ae 377 ch = pim_ifchannel_find(ifp, &sg);
378 if (!ch) {
379 struct prefix_sg star_g = sg;
380 if (PIM_DEBUG_MROUTE)
381 zlog_debug(
382 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
15569c58 383 __func__, pim_str_sg_dump(&sg), ifp->name);
d62a17ae 384
385 star_g.src.s_addr = INADDR_ANY;
386 ch = pim_ifchannel_find(ifp, &star_g);
387 if (!ch) {
388 if (PIM_DEBUG_MROUTE)
389 zlog_debug(
390 "%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
15569c58
DA
391 __func__, pim_str_sg_dump(&star_g),
392 ifp->name);
d62a17ae 393 return -3;
394 }
395 }
12e41d03 396
d62a17ae 397 /*
398 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
399
400 Transitions from NoInfo State
401
402 An (S,G) data packet arrives on interface I, AND
403 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
404 downstream interface that is in our (S,G) outgoing interface
405 list. We optimistically assume that we will be the assert
406 winner for this (S,G), and so we transition to the "I am Assert
407 Winner" state and perform Actions A1 (below), which will
408 initiate the assert negotiation for (S,G).
409 */
410
411 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
412 if (PIM_DEBUG_MROUTE) {
413 zlog_debug(
414 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
15569c58 415 __func__, ch->sg_str, ifp->name);
d62a17ae 416 }
417 return -4;
418 }
e355e30f 419
d62a17ae 420 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
421 if (PIM_DEBUG_MROUTE) {
422 zlog_debug(
423 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
15569c58 424 __func__, ch->sg_str, ifp->name);
d62a17ae 425 }
426 return -5;
427 }
428
429 if (assert_action_a1(ch)) {
430 if (PIM_DEBUG_MROUTE) {
431 zlog_debug(
432 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
15569c58 433 __func__, ch->sg_str, ifp->name);
d62a17ae 434 }
435 return -6;
436 }
e355e30f 437
d62a17ae 438 return 0;
e355e30f
DS
439}
440
d62a17ae 441static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
442 const char *buf)
08e1fe76 443{
d62a17ae 444 const struct ip *ip_hdr = (const struct ip *)buf;
445 struct pim_interface *pim_ifp;
a054f6d7 446 struct pim_instance *pim;
d62a17ae 447 struct pim_ifchannel *ch;
448 struct pim_upstream *up;
449 struct prefix_sg star_g;
450 struct prefix_sg sg;
d62a17ae 451
fec883d9
DS
452 pim_ifp = ifp->info;
453
d62a17ae 454 memset(&sg, 0, sizeof(struct prefix_sg));
455 sg.src = ip_hdr->ip_src;
456 sg.grp = ip_hdr->ip_dst;
457
458 ch = pim_ifchannel_find(ifp, &sg);
459 if (ch) {
460 if (PIM_DEBUG_MROUTE)
461 zlog_debug(
462 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
463 ch->sg_str, ifp->name);
464 return -1;
465 }
b7ddd2ec 466
d62a17ae 467 star_g = sg;
468 star_g.src.s_addr = INADDR_ANY;
a054f6d7
DS
469
470 pim = pim_ifp->pim;
471 /*
472 * If the incoming interface is the pimreg, then
473 * we know the callback is associated with a pim register
474 * packet and there is nothing to do here as that
475 * normal pim processing will see the packet and allow
476 * us to do the right thing.
477 */
478 if (ifp == pim->regiface) {
479 return 0;
480 }
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 }
46dd6edb 516
9b29ea95 517 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 518 if (!up->channel_oil->installed)
69e3538c 519 pim_upstream_mroute_add(up->channel_oil,
15569c58 520 __func__);
d62a17ae 521 } else {
d9c9a9ee
DS
522 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
523 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1
DS
524 up->upstream_register,
525 0))
d62a17ae 526 pim_register_stop_send(
527 source.interface, &sg,
528 pim_ifp->primary_address,
529 up->upstream_register);
530 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
531 }
532 pim_upstream_keep_alive_timer_start(
19b807ca 533 up, pim_ifp->pim->keep_alive_time);
9b29ea95 534 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 535 pim_mroute_msg_wholepkt(fd, ifp, buf);
536 }
537 return 0;
538 }
8e38a2cf 539
d62a17ae 540 pim_ifp = ifp->info;
d62a17ae 541 if (pim_if_connected_to_source(ifp, sg.src)) {
2002dcdb 542 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
15569c58
DA
543 PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
544 NULL);
d62a17ae 545 if (!up) {
546 if (PIM_DEBUG_MROUTE)
547 zlog_debug(
548 "%s: WRONGVIF%s unable to create upstream on interface",
549 pim_str_sg_dump(&sg), ifp->name);
550 return -2;
551 }
552 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
996c9314
LB
553 pim_upstream_keep_alive_timer_start(
554 up, pim_ifp->pim->keep_alive_time);
d62a17ae 555 up->channel_oil->cc.pktcnt++;
556 pim_register_join(up);
9b29ea95 557 pim_upstream_inherited_olist(pim_ifp->pim, up);
69e3538c
AK
558 if (!up->channel_oil->installed)
559 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 560
561 // Send the packet to the RP
562 pim_mroute_msg_wholepkt(fd, ifp, buf);
02434c43
DS
563 } else {
564 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
565 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
15569c58 566 __func__, NULL);
02434c43 567 if (!up->channel_oil->installed)
15569c58 568 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 569 }
08e1fe76 570
d62a17ae 571 return 0;
08e1fe76
DS
572}
573
405d6357 574static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
90450a3d 575 int buf_size, ifindex_t ifindex)
e355e30f 576{
d62a17ae 577 struct interface *ifp;
578 struct pim_interface *pim_ifp;
579 const struct ip *ip_hdr;
580 const struct igmpmsg *msg;
581 char ip_src_str[INET_ADDRSTRLEN] = "";
582 char ip_dst_str[INET_ADDRSTRLEN] = "";
583 char src_str[INET_ADDRSTRLEN] = "<src?>";
584 char grp_str[INET_ADDRSTRLEN] = "<grp?>";
585 struct in_addr ifaddr;
586 struct igmp_sock *igmp;
587
f08e6750
QY
588 if (buf_size < (int)sizeof(struct ip))
589 return 0;
590
d62a17ae 591 ip_hdr = (const struct ip *)buf;
592
593 if (ip_hdr->ip_p == IPPROTO_IGMP) {
594
595 /* We have the IP packet but we do not know which interface this
596 * packet was
597 * received on. Find the interface that is on the same subnet as
598 * the source
599 * of the IP packet.
600 */
90450a3d 601 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
d62a17ae 602
1ef8c24e 603 if (!ifp || !ifp->info)
d62a17ae 604 return 0;
90450a3d 605
d62a17ae 606 pim_ifp = ifp->info;
607 ifaddr = pim_find_primary_addr(ifp);
608 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
609 ifaddr);
610
611 if (PIM_DEBUG_MROUTE) {
612 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
613 sizeof(ip_src_str));
614 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
615 sizeof(ip_dst_str));
616
fb9670aa 617 zlog_debug(
7c2bfc2a 618 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
15569c58
DA
619 __func__, pim->vrf->name, ifp->name, igmp,
620 ip_src_str, ip_dst_str);
d62a17ae 621 }
622 if (igmp)
623 pim_igmp_packet(igmp, (char *)buf, buf_size);
624
625 } else if (ip_hdr->ip_p) {
626 if (PIM_DEBUG_MROUTE_DETAIL) {
627 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
628 sizeof(src_str));
629 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
630 sizeof(grp_str));
631 zlog_debug(
632 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
15569c58
DA
633 __func__, ip_hdr->ip_p, src_str, grp_str,
634 buf_size);
d62a17ae 635 }
636
637 } else {
638 msg = (const struct igmpmsg *)buf;
639
7cfc7bcf 640 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
d62a17ae 641
642 if (!ifp)
643 return 0;
644 if (PIM_DEBUG_MROUTE) {
645 pim_inet4_dump("<src?>", msg->im_src, src_str,
646 sizeof(src_str));
647 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
648 sizeof(grp_str));
fb9670aa 649 zlog_debug(
d62a17ae 650 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
15569c58 651 __func__, igmpmsgtype2str[msg->im_msgtype],
405d6357
DS
652 msg->im_msgtype, ip_hdr->ip_p,
653 pim->mroute_socket, src_str, grp_str, ifp->name,
654 msg->im_vif, buf_size);
d62a17ae 655 }
656
657 switch (msg->im_msgtype) {
658 case IGMPMSG_WRONGVIF:
405d6357
DS
659 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
660 msg);
d62a17ae 661 break;
662 case IGMPMSG_NOCACHE:
405d6357
DS
663 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
664 msg);
d62a17ae 665 break;
666 case IGMPMSG_WHOLEPKT:
405d6357 667 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
d62a17ae 668 (const char *)msg);
669 break;
670 case IGMPMSG_WRVIFWHOLE:
405d6357
DS
671 return pim_mroute_msg_wrvifwhole(
672 pim->mroute_socket, ifp, (const char *)msg);
d62a17ae 673 break;
674 default:
675 break;
676 }
677 }
12e41d03 678
d62a17ae 679 return 0;
12e41d03
DL
680}
681
12e41d03
DL
682static int mroute_read(struct thread *t)
683{
8ea5d944 684 struct pim_instance *pim;
d62a17ae 685 static long long count;
686 char buf[10000];
687 int result = 0;
688 int cont = 1;
d62a17ae 689 int rd;
90450a3d 690 ifindex_t ifindex;
8ea5d944 691 pim = THREAD_ARG(t);
d62a17ae 692
693 while (cont) {
90450a3d
DS
694 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
695 sizeof(buf), NULL, NULL, NULL, NULL,
696 &ifindex);
61e99c94 697 if (rd <= 0) {
d62a17ae 698 if (errno == EINTR)
699 continue;
700 if (errno == EWOULDBLOCK || errno == EAGAIN)
701 break;
702
15569c58
DA
703 zlog_warn(
704 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
705 __func__, rd, pim->mroute_socket, errno,
706 safe_strerror(errno));
d62a17ae 707 goto done;
708 }
709
90450a3d 710 result = pim_mroute_msg(pim, buf, rd, ifindex);
d62a17ae 711
712 count++;
75373cca 713 if (count % router->packet_process == 0)
d62a17ae 714 cont = 0;
715 }
716/* Keep reading */
717done:
8ea5d944 718 mroute_read_on(pim);
12e41d03 719
d62a17ae 720 return result;
12e41d03
DL
721}
722
8ea5d944 723static void mroute_read_on(struct pim_instance *pim)
12e41d03 724{
36417fcc 725 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
8ea5d944 726 &pim->thread);
12e41d03
DL
727}
728
8ea5d944 729static void mroute_read_off(struct pim_instance *pim)
12e41d03 730{
8ea5d944 731 THREAD_OFF(pim->thread);
12e41d03
DL
732}
733
6beed987 734int pim_mroute_socket_enable(struct pim_instance *pim)
12e41d03 735{
d62a17ae 736 int fd;
12e41d03 737
0cf6db21 738 frr_with_privs(&pimd_privs) {
12e41d03 739
01b9e3fd 740 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
12e41d03 741
01b9e3fd
DL
742 if (fd < 0) {
743 zlog_warn("Could not create mroute socket: errno=%d: %s",
744 errno,
745 safe_strerror(errno));
746 return -2;
747 }
e691f179 748
466e4e5b 749#ifdef SO_BINDTODEVICE
01b9e3fd 750 if (pim->vrf->vrf_id != VRF_DEFAULT
633fc9b1
DL
751 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
752 pim->vrf->name, strlen(pim->vrf->name))) {
01b9e3fd
DL
753 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
754 safe_strerror(errno));
755 close(fd);
756 return -3;
757 }
466e4e5b 758#endif
90450a3d 759
01b9e3fd 760 }
12e41d03 761
cdbfaec5
DS
762 pim->mroute_socket = fd;
763 if (pim_mroute_set(pim, 1)) {
d62a17ae 764 zlog_warn(
765 "Could not enable mroute on socket fd=%d: errno=%d: %s",
766 fd, errno, safe_strerror(errno));
767 close(fd);
cdbfaec5 768 pim->mroute_socket = -1;
d62a17ae 769 return -3;
770 }
12e41d03 771
6beed987 772 pim->mroute_socket_creation = pim_time_monotonic_sec();
b45cefcb 773
8ea5d944 774 mroute_read_on(pim);
12e41d03 775
d62a17ae 776 return 0;
12e41d03
DL
777}
778
6beed987 779int pim_mroute_socket_disable(struct pim_instance *pim)
12e41d03 780{
cdbfaec5 781 if (pim_mroute_set(pim, 0)) {
d62a17ae 782 zlog_warn(
783 "Could not disable mroute on socket fd=%d: errno=%d: %s",
405d6357 784 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 785 return -2;
786 }
787
6beed987 788 if (close(pim->mroute_socket)) {
d62a17ae 789 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
405d6357 790 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 791 return -3;
792 }
793
8ea5d944 794 mroute_read_off(pim);
6beed987 795 pim->mroute_socket = -1;
d62a17ae 796
797 return 0;
12e41d03
DL
798}
799
800/*
801 For each network interface (e.g., physical or a virtual tunnel) that
802 would be used for multicast forwarding, a corresponding multicast
803 interface must be added to the kernel.
804 */
d62a17ae 805int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
806 unsigned char flags)
12e41d03 807{
d62a17ae 808 struct pim_interface *pim_ifp = ifp->info;
809 struct vifctl vc;
810 int err;
12e41d03 811
08f4f901 812 if (PIM_DEBUG_MROUTE)
15569c58 813 zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
996c9314
LB
814 pim_ifp->mroute_vif_index, ifp->name,
815 pim_ifp->pim->vrf->name);
08f4f901 816
d62a17ae 817 memset(&vc, 0, sizeof(vc));
818 vc.vifc_vifi = pim_ifp->mroute_vif_index;
b3f2bf7c 819#ifdef VIFF_USE_IFINDEX
d62a17ae 820 vc.vifc_lcl_ifindex = ifp->ifindex;
b3f2bf7c 821#else
d62a17ae 822 if (ifaddr.s_addr == INADDR_ANY) {
823 zlog_warn(
824 "%s: unnumbered interfaces are not supported on this platform",
15569c58 825 __func__);
d62a17ae 826 return -1;
827 }
828 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
b3f2bf7c 829#endif
d62a17ae 830 vc.vifc_flags = flags;
831 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
832 vc.vifc_rate_limit = 0;
833
834#ifdef PIM_DVMRP_TUNNEL
835 if (vc.vifc_flags & VIFF_TUNNEL) {
836 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
837 sizeof(vc.vifc_rmt_addr));
838 }
12e41d03
DL
839#endif
840
ea3d967b 841 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
d62a17ae 842 (void *)&vc, sizeof(vc));
843 if (err) {
844 char ifaddr_str[INET_ADDRSTRLEN];
12e41d03 845
d62a17ae 846 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
847 sizeof(ifaddr_str));
12e41d03 848
d62a17ae 849 zlog_warn(
08f4f901 850 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
15569c58
DA
851 __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
852 ifaddr_str, flags, errno, safe_strerror(errno));
d62a17ae 853 return -2;
854 }
12e41d03 855
d62a17ae 856 return 0;
12e41d03
DL
857}
858
ea3d967b 859int pim_mroute_del_vif(struct interface *ifp)
12e41d03 860{
ea3d967b 861 struct pim_interface *pim_ifp = ifp->info;
d62a17ae 862 struct vifctl vc;
863 int err;
864
ea3d967b 865 if (PIM_DEBUG_MROUTE)
15569c58 866 zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
996c9314
LB
867 pim_ifp->mroute_vif_index, ifp->name,
868 pim_ifp->pim->vrf->name);
12e41d03 869
d62a17ae 870 memset(&vc, 0, sizeof(vc));
ea3d967b 871 vc.vifc_vifi = pim_ifp->mroute_vif_index;
d62a17ae 872
ea3d967b 873 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
d62a17ae 874 (void *)&vc, sizeof(vc));
875 if (err) {
876 zlog_warn(
877 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
15569c58
DA
878 __FILE__, __func__, pim_ifp->pim->mroute_socket,
879 pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
d62a17ae 880 return -2;
881 }
12e41d03 882
d62a17ae 883 return 0;
12e41d03
DL
884}
885
60eb7e6b
AK
886/*
887 * Prevent creating MFC entry with OIF=IIF.
888 *
889 * This is a protection against implementation mistakes.
890 *
891 * PIM protocol implicitely ensures loopfree multicast topology.
892 *
893 * IGMP must be protected against adding looped MFC entries created
894 * by both source and receiver attached to the same interface. See
895 * TODO T22.
896 * We shall allow igmp to create upstream when it is DR for the intf.
897 * Assume RP reachable via non DR.
898 */
899bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
900 int oif_index)
901{
902#ifdef PIM_ENFORCE_LOOPFREE_MFC
903 struct interface *ifp_out;
904 struct pim_interface *pim_ifp;
905
906 if (c_oil->up &&
907 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
908 return true;
909
910 ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
911 if (!ifp_out)
912 return false;
913 pim_ifp = ifp_out->info;
914 if (!pim_ifp)
915 return false;
916 if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_IGMP) &&
917 PIM_I_am_DR(pim_ifp))
918 return true;
919
920 return false;
921#else
922 return true;
923#endif
924}
925
5a5f404e
AK
926static inline void pim_mroute_copy(struct mfcctl *oil,
927 struct channel_oil *c_oil)
928{
929 int i;
930
931 oil->mfcc_origin = c_oil->oil.mfcc_origin;
932 oil->mfcc_mcastgrp = c_oil->oil.mfcc_mcastgrp;
933 oil->mfcc_parent = c_oil->oil.mfcc_parent;
934
935 for (i = 0; i < MAXVIFS; ++i) {
60eb7e6b
AK
936 if ((oil->mfcc_parent == i) &&
937 !pim_mroute_allow_iif_in_oil(c_oil, i)) {
938 oil->mfcc_ttls[i] = 0;
939 continue;
940 }
941
5a5f404e
AK
942 if (c_oil->oif_flags[i] & PIM_OIF_FLAG_MUTE)
943 oil->mfcc_ttls[i] = 0;
944 else
945 oil->mfcc_ttls[i] = c_oil->oil.mfcc_ttls[i];
946 }
947}
948
69e3538c
AK
949/* This function must not be called directly 0
950 * use pim_upstream_mroute_add or pim_static_mroute_add instead
951 */
952static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
12e41d03 953{
9a0f71c9 954 struct pim_instance *pim = c_oil->pim;
5a5f404e 955 struct mfcctl tmp_oil;
d62a17ae 956 int err;
d62a17ae 957
856e863f
DS
958 pim->mroute_add_last = pim_time_monotonic_sec();
959 ++pim->mroute_add_events;
d62a17ae 960
5a5f404e
AK
961 /* Copy the oil to a temporary structure to fixup (without need to
962 * later restore) before sending the mroute add to the dataplane
963 */
964 pim_mroute_copy(&tmp_oil, c_oil);
d3aded99 965
d62a17ae 966 /* The linux kernel *expects* the incoming
967 * vif to be part of the outgoing list
968 * in the case of a (*,G).
969 */
970 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
5a5f404e 971 tmp_oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
76e4825a
AK
972 }
973
d62a17ae 974 /*
975 * If we have an unresolved cache entry for the S,G
976 * it is owned by the pimreg for the incoming IIF
977 * So set pimreg as the IIF temporarily to cause
978 * the packets to be forwarded. Then set it
979 * to the correct IIF afterwords.
980 */
981 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
982 && c_oil->oil.mfcc_parent != 0) {
5a5f404e 983 tmp_oil.mfcc_parent = 0;
d62a17ae 984 }
856e863f 985 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
5a5f404e 986 &tmp_oil, sizeof(tmp_oil));
d62a17ae 987
988 if (!err && !c_oil->installed
989 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
5a5f404e
AK
990 && c_oil->oil.mfcc_parent != 0) {
991 tmp_oil.mfcc_parent = c_oil->oil.mfcc_parent;
856e863f 992 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
5a5f404e 993 &tmp_oil, sizeof(tmp_oil));
42e01756 994 }
37c3fd98 995
d62a17ae 996 if (err) {
997 zlog_warn(
998 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
15569c58
DA
999 __FILE__, __func__, pim->mroute_socket, errno,
1000 safe_strerror(errno));
d62a17ae 1001 return -2;
1002 }
12e41d03 1003
d62a17ae 1004 if (PIM_DEBUG_MROUTE) {
1005 char buf[1000];
15569c58
DA
1006 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
1007 pim->vrf->name,
d62a17ae 1008 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1009 }
6a78764e 1010
d62a17ae 1011 c_oil->installed = 1;
e7cd85bd
SP
1012 c_oil->mroute_creation = pim_time_monotonic_sec();
1013
d62a17ae 1014 return 0;
12e41d03
DL
1015}
1016
7984af18
AK
1017static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
1018 const char *name)
69e3538c
AK
1019{
1020 vifi_t iif = MAXVIFS;
69e3538c
AK
1021 struct interface *ifp = NULL;
1022 struct pim_interface *pim_ifp;
1023 struct pim_upstream *up = c_oil->up;
1024
1025 if (up) {
1026 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
1027 if (up->parent)
1028 ifp = up->parent->rpf.source_nexthop.interface;
1029 } else {
1030 ifp = up->rpf.source_nexthop.interface;
1031 }
1032 if (ifp) {
1033 pim_ifp = (struct pim_interface *)ifp->info;
1034 if (pim_ifp)
1035 iif = pim_ifp->mroute_vif_index;
1036 }
1037 }
7984af18
AK
1038 return iif;
1039}
69e3538c 1040
7984af18
AK
1041static int pim_upstream_mroute_update(struct channel_oil *c_oil,
1042 const char *name)
1043{
1044 char buf[1000];
69e3538c
AK
1045
1046 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
1047 /* the c_oil cannot be installed as a mroute yet */
1048 if (PIM_DEBUG_MROUTE)
1049 zlog_debug(
1050 "%s(%s) %s mroute not ready to be installed; %s",
7984af18 1051 __func__, name,
69e3538c
AK
1052 pim_channel_oil_dump(c_oil, buf,
1053 sizeof(buf)),
1054 c_oil->installed ?
1055 "uninstall" : "skip");
1056 /* if already installed flush it out as we are going to stop
1057 * updates to it leaving it in a stale state
1058 */
1059 if (c_oil->installed)
1060 pim_mroute_del(c_oil, name);
1061 /* return success (skipped) */
1062 return 0;
1063 }
1064
1065 return pim_mroute_add(c_oil, name);
1066}
1067
70c86421
AK
1068/* IIF associated with SGrpt entries are re-evaluated when the parent
1069 * (*,G) entries IIF changes
1070 */
1071static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
1072{
1073 struct listnode *listnode;
1074 struct pim_upstream *child;
1075
1076 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
1077 child)) {
1078 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
1079 pim_upstream_mroute_iif_update(child->channel_oil,
1080 __func__);
1081 }
1082}
1083
7984af18
AK
1084/* In the case of "PIM state machine" added mroutes an upstream entry
1085 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1086 */
1087int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
1088{
70c86421
AK
1089 vifi_t iif;
1090
1091 iif = pim_upstream_get_mroute_iif(c_oil, name);
1092
1093 if (c_oil->oil.mfcc_parent != iif) {
1094 c_oil->oil.mfcc_parent = iif;
1095 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY &&
1096 c_oil->up)
1097 pim_upstream_all_sources_iif_update(c_oil->up);
1098 } else {
1099 c_oil->oil.mfcc_parent = iif;
1100 }
7984af18
AK
1101
1102 return pim_upstream_mroute_update(c_oil, name);
1103}
1104
1105/* Look for IIF changes and update the dateplane entry only if the IIF
1106 * has changed.
1107 */
1108int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
1109{
1110 vifi_t iif;
1111 char buf[1000];
1112
1113 iif = pim_upstream_get_mroute_iif(c_oil, name);
1114 if (c_oil->oil.mfcc_parent == iif) {
1115 /* no change */
1116 return 0;
1117 }
1118 c_oil->oil.mfcc_parent = iif;
1119
70c86421
AK
1120 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY &&
1121 c_oil->up)
1122 pim_upstream_all_sources_iif_update(c_oil->up);
1123
7984af18
AK
1124 if (PIM_DEBUG_MROUTE_DETAIL)
1125 zlog_debug("%s(%s) %s mroute iif update %d",
1126 __func__, name,
1127 pim_channel_oil_dump(c_oil, buf,
1128 sizeof(buf)), iif);
1129 /* XXX: is this hack needed? */
1130 c_oil->oil_inherited_rescan = 1;
1131 return pim_upstream_mroute_update(c_oil, name);
1132}
1133
69e3538c
AK
1134int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
1135{
1136 return pim_mroute_add(c_oil, name);
1137}
1138
7984af18
AK
1139void pim_static_mroute_iif_update(struct channel_oil *c_oil,
1140 int input_vif_index,
1141 const char *name)
1142{
1143 if (c_oil->oil.mfcc_parent == input_vif_index)
1144 return;
1145
1146 c_oil->oil.mfcc_parent = input_vif_index;
1147 if (input_vif_index == MAXVIFS)
1148 pim_mroute_del(c_oil, name);
1149 else
1150 pim_static_mroute_add(c_oil, name);
1151}
1152
d62a17ae 1153int pim_mroute_del(struct channel_oil *c_oil, const char *name)
12e41d03 1154{
9a0f71c9 1155 struct pim_instance *pim = c_oil->pim;
d62a17ae 1156 int err;
1157
856e863f
DS
1158 pim->mroute_del_last = pim_time_monotonic_sec();
1159 ++pim->mroute_del_events;
d62a17ae 1160
1161 if (!c_oil->installed) {
1162 if (PIM_DEBUG_MROUTE) {
1163 char buf[1000];
1164 zlog_debug(
1165 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
15569c58 1166 __FILE__, __func__, c_oil->oil.mfcc_parent,
d62a17ae 1167 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1168 }
1169 return -2;
1170 }
12e41d03 1171
856e863f 1172 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
d62a17ae 1173 &c_oil->oil, sizeof(c_oil->oil));
1174 if (err) {
1175 if (PIM_DEBUG_MROUTE)
1176 zlog_warn(
1177 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
15569c58 1178 __FILE__, __func__, pim->mroute_socket, errno,
d62a17ae 1179 safe_strerror(errno));
1180 return -2;
1181 }
429a291b 1182
d62a17ae 1183 if (PIM_DEBUG_MROUTE) {
1184 char buf[1000];
15569c58
DA
1185 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
1186 pim->vrf->name,
d62fd596 1187 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
d62a17ae 1188 }
781a1745 1189
d62a17ae 1190 // Reset kernel installed flag
1191 c_oil->installed = 0;
58302dc7 1192
d62a17ae 1193 return 0;
12e41d03 1194}
3667e8a0 1195
d62a17ae 1196void pim_mroute_update_counters(struct channel_oil *c_oil)
3667e8a0 1197{
9a0f71c9 1198 struct pim_instance *pim = c_oil->pim;
d62a17ae 1199 struct sioc_sg_req sgreq;
1200
1201 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1202 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1203 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1204
1205 if (!c_oil->installed) {
19b807ca 1206 c_oil->cc.lastused = 100 * pim->keep_alive_time;
d62a17ae 1207 if (PIM_DEBUG_MROUTE) {
1208 struct prefix_sg sg;
1209
1210 sg.src = c_oil->oil.mfcc_origin;
1211 sg.grp = c_oil->oil.mfcc_mcastgrp;
1212 if (PIM_DEBUG_MROUTE)
1213 zlog_debug(
41714081 1214 "Channel%s is not installed no need to collect data from kernel",
d62a17ae 1215 pim_str_sg_dump(&sg));
1216 }
1217 return;
c7b1183f 1218 }
c7b1183f 1219
d62a17ae 1220 memset(&sgreq, 0, sizeof(sgreq));
1221 sgreq.src = c_oil->oil.mfcc_origin;
1222 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1223
1224 pim_zlookup_sg_statistics(c_oil);
856e863f 1225 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
fb9670aa 1226 struct prefix_sg sg;
d62a17ae 1227
fb9670aa
DS
1228 sg.src = c_oil->oil.mfcc_origin;
1229 sg.grp = c_oil->oil.mfcc_mcastgrp;
d62a17ae 1230
fb9670aa
DS
1231 zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
1232 (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg),
1233 errno, safe_strerror(errno));
d62a17ae 1234 return;
c7b1183f 1235 }
3667e8a0 1236
d62a17ae 1237 c_oil->cc.pktcnt = sgreq.pktcnt;
1238 c_oil->cc.bytecnt = sgreq.bytecnt;
1239 c_oil->cc.wrong_if = sgreq.wrong_if;
3667e8a0 1240
d62a17ae 1241 return;
3667e8a0 1242}