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