]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / pimd / pim_mroute.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
12e41d03 2/*
896014f4
DL
3 * PIM for Quagga
4 * Copyright (C) 2008 Everton da Silva Marques
896014f4 5 */
12e41d03
DL
6
7#include <zebra.h>
8#include "log.h"
9#include "privs.h"
744d91b3 10#include "if.h"
065bee4b 11#include "prefix.h"
dfe43e25
DW
12#include "vty.h"
13#include "plist.h"
fe232c19 14#include "sockopt.h"
3613d898 15#include "lib_errors.h"
1ce957d6 16#include "lib/network.h"
12e41d03
DL
17
18#include "pimd.h"
8e38a2cf 19#include "pim_rpf.h"
12e41d03 20#include "pim_mroute.h"
37653d4f 21#include "pim_oil.h"
12e41d03
DL
22#include "pim_str.h"
23#include "pim_time.h"
24#include "pim_iface.h"
25#include "pim_macro.h"
c8ae3ce8 26#include "pim_rp.h"
59471fb8 27#include "pim_oil.h"
998af219 28#include "pim_register.h"
56638739 29#include "pim_ifchannel.h"
e3be0432 30#include "pim_zlookup.h"
15a5dafe 31#include "pim_ssm.h"
2002dcdb 32#include "pim_sock.h"
37c3fd98 33#include "pim_vxlan.h"
a5fa9822 34#include "pim_msg.h"
12e41d03 35
8ea5d944 36static void mroute_read_on(struct pim_instance *pim);
12e41d03 37
1ce957d6 38int pim_mroute_set(struct pim_instance *pim, int enable)
39{
40 int err;
41 int opt, data;
42 socklen_t data_len = sizeof(data);
43
44 /*
45 * We need to create the VRF table for the pim mroute_socket
46 */
47 if (pim->vrf->vrf_id != VRF_DEFAULT) {
48 frr_with_privs (&pimd_privs) {
49
50 data = pim->vrf->data.l.table_id;
51 err = setsockopt(pim->mroute_socket, PIM_IPPROTO,
52 MRT_TABLE, &data, data_len);
53 if (err) {
54 zlog_warn(
55 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s",
56 __FILE__, __func__, pim->mroute_socket,
57 data, errno, safe_strerror(errno));
58 return -1;
59 }
60 }
61 }
62
63 frr_with_privs (&pimd_privs) {
64 opt = enable ? MRT_INIT : MRT_DONE;
65 /*
66 * *BSD *cares* about what value we pass down
67 * here
68 */
69 data = 1;
70 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data,
71 data_len);
72 if (err) {
73 zlog_warn(
74 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
75 __FILE__, __func__, pim->mroute_socket,
76 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
77 safe_strerror(errno));
78 return -1;
79 }
80 }
81
82#if defined(HAVE_IP_PKTINFO)
83 if (enable) {
84 /* Linux and Solaris IP_PKTINFO */
85 data = 1;
86 if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IP_PKTINFO,
87 &data, data_len)) {
88 zlog_warn(
89 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
90 pim->mroute_socket, errno,
91 safe_strerror(errno));
92 }
93 }
94#endif
95
96#if PIM_IPV == 6
97 if (enable) {
98 /* Linux and Solaris IPV6_PKTINFO */
99 data = 1;
100 if (setsockopt(pim->mroute_socket, PIM_IPPROTO,
101 IPV6_RECVPKTINFO, &data, data_len)) {
102 zlog_warn(
103 "Could not set IPV6_RECVPKTINFO on socket fd=%d: errno=%d: %s",
104 pim->mroute_socket, errno,
105 safe_strerror(errno));
106 }
107 }
108#endif
109 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
110
111 if (set_nonblocking(pim->mroute_socket) < 0) {
112 zlog_warn(
113 "Could not set non blocking on socket fd=%d: errno=%d: %s",
114 pim->mroute_socket, errno, safe_strerror(errno));
115 return -1;
116 }
117
118 if (enable) {
119#if defined linux
120 int upcalls = GMMSG_WRVIFWHOLE;
121 opt = MRT_PIM;
122
123 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls,
124 sizeof(upcalls));
125 if (err) {
126 zlog_warn(
127 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
128 errno, safe_strerror(errno));
129 return -1;
130 }
131#else
132 zlog_warn(
133 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
134#endif
135 }
136
137 return 0;
138}
139
140static const char *const gmmsgtype2str[GMMSG_WRVIFWHOLE + 1] = {
141 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
142
d62a17ae 143
a5fa9822 144int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
12e41d03 145{
d62a17ae 146 struct pim_interface *pim_ifp = ifp->info;
147 struct pim_upstream *up;
148 struct pim_rpf *rpg;
6fff2cc6 149 pim_sgaddr sg;
d62a17ae 150
a5fa9822 151 rpg = pim_ifp ? RP(pim_ifp->pim, msg->msg_im_dst) : NULL;
d62a17ae 152 /*
153 * If the incoming interface is unknown OR
154 * the Interface type is SSM we don't need to
155 * do anything here
156 */
cc144e8b 157 if (!rpg || pim_rpf_addr_is_inaddr_any(rpg)) {
d62a17ae 158 if (PIM_DEBUG_MROUTE_DETAIL)
159 zlog_debug(
b5469d02 160 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
15569c58 161 __func__);
b5469d02 162
d62a17ae 163 return 0;
164 }
04b40f02 165
d62a17ae 166 /*
167 * If we've received a multicast packet that isn't connected to
168 * us
169 */
a5fa9822 170 if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) {
d62a17ae 171 if (PIM_DEBUG_MROUTE_DETAIL)
172 zlog_debug(
173 "%s: Received incoming packet that doesn't originate on our seg",
15569c58 174 __func__);
d62a17ae 175 return 0;
176 }
065bee4b 177
6fff2cc6 178 memset(&sg, 0, sizeof(sg));
a5fa9822 179 sg.src = msg->msg_im_src;
180 sg.grp = msg->msg_im_dst;
d62a17ae 181
b5469d02 182 if (!(PIM_I_am_DR(pim_ifp))) {
b5469d02 183 if (PIM_DEBUG_MROUTE_DETAIL)
a5fa9822 184 zlog_debug(
185 "%s: Interface is not the DR blackholing incoming traffic for %pSG",
186 __func__, &sg);
b5469d02
DS
187
188 /*
189 * We are not the DR, but we are still receiving packets
190 * Let's blackhole those packets for the moment
191 * As that they will be coming up to the cpu
192 * and causing us to consider them.
9e132a49
DS
193 *
194 * This *will* create a dangling channel_oil
195 * that I see no way to get rid of. Just noting
196 * this for future reference.
b5469d02 197 */
02434c43 198 up = pim_upstream_find_or_add(
15569c58
DA
199 &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
200 pim_upstream_mroute_add(up->channel_oil, __func__);
b5469d02
DS
201
202 return 0;
203 }
204
d62a17ae 205 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
15569c58 206 __func__);
c29a5806 207
d62a17ae 208 /*
209 * I moved this debug till after the actual add because
210 * I want to take advantage of the up->sg_str being filled in.
211 */
212 if (PIM_DEBUG_MROUTE) {
213 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
15569c58 214 __func__, up->sg_str);
d62a17ae 215 }
8bfb8b67 216
d62a17ae 217 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
19b807ca 218 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
d62a17ae 219
220 up->channel_oil->cc.pktcnt++;
d62a17ae 221 // resolve mfcc_parent prior to mroute_add in channel_add_oif
957d93ea 222 if (up->rpf.source_nexthop.interface &&
a9338fa4 223 *oil_parent(up->channel_oil) >= MAXVIFS) {
7984af18 224 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
d62a17ae 225 }
226 pim_register_join(up);
ac6c8d54 227 /* if we have receiver, inherit from parent */
228 pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
59471fb8 229
d62a17ae 230 return 0;
e355e30f 231}
12e41d03 232
1b00ed5f
DL
233int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf,
234 size_t len)
e355e30f 235{
d62a17ae 236 struct pim_interface *pim_ifp;
6fff2cc6 237 pim_sgaddr sg;
d62a17ae 238 struct pim_rpf *rpg;
a5fa9822 239 const ipv_hdr *ip_hdr;
d62a17ae 240 struct pim_upstream *up;
241
9b29ea95
DS
242 pim_ifp = ifp->info;
243
a5fa9822 244 ip_hdr = (const ipv_hdr *)buf;
d62a17ae 245
6fff2cc6 246 memset(&sg, 0, sizeof(sg));
a5fa9822 247 sg.src = IPV_SRC(ip_hdr);
248 sg.grp = IPV_DST(ip_hdr);
d62a17ae 249
9b29ea95 250 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 251 if (!up) {
6fff2cc6 252 pim_sgaddr star = sg;
bca160c6 253 star.src = PIMADDR_ANY;
d62a17ae 254
9b29ea95 255 up = pim_upstream_find(pim_ifp->pim, &star);
d62a17ae 256
448139e7 257 if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) {
2002dcdb 258 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
d62a17ae 259 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
15569c58 260 __func__, NULL);
d62a17ae 261 if (!up) {
262 if (PIM_DEBUG_MROUTE)
a5fa9822 263 zlog_debug(
264 "%s: Unable to create upstream information for %pSG",
265 __func__, &sg);
d62a17ae 266 return 0;
267 }
268 pim_upstream_keep_alive_timer_start(
19b807ca 269 up, pim_ifp->pim->keep_alive_time);
9b29ea95 270 pim_upstream_inherited_olist(pim_ifp->pim, up);
a53a9b3e 271 pim_upstream_update_join_desired(pim_ifp->pim, up);
d62a17ae 272
273 if (PIM_DEBUG_MROUTE)
274 zlog_debug("%s: Creating %s upstream on LHR",
15569c58 275 __func__, up->sg_str);
d62a17ae 276 return 0;
277 }
278 if (PIM_DEBUG_MROUTE_DETAIL) {
a5fa9822 279 zlog_debug(
280 "%s: Unable to find upstream channel WHOLEPKT%pSG",
281 __func__, &sg);
d62a17ae 282 }
283 return 0;
284 }
59471fb8 285
957d93ea 286 if (!up->rpf.source_nexthop.interface) {
23fc858a 287 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
288 zlog_debug("%s: up %s RPF is not present", __func__,
289 up->sg_str);
957d93ea
SP
290 return 0;
291 }
292
d62a17ae 293 pim_ifp = up->rpf.source_nexthop.interface->info;
998af219 294
b575a12c 295 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
c8ae3ce8 296
cc144e8b 297 if ((pim_rpf_addr_is_inaddr_any(rpg)) || (!pim_ifp) ||
298 (!(PIM_I_am_DR(pim_ifp)))) {
d62a17ae 299 if (PIM_DEBUG_MROUTE) {
15569c58 300 zlog_debug("%s: Failed Check send packet", __func__);
d62a17ae 301 }
302 return 0;
303 }
84366c7e 304
d62a17ae 305 /*
306 * If we've received a register suppress
307 */
308 if (!up->t_rs_timer) {
6f439a70 309 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
d62a17ae 310 if (PIM_DEBUG_PIM_REG)
a5fa9822 311 zlog_debug(
312 "%pSG register forward skipped as group is SSM",
313 &sg);
d62a17ae 314 return 0;
315 }
2bc31c44
AK
316
317 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
318 if (PIM_DEBUG_PIM_REG)
319 zlog_debug(
320 "%s register forward skipped, not FHR",
321 up->sg_str);
322 return 0;
323 }
324
a5fa9822 325 pim_register_send((uint8_t *)buf + sizeof(ipv_hdr),
1b00ed5f 326 len - sizeof(ipv_hdr),
d62a17ae 327 pim_ifp->primary_address, rpg, 0, up);
328 }
329 return 0;
e355e30f 330}
12e41d03 331
a5fa9822 332int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, const kernmsg *msg)
e355e30f 333{
d62a17ae 334 struct pim_ifchannel *ch;
335 struct pim_interface *pim_ifp;
6fff2cc6 336 pim_sgaddr sg;
d62a17ae 337
6fff2cc6 338 memset(&sg, 0, sizeof(sg));
a5fa9822 339 sg.src = msg->msg_im_src;
340 sg.grp = msg->msg_im_dst;
d62a17ae 341
342 /*
343 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
344
345 RFC 4601 4.8.2. PIM-SSM-Only Routers
346
347 iif is the incoming interface of the packet.
348 if (iif is in inherited_olist(S,G)) {
349 send Assert(S,G) on iif
350 }
351 */
352
353 if (!ifp) {
354 if (PIM_DEBUG_MROUTE)
a5fa9822 355 zlog_debug(
356 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
357 __func__, &sg, msg->msg_im_vif);
d62a17ae 358 return -1;
359 }
12e41d03 360
d62a17ae 361 pim_ifp = ifp->info;
362 if (!pim_ifp) {
363 if (PIM_DEBUG_MROUTE)
a5fa9822 364 zlog_debug(
365 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
366 __func__, &sg, ifp->name);
d62a17ae 367 return -2;
368 }
c29a5806 369
d62a17ae 370 ch = pim_ifchannel_find(ifp, &sg);
371 if (!ch) {
6fff2cc6 372 pim_sgaddr star_g = sg;
d62a17ae 373 if (PIM_DEBUG_MROUTE)
a5fa9822 374 zlog_debug(
375 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
376 __func__, &sg, ifp->name);
d62a17ae 377
bca160c6 378 star_g.src = PIMADDR_ANY;
d62a17ae 379 ch = pim_ifchannel_find(ifp, &star_g);
380 if (!ch) {
381 if (PIM_DEBUG_MROUTE)
a5fa9822 382 zlog_debug(
383 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
384 __func__, &star_g, ifp->name);
d62a17ae 385 return -3;
386 }
387 }
12e41d03 388
d62a17ae 389 /*
390 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
391
392 Transitions from NoInfo State
393
394 An (S,G) data packet arrives on interface I, AND
395 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
396 downstream interface that is in our (S,G) outgoing interface
397 list. We optimistically assume that we will be the assert
398 winner for this (S,G), and so we transition to the "I am Assert
399 Winner" state and perform Actions A1 (below), which will
400 initiate the assert negotiation for (S,G).
401 */
402
403 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
404 if (PIM_DEBUG_MROUTE) {
405 zlog_debug(
406 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
15569c58 407 __func__, ch->sg_str, ifp->name);
d62a17ae 408 }
409 return -4;
410 }
e355e30f 411
d62a17ae 412 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
413 if (PIM_DEBUG_MROUTE) {
414 zlog_debug(
415 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
15569c58 416 __func__, ch->sg_str, ifp->name);
d62a17ae 417 }
418 return -5;
419 }
420
421 if (assert_action_a1(ch)) {
422 if (PIM_DEBUG_MROUTE) {
423 zlog_debug(
424 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
15569c58 425 __func__, ch->sg_str, ifp->name);
d62a17ae 426 }
427 return -6;
428 }
e355e30f 429
d62a17ae 430 return 0;
e355e30f
DS
431}
432
1b00ed5f
DL
433int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf,
434 size_t len)
08e1fe76 435{
a5fa9822 436 const ipv_hdr *ip_hdr = (const ipv_hdr *)buf;
d62a17ae 437 struct pim_interface *pim_ifp;
a054f6d7 438 struct pim_instance *pim;
d62a17ae 439 struct pim_ifchannel *ch;
440 struct pim_upstream *up;
6fff2cc6
DL
441 pim_sgaddr star_g;
442 pim_sgaddr sg;
d62a17ae 443
fec883d9
DS
444 pim_ifp = ifp->info;
445
6fff2cc6 446 memset(&sg, 0, sizeof(sg));
a5fa9822 447 sg.src = IPV_SRC(ip_hdr);
448 sg.grp = IPV_DST(ip_hdr);
d62a17ae 449
450 ch = pim_ifchannel_find(ifp, &sg);
451 if (ch) {
452 if (PIM_DEBUG_MROUTE)
453 zlog_debug(
454 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
455 ch->sg_str, ifp->name);
456 return -1;
457 }
b7ddd2ec 458
d62a17ae 459 star_g = sg;
bca160c6 460 star_g.src = PIMADDR_ANY;
a054f6d7
DS
461
462 pim = pim_ifp->pim;
463 /*
464 * If the incoming interface is the pimreg, then
465 * we know the callback is associated with a pim register
466 * packet and there is nothing to do here as that
467 * normal pim processing will see the packet and allow
468 * us to do the right thing.
469 */
470 if (ifp == pim->regiface) {
471 return 0;
472 }
08e1fe76 473
9b29ea95 474 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 475 if (up) {
476 struct pim_upstream *parent;
477 struct pim_nexthop source;
fec883d9 478 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
c783249b 479
480 /* No RPF or No RPF interface or No mcast on RPF interface */
a5fa9822 481 if (!rpf || !rpf->source_nexthop.interface ||
482 !rpf->source_nexthop.interface->info)
d62a17ae 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)) {
aeb67246
DS
503 /*
504 * No if channel, but upstream we are at the RP.
505 *
506 * This could be a anycast RP too and we may
507 * not have received a register packet from
508 * the source here at all. So gracefully
509 * bow out of doing a nexthop lookup and
510 * setting the SPTBIT to true
511 */
a5fa9822 512 if (!(pim_addr_is_any(up->upstream_register)) &&
aeb67246 513 pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1 514 up->upstream_register, 0)) {
d62a17ae 515 pim_register_stop_send(source.interface, &sg,
516 pim_ifp->primary_address,
517 up->upstream_register);
df766618
DS
518 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
519 }
46dd6edb 520
9b29ea95 521 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 522 if (!up->channel_oil->installed)
69e3538c 523 pim_upstream_mroute_add(up->channel_oil,
15569c58 524 __func__);
d62a17ae 525 } else {
d9c9a9ee
DS
526 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
527 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1
DS
528 up->upstream_register,
529 0))
d62a17ae 530 pim_register_stop_send(
531 source.interface, &sg,
532 pim_ifp->primary_address,
533 up->upstream_register);
534 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
33ec4015
DS
535 } else {
536 /*
537 * At this point pimd is connected to
538 * the source, it has a parent, we are not
539 * the RP and the SPTBIT should be set
540 * since we know *the* S,G is on the SPT.
541 * The first time this happens, let's cause
542 * an immediate join to go out so that
543 * the RP can trim this guy immediately
544 * if necessary, instead of waiting
545 * one join/prune send cycle
546 */
547 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE &&
548 up->parent &&
549 up->rpf.source_nexthop.interface !=
550 up->parent->rpf.source_nexthop
551 .interface) {
552 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
553 pim_jp_agg_single_upstream_send(
554 &up->parent->rpf, up->parent,
555 true);
556 }
d62a17ae 557 }
558 pim_upstream_keep_alive_timer_start(
19b807ca 559 up, pim_ifp->pim->keep_alive_time);
9b29ea95 560 pim_upstream_inherited_olist(pim_ifp->pim, up);
1b00ed5f 561 pim_mroute_msg_wholepkt(fd, ifp, buf, len);
d62a17ae 562 }
563 return 0;
564 }
8e38a2cf 565
d62a17ae 566 pim_ifp = ifp->info;
d62a17ae 567 if (pim_if_connected_to_source(ifp, sg.src)) {
2002dcdb 568 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
15569c58
DA
569 PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
570 NULL);
d62a17ae 571 if (!up) {
572 if (PIM_DEBUG_MROUTE)
a5fa9822 573 zlog_debug(
574 "%pSG: WRONGVIF%s unable to create upstream on interface",
575 &sg, ifp->name);
d62a17ae 576 return -2;
577 }
578 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
996c9314
LB
579 pim_upstream_keep_alive_timer_start(
580 up, pim_ifp->pim->keep_alive_time);
d62a17ae 581 up->channel_oil->cc.pktcnt++;
582 pim_register_join(up);
9b29ea95 583 pim_upstream_inherited_olist(pim_ifp->pim, up);
69e3538c
AK
584 if (!up->channel_oil->installed)
585 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 586
587 // Send the packet to the RP
1b00ed5f 588 pim_mroute_msg_wholepkt(fd, ifp, buf, len);
02434c43
DS
589 } else {
590 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
591 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
15569c58 592 __func__, NULL);
02434c43 593 if (!up->channel_oil->installed)
15569c58 594 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 595 }
08e1fe76 596
d62a17ae 597 return 0;
08e1fe76
DS
598}
599
1ce957d6 600#if PIM_IPV == 4
601static int process_igmp_packet(struct pim_instance *pim, const char *buf,
602 size_t buf_size, ifindex_t ifindex)
603{
604 struct interface *ifp;
605 struct pim_interface *pim_ifp;
606 struct in_addr ifaddr;
607 struct gm_sock *igmp;
608 const struct prefix *connected_src;
609 const struct ip *ip_hdr = (const struct ip *)buf;
610
611 /* We have the IP packet but we do not know which interface this
612 * packet was
613 * received on. Find the interface that is on the same subnet as
614 * the source
615 * of the IP packet.
616 */
617 ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
618
619 if (!ifp || !ifp->info)
620 return 0;
621
622 connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src);
623
b2212b99 624 if (!connected_src && !pim_addr_is_any(ip_hdr->ip_src)) {
55eb347d 625 if (PIM_DEBUG_GM_PACKETS) {
1ce957d6 626 zlog_debug(
627 "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
628 ifp->name, &ip_hdr->ip_src);
629 }
630 return 0;
631 }
632
633 pim_ifp = ifp->info;
b2212b99
MR
634 ifaddr = connected_src ? connected_src->u.prefix4
635 : pim_ifp->primary_address;
1ce957d6 636 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
637
55eb347d 638 if (PIM_DEBUG_GM_PACKETS) {
1ce957d6 639 zlog_debug(
640 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
641 __func__, pim->vrf->name, ifp->name, igmp,
642 &ip_hdr->ip_src, &ip_hdr->ip_dst);
643 }
644 if (igmp)
645 pim_igmp_packet(igmp, (char *)buf, buf_size);
b2212b99 646 else if (PIM_DEBUG_GM_PACKETS)
1ce957d6 647 zlog_debug(
b2212b99
MR
648 "No IGMP socket on interface: %s with connected source: %pI4",
649 ifp->name, &ifaddr);
650
1ce957d6 651 return 0;
652}
653#endif
654
655int pim_mroute_msg(struct pim_instance *pim, const char *buf, size_t buf_size,
656 ifindex_t ifindex)
657{
658 struct interface *ifp;
659 const ipv_hdr *ip_hdr;
660 const kernmsg *msg;
661
662 if (buf_size < (int)sizeof(ipv_hdr))
663 return 0;
664
665 ip_hdr = (const ipv_hdr *)buf;
666
667#if PIM_IPV == 4
668 if (ip_hdr->ip_p == IPPROTO_IGMP) {
669 process_igmp_packet(pim, buf, buf_size, ifindex);
670 } else if (ip_hdr->ip_p) {
671 if (PIM_DEBUG_MROUTE_DETAIL) {
672 zlog_debug(
673 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
674 __func__, ip_hdr->ip_p, &ip_hdr->ip_src,
675 &ip_hdr->ip_dst, (long int)buf_size);
676 }
677
678 } else {
679#else
680
681 if ((ip_hdr->ip6_vfc & 0xf) == 0) {
682#endif
683 msg = (const kernmsg *)buf;
684
685 ifp = pim_if_find_by_vif_index(pim, msg->msg_im_vif);
686
687 if (!ifp)
688 return 0;
689 if (PIM_DEBUG_MROUTE) {
690#if PIM_IPV == 4
691 zlog_debug(
692 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%ld",
693 __func__, gmmsgtype2str[msg->msg_im_msgtype],
694 msg->msg_im_msgtype, ip_hdr->ip_p,
695 pim->mroute_socket, &msg->msg_im_src,
696 &msg->msg_im_dst, ifp->name, msg->msg_im_vif,
697 (long int)buf_size);
698#else
699 zlog_debug(
700 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld",
701 __func__, gmmsgtype2str[msg->msg_im_msgtype],
702 msg->msg_im_msgtype, ip_hdr->ip6_nxt,
703 pim->mroute_socket, &msg->msg_im_src,
704 &msg->msg_im_dst, ifp->name, msg->msg_im_vif,
705 (long int)buf_size);
706#endif
707 }
708
709 switch (msg->msg_im_msgtype) {
710 case GMMSG_WRONGVIF:
711 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
712 msg);
713 case GMMSG_NOCACHE:
714 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
715 msg);
716 case GMMSG_WHOLEPKT:
717 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
718 (const char *)msg,
719 buf_size);
720 case GMMSG_WRVIFWHOLE:
721 return pim_mroute_msg_wrvifwhole(pim->mroute_socket,
722 ifp, (const char *)msg,
723 buf_size);
724 default:
725 break;
726 }
727 }
728
729 return 0;
730}
731
cc9f21da 732static void mroute_read(struct thread *t)
12e41d03 733{
8ea5d944 734 struct pim_instance *pim;
d62a17ae 735 static long long count;
736 char buf[10000];
d62a17ae 737 int cont = 1;
d62a17ae 738 int rd;
90450a3d 739 ifindex_t ifindex;
8ea5d944 740 pim = THREAD_ARG(t);
d62a17ae 741
742 while (cont) {
90450a3d
DS
743 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
744 sizeof(buf), NULL, NULL, NULL, NULL,
745 &ifindex);
61e99c94 746 if (rd <= 0) {
d62a17ae 747 if (errno == EINTR)
748 continue;
749 if (errno == EWOULDBLOCK || errno == EAGAIN)
750 break;
751
15569c58
DA
752 zlog_warn(
753 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
754 __func__, rd, pim->mroute_socket, errno,
755 safe_strerror(errno));
d62a17ae 756 goto done;
757 }
758
cc9f21da 759 pim_mroute_msg(pim, buf, rd, ifindex);
d62a17ae 760
761 count++;
75373cca 762 if (count % router->packet_process == 0)
d62a17ae 763 cont = 0;
764 }
765/* Keep reading */
766done:
8ea5d944 767 mroute_read_on(pim);
a5fa9822 768
769 return;
12e41d03
DL
770}
771
8ea5d944 772static void mroute_read_on(struct pim_instance *pim)
12e41d03 773{
36417fcc 774 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
8ea5d944 775 &pim->thread);
12e41d03
DL
776}
777
8ea5d944 778static void mroute_read_off(struct pim_instance *pim)
12e41d03 779{
8ea5d944 780 THREAD_OFF(pim->thread);
12e41d03
DL
781}
782
6beed987 783int pim_mroute_socket_enable(struct pim_instance *pim)
12e41d03 784{
d62a17ae 785 int fd;
12e41d03 786
0cf6db21 787 frr_with_privs(&pimd_privs) {
12e41d03 788
a5fa9822 789#if PIM_IPV == 4
01b9e3fd 790 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
a5fa9822 791#else
792 fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
793#endif
01b9e3fd
DL
794 if (fd < 0) {
795 zlog_warn("Could not create mroute socket: errno=%d: %s",
796 errno,
797 safe_strerror(errno));
798 return -2;
799 }
e691f179 800
fef295d4
DL
801#if PIM_IPV == 6
802 struct icmp6_filter filter[1];
803 int ret;
804
805 /* Unlike IPv4, this socket is not used for MLD, so just drop
806 * everything with an empty ICMP6 filter. Otherwise we get
807 * all kinds of garbage here, possibly even non-multicast
808 * related ICMPv6 traffic (e.g. ping)
809 *
810 * (mroute kernel upcall "packets" are injected directly on the
811 * socket, this sockopt -or any other- has no effect on them)
812 */
813 ICMP6_FILTER_SETBLOCKALL(filter);
814 ret = setsockopt(fd, SOL_ICMPV6, ICMP6_FILTER, filter,
815 sizeof(filter));
816 if (ret)
817 zlog_err(
818 "(VRF %s) failed to set mroute control filter: %m",
819 pim->vrf->name);
820#endif
821
466e4e5b 822#ifdef SO_BINDTODEVICE
01b9e3fd 823 if (pim->vrf->vrf_id != VRF_DEFAULT
633fc9b1
DL
824 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
825 pim->vrf->name, strlen(pim->vrf->name))) {
01b9e3fd
DL
826 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
827 safe_strerror(errno));
828 close(fd);
829 return -3;
830 }
466e4e5b 831#endif
90450a3d 832
01b9e3fd 833 }
12e41d03 834
cdbfaec5
DS
835 pim->mroute_socket = fd;
836 if (pim_mroute_set(pim, 1)) {
d62a17ae 837 zlog_warn(
838 "Could not enable mroute on socket fd=%d: errno=%d: %s",
839 fd, errno, safe_strerror(errno));
840 close(fd);
cdbfaec5 841 pim->mroute_socket = -1;
d62a17ae 842 return -3;
843 }
12e41d03 844
6beed987 845 pim->mroute_socket_creation = pim_time_monotonic_sec();
b45cefcb 846
8ea5d944 847 mroute_read_on(pim);
12e41d03 848
d62a17ae 849 return 0;
12e41d03
DL
850}
851
6beed987 852int pim_mroute_socket_disable(struct pim_instance *pim)
12e41d03 853{
cdbfaec5 854 if (pim_mroute_set(pim, 0)) {
d62a17ae 855 zlog_warn(
856 "Could not disable mroute on socket fd=%d: errno=%d: %s",
405d6357 857 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 858 return -2;
859 }
860
6beed987 861 if (close(pim->mroute_socket)) {
d62a17ae 862 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
405d6357 863 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 864 return -3;
865 }
866
8ea5d944 867 mroute_read_off(pim);
6beed987 868 pim->mroute_socket = -1;
d62a17ae 869
870 return 0;
12e41d03
DL
871}
872
873/*
874 For each network interface (e.g., physical or a virtual tunnel) that
875 would be used for multicast forwarding, a corresponding multicast
876 interface must be added to the kernel.
877 */
a9338fa4 878int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
d62a17ae 879 unsigned char flags)
12e41d03 880{
d62a17ae 881 struct pim_interface *pim_ifp = ifp->info;
a5fa9822 882 pim_vifctl vc;
d62a17ae 883 int err;
12e41d03 884
08f4f901 885 if (PIM_DEBUG_MROUTE)
15569c58 886 zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
996c9314
LB
887 pim_ifp->mroute_vif_index, ifp->name,
888 pim_ifp->pim->vrf->name);
08f4f901 889
d62a17ae 890 memset(&vc, 0, sizeof(vc));
a5fa9822 891 vc.vc_vifi = pim_ifp->mroute_vif_index;
892#if PIM_IPV == 4
b3f2bf7c 893#ifdef VIFF_USE_IFINDEX
a5fa9822 894 vc.vc_lcl_ifindex = ifp->ifindex;
b3f2bf7c 895#else
d62a17ae 896 if (ifaddr.s_addr == INADDR_ANY) {
897 zlog_warn(
898 "%s: unnumbered interfaces are not supported on this platform",
15569c58 899 __func__);
d62a17ae 900 return -1;
901 }
a5fa9822 902 memcpy(&vc.vc_lcl_addr, &ifaddr, sizeof(vc.vc_lcl_addr));
903#endif
904#else
905 vc.vc_pifi = ifp->ifindex;
b3f2bf7c 906#endif
a5fa9822 907 vc.vc_flags = flags;
908 vc.vc_threshold = PIM_MROUTE_MIN_TTL;
909 vc.vc_rate_limit = 0;
d62a17ae 910
a5fa9822 911#if PIM_IPV == 4
d62a17ae 912#ifdef PIM_DVMRP_TUNNEL
a5fa9822 913 if (vc.vc_flags & VIFF_TUNNEL) {
914 memcpy(&vc.vc_rmt_addr, &vif_remote_addr,
915 sizeof(vc.vc_rmt_addr));
d62a17ae 916 }
a5fa9822 917#endif
12e41d03
DL
918#endif
919
a5fa9822 920 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
d62a17ae 921 (void *)&vc, sizeof(vc));
922 if (err) {
d62a17ae 923 zlog_warn(
a5fa9822 924 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
15569c58 925 __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
a9338fa4 926 &ifaddr, flags, errno, safe_strerror(errno));
d62a17ae 927 return -2;
928 }
12e41d03 929
d62a17ae 930 return 0;
12e41d03
DL
931}
932
ea3d967b 933int pim_mroute_del_vif(struct interface *ifp)
12e41d03 934{
ea3d967b 935 struct pim_interface *pim_ifp = ifp->info;
a5fa9822 936 pim_vifctl vc;
d62a17ae 937 int err;
938
ea3d967b 939 if (PIM_DEBUG_MROUTE)
15569c58 940 zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
996c9314
LB
941 pim_ifp->mroute_vif_index, ifp->name,
942 pim_ifp->pim->vrf->name);
12e41d03 943
d62a17ae 944 memset(&vc, 0, sizeof(vc));
a5fa9822 945 vc.vc_vifi = pim_ifp->mroute_vif_index;
d62a17ae 946
a5fa9822 947 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_DEL_VIF,
d62a17ae 948 (void *)&vc, sizeof(vc));
949 if (err) {
950 zlog_warn(
a5fa9822 951 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
15569c58
DA
952 __FILE__, __func__, pim_ifp->pim->mroute_socket,
953 pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
d62a17ae 954 return -2;
955 }
12e41d03 956
d62a17ae 957 return 0;
12e41d03
DL
958}
959
60eb7e6b
AK
960/*
961 * Prevent creating MFC entry with OIF=IIF.
962 *
963 * This is a protection against implementation mistakes.
964 *
965 * PIM protocol implicitely ensures loopfree multicast topology.
966 *
967 * IGMP must be protected against adding looped MFC entries created
968 * by both source and receiver attached to the same interface. See
969 * TODO T22.
970 * We shall allow igmp to create upstream when it is DR for the intf.
971 * Assume RP reachable via non DR.
972 */
973bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
974 int oif_index)
975{
976#ifdef PIM_ENFORCE_LOOPFREE_MFC
977 struct interface *ifp_out;
978 struct pim_interface *pim_ifp;
979
980 if (c_oil->up &&
981 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
982 return true;
983
984 ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
985 if (!ifp_out)
986 return false;
987 pim_ifp = ifp_out->info;
988 if (!pim_ifp)
989 return false;
80a82b56
A
990 if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_GM) &&
991 PIM_I_am_DR(pim_ifp))
60eb7e6b
AK
992 return true;
993
994 return false;
995#else
996 return true;
997#endif
998}
999
a9338fa4
DL
1000static inline void pim_mroute_copy(struct channel_oil *out,
1001 struct channel_oil *in)
5a5f404e
AK
1002{
1003 int i;
1004
a9338fa4
DL
1005 *oil_origin(out) = *oil_origin(in);
1006 *oil_mcastgrp(out) = *oil_mcastgrp(in);
1007 *oil_parent(out) = *oil_parent(in);
5a5f404e
AK
1008
1009 for (i = 0; i < MAXVIFS; ++i) {
a9338fa4
DL
1010 if (*oil_parent(out) == i &&
1011 !pim_mroute_allow_iif_in_oil(in, i)) {
1012 oil_if_set(out, i, 0);
60eb7e6b
AK
1013 continue;
1014 }
1015
a9338fa4
DL
1016 if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
1017 oil_if_set(out, i, 0);
5a5f404e 1018 else
a9338fa4 1019 oil_if_set(out, i, oil_if_has(in, i));
5a5f404e
AK
1020 }
1021}
1022
69e3538c
AK
1023/* This function must not be called directly 0
1024 * use pim_upstream_mroute_add or pim_static_mroute_add instead
1025 */
1026static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
12e41d03 1027{
9a0f71c9 1028 struct pim_instance *pim = c_oil->pim;
a9338fa4 1029 struct channel_oil tmp_oil[1] = { };
d62a17ae 1030 int err;
d62a17ae 1031
856e863f
DS
1032 pim->mroute_add_last = pim_time_monotonic_sec();
1033 ++pim->mroute_add_events;
d62a17ae 1034
5a5f404e
AK
1035 /* Copy the oil to a temporary structure to fixup (without need to
1036 * later restore) before sending the mroute add to the dataplane
1037 */
a9338fa4 1038 pim_mroute_copy(tmp_oil, c_oil);
d3aded99 1039
d62a17ae 1040 /* The linux kernel *expects* the incoming
1041 * vif to be part of the outgoing list
1042 * in the case of a (*,G).
1043 */
a9338fa4
DL
1044 if (pim_addr_is_any(*oil_origin(c_oil))) {
1045 oil_if_set(tmp_oil, *oil_parent(c_oil), 1);
76e4825a
AK
1046 }
1047
d62a17ae 1048 /*
1049 * If we have an unresolved cache entry for the S,G
1050 * it is owned by the pimreg for the incoming IIF
1051 * So set pimreg as the IIF temporarily to cause
1052 * the packets to be forwarded. Then set it
1053 * to the correct IIF afterwords.
1054 */
a9338fa4
DL
1055 if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil))
1056 && *oil_parent(c_oil) != 0) {
1057 *oil_parent(tmp_oil) = 0;
d62a17ae 1058 }
a5fa9822 1059 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
1060 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
a9338fa4 1061 &tmp_oil->oil, sizeof(tmp_oil->oil));
d62a17ae 1062
1063 if (!err && !c_oil->installed
a9338fa4
DL
1064 && !pim_addr_is_any(*oil_origin(c_oil))
1065 && *oil_parent(c_oil) != 0) {
1066 *oil_parent(tmp_oil) = *oil_parent(c_oil);
a5fa9822 1067 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
a9338fa4 1068 &tmp_oil->oil, sizeof(tmp_oil->oil));
42e01756 1069 }
37c3fd98 1070
d62a17ae 1071 if (err) {
1072 zlog_warn(
a5fa9822 1073 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
15569c58
DA
1074 __FILE__, __func__, pim->mroute_socket, errno,
1075 safe_strerror(errno));
d62a17ae 1076 return -2;
1077 }
12e41d03 1078
d62a17ae 1079 if (PIM_DEBUG_MROUTE) {
1080 char buf[1000];
15569c58
DA
1081 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
1082 pim->vrf->name,
d62a17ae 1083 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1084 }
6a78764e 1085
fe75a058
SP
1086 if (!c_oil->installed) {
1087 c_oil->installed = 1;
1088 c_oil->mroute_creation = pim_time_monotonic_sec();
1089 }
e7cd85bd 1090
d62a17ae 1091 return 0;
12e41d03
DL
1092}
1093
7984af18
AK
1094static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
1095 const char *name)
69e3538c
AK
1096{
1097 vifi_t iif = MAXVIFS;
69e3538c
AK
1098 struct interface *ifp = NULL;
1099 struct pim_interface *pim_ifp;
1100 struct pim_upstream *up = c_oil->up;
1101
1102 if (up) {
1103 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
1104 if (up->parent)
1105 ifp = up->parent->rpf.source_nexthop.interface;
1106 } else {
1107 ifp = up->rpf.source_nexthop.interface;
1108 }
1109 if (ifp) {
1110 pim_ifp = (struct pim_interface *)ifp->info;
1111 if (pim_ifp)
1112 iif = pim_ifp->mroute_vif_index;
1113 }
1114 }
7984af18
AK
1115 return iif;
1116}
69e3538c 1117
7984af18
AK
1118static int pim_upstream_mroute_update(struct channel_oil *c_oil,
1119 const char *name)
1120{
1121 char buf[1000];
69e3538c 1122
a9338fa4 1123 if (*oil_parent(c_oil) >= MAXVIFS) {
69e3538c
AK
1124 /* the c_oil cannot be installed as a mroute yet */
1125 if (PIM_DEBUG_MROUTE)
1126 zlog_debug(
1127 "%s(%s) %s mroute not ready to be installed; %s",
7984af18 1128 __func__, name,
69e3538c
AK
1129 pim_channel_oil_dump(c_oil, buf,
1130 sizeof(buf)),
1131 c_oil->installed ?
1132 "uninstall" : "skip");
1133 /* if already installed flush it out as we are going to stop
1134 * updates to it leaving it in a stale state
1135 */
1136 if (c_oil->installed)
1137 pim_mroute_del(c_oil, name);
1138 /* return success (skipped) */
1139 return 0;
1140 }
1141
1142 return pim_mroute_add(c_oil, name);
1143}
1144
70c86421
AK
1145/* IIF associated with SGrpt entries are re-evaluated when the parent
1146 * (*,G) entries IIF changes
1147 */
1148static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
1149{
1150 struct listnode *listnode;
1151 struct pim_upstream *child;
1152
1153 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
1154 child)) {
1155 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
1156 pim_upstream_mroute_iif_update(child->channel_oil,
1157 __func__);
1158 }
1159}
1160
7984af18
AK
1161/* In the case of "PIM state machine" added mroutes an upstream entry
1162 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1163 */
1164int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
1165{
70c86421
AK
1166 vifi_t iif;
1167
1168 iif = pim_upstream_get_mroute_iif(c_oil, name);
1169
a9338fa4
DL
1170 if (*oil_parent(c_oil) != iif) {
1171 *oil_parent(c_oil) = iif;
1172 if (pim_addr_is_any(*oil_origin(c_oil)) &&
70c86421
AK
1173 c_oil->up)
1174 pim_upstream_all_sources_iif_update(c_oil->up);
1175 } else {
a9338fa4 1176 *oil_parent(c_oil) = iif;
70c86421 1177 }
7984af18
AK
1178
1179 return pim_upstream_mroute_update(c_oil, name);
1180}
1181
1182/* Look for IIF changes and update the dateplane entry only if the IIF
1183 * has changed.
1184 */
1185int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
1186{
1187 vifi_t iif;
1188 char buf[1000];
1189
1190 iif = pim_upstream_get_mroute_iif(c_oil, name);
a9338fa4 1191 if (*oil_parent(c_oil) == iif) {
7984af18
AK
1192 /* no change */
1193 return 0;
1194 }
a9338fa4 1195 *oil_parent(c_oil) = iif;
7984af18 1196
a9338fa4 1197 if (pim_addr_is_any(*oil_origin(c_oil)) &&
70c86421
AK
1198 c_oil->up)
1199 pim_upstream_all_sources_iif_update(c_oil->up);
1200
7984af18
AK
1201 if (PIM_DEBUG_MROUTE_DETAIL)
1202 zlog_debug("%s(%s) %s mroute iif update %d",
1203 __func__, name,
1204 pim_channel_oil_dump(c_oil, buf,
1205 sizeof(buf)), iif);
1206 /* XXX: is this hack needed? */
1207 c_oil->oil_inherited_rescan = 1;
1208 return pim_upstream_mroute_update(c_oil, name);
1209}
1210
69e3538c
AK
1211int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
1212{
1213 return pim_mroute_add(c_oil, name);
1214}
1215
7984af18
AK
1216void pim_static_mroute_iif_update(struct channel_oil *c_oil,
1217 int input_vif_index,
1218 const char *name)
1219{
a9338fa4 1220 if (*oil_parent(c_oil) == input_vif_index)
7984af18
AK
1221 return;
1222
a9338fa4 1223 *oil_parent(c_oil) = input_vif_index;
7984af18
AK
1224 if (input_vif_index == MAXVIFS)
1225 pim_mroute_del(c_oil, name);
1226 else
1227 pim_static_mroute_add(c_oil, name);
1228}
1229
d62a17ae 1230int pim_mroute_del(struct channel_oil *c_oil, const char *name)
12e41d03 1231{
9a0f71c9 1232 struct pim_instance *pim = c_oil->pim;
d62a17ae 1233 int err;
1234
856e863f
DS
1235 pim->mroute_del_last = pim_time_monotonic_sec();
1236 ++pim->mroute_del_events;
d62a17ae 1237
1238 if (!c_oil->installed) {
1239 if (PIM_DEBUG_MROUTE) {
1240 char buf[1000];
1241 zlog_debug(
1242 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
a9338fa4 1243 __FILE__, __func__, *oil_parent(c_oil),
d62a17ae 1244 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1245 }
1246 return -2;
1247 }
12e41d03 1248
a5fa9822 1249 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_DEL_MFC,
d62a17ae 1250 &c_oil->oil, sizeof(c_oil->oil));
1251 if (err) {
1252 if (PIM_DEBUG_MROUTE)
1253 zlog_warn(
a5fa9822 1254 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
15569c58 1255 __FILE__, __func__, pim->mroute_socket, errno,
d62a17ae 1256 safe_strerror(errno));
1257 return -2;
1258 }
429a291b 1259
d62a17ae 1260 if (PIM_DEBUG_MROUTE) {
1261 char buf[1000];
15569c58
DA
1262 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
1263 pim->vrf->name,
d62fd596 1264 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
d62a17ae 1265 }
781a1745 1266
d62a17ae 1267 // Reset kernel installed flag
1268 c_oil->installed = 0;
58302dc7 1269
d62a17ae 1270 return 0;
12e41d03 1271}
3667e8a0 1272
d62a17ae 1273void pim_mroute_update_counters(struct channel_oil *c_oil)
3667e8a0 1274{
9a0f71c9 1275 struct pim_instance *pim = c_oil->pim;
a5fa9822 1276 pim_sioc_sg_req sgreq;
d62a17ae 1277
1278 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1279 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1280 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1281
1282 if (!c_oil->installed) {
19b807ca 1283 c_oil->cc.lastused = 100 * pim->keep_alive_time;
d62a17ae 1284 if (PIM_DEBUG_MROUTE) {
6fff2cc6 1285 pim_sgaddr sg;
d62a17ae 1286
a9338fa4
DL
1287 sg.src = *oil_origin(c_oil);
1288 sg.grp = *oil_mcastgrp(c_oil);
98a81d2b
DL
1289 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1290 &sg);
d62a17ae 1291 }
1292 return;
c7b1183f 1293 }
c7b1183f 1294
a9338fa4 1295
d62a17ae 1296 memset(&sgreq, 0, sizeof(sgreq));
a5fa9822 1297
0696c2ff
MR
1298 pim_zlookup_sg_statistics(c_oil);
1299
a5fa9822 1300#if PIM_IPV == 4
a9338fa4
DL
1301 sgreq.src = *oil_origin(c_oil);
1302 sgreq.grp = *oil_mcastgrp(c_oil);
a5fa9822 1303#else
1304 sgreq.src = c_oil->oil.mf6cc_origin;
1305 sgreq.grp = c_oil->oil.mf6cc_mcastgrp;
a5fa9822 1306#endif
1307 if (ioctl(pim->mroute_socket, PIM_SIOCGETSGCNT, &sgreq)) {
6fff2cc6 1308 pim_sgaddr sg;
d62a17ae 1309
a9338fa4
DL
1310 sg.src = *oil_origin(c_oil);
1311 sg.grp = *oil_mcastgrp(c_oil);
d62a17ae 1312
a5fa9822 1313 zlog_warn(
1314 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1315 (unsigned long)PIM_SIOCGETSGCNT, &sg, errno,
1316 safe_strerror(errno));
d62a17ae 1317 return;
c7b1183f 1318 }
3667e8a0 1319
d62a17ae 1320 c_oil->cc.pktcnt = sgreq.pktcnt;
1321 c_oil->cc.bytecnt = sgreq.bytecnt;
1322 c_oil->cc.wrong_if = sgreq.wrong_if;
d62a17ae 1323 return;
3667e8a0 1324}