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