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