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