]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
*: Replace __PRETTY_FUNCTION__/__FUNCTION__ to __func__
[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(
68 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
69 __FILE__, __PRETTY_FUNCTION__,
e5a2ebe6 70 pim->mroute_socket, data, errno,
01b9e3fd
DL
71 safe_strerror(errno));
72 return -1;
73 }
f507c196 74
01b9e3fd 75 }
f507c196
DS
76 }
77
0cf6db21 78 frr_with_privs(&pimd_privs) {
f0b009a4 79 opt = enable ? MRT_INIT : MRT_DONE;
e5a2ebe6
DS
80 /*
81 * *BSD *cares* about what value we pass down
82 * here
83 */
84 data = 1;
f0b009a4 85 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
e5a2ebe6 86 opt, &data, data_len);
f0b009a4
DS
87 if (err) {
88 zlog_warn(
89 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
90 __FILE__, __PRETTY_FUNCTION__,
91 pim->mroute_socket,
e5a2ebe6 92 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
f0b009a4
DS
93 safe_strerror(errno));
94 return -1;
95 }
cdbfaec5
DS
96 }
97
466e4e5b
DS
98#if defined(HAVE_IP_PKTINFO)
99 if (enable) {
100 /* Linux and Solaris IP_PKTINFO */
e5a2ebe6
DS
101 data = 1;
102 if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
103 &data, data_len)) {
466e4e5b
DS
104 zlog_warn(
105 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
106 pim->mroute_socket, errno,
107 safe_strerror(errno));
108 }
109 }
110#endif
111
cdbfaec5 112 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
d62a17ae 113
cdbfaec5 114 flags = fcntl(pim->mroute_socket, F_GETFL, 0);
d62a17ae 115 if (flags < 0) {
cdbfaec5
DS
116 zlog_warn("Could not get flags on socket fd:%d %d %s",
117 pim->mroute_socket, errno, safe_strerror(errno));
118 close(pim->mroute_socket);
d62a17ae 119 return -1;
120 }
cdbfaec5
DS
121 if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
122 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
123 pim->mroute_socket, errno, safe_strerror(errno));
124 close(pim->mroute_socket);
d62a17ae 125 return -1;
126 }
127
128 if (enable) {
77b7d90b 129#if defined linux
d62a17ae 130 int upcalls = IGMPMSG_WRVIFWHOLE;
131 opt = MRT_PIM;
132
cdbfaec5 133 err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
d62a17ae 134 sizeof(upcalls));
135 if (err) {
136 zlog_warn(
137 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
138 errno, safe_strerror(errno));
139 return -1;
140 }
77b7d90b 141#else
d62a17ae 142 zlog_warn(
143 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
77b7d90b 144#endif
d62a17ae 145 }
146
147 return 0;
12e41d03
DL
148}
149
2b64873d 150static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
d62a17ae 151 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
152
153static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
154 const struct igmpmsg *msg)
12e41d03 155{
d62a17ae 156 struct pim_interface *pim_ifp = ifp->info;
157 struct pim_upstream *up;
158 struct pim_rpf *rpg;
159 struct prefix_sg sg;
160
b575a12c 161 rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
d62a17ae 162 /*
163 * If the incoming interface is unknown OR
164 * the Interface type is SSM we don't need to
165 * do anything here
166 */
b5469d02 167 if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) {
d62a17ae 168 if (PIM_DEBUG_MROUTE_DETAIL)
169 zlog_debug(
b5469d02 170 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
15569c58 171 __func__);
b5469d02 172
d62a17ae 173 return 0;
174 }
04b40f02 175
d62a17ae 176 /*
177 * If we've received a multicast packet that isn't connected to
178 * us
179 */
180 if (!pim_if_connected_to_source(ifp, msg->im_src)) {
181 if (PIM_DEBUG_MROUTE_DETAIL)
182 zlog_debug(
183 "%s: Received incoming packet that doesn't originate on our seg",
15569c58 184 __func__);
d62a17ae 185 return 0;
186 }
065bee4b 187
d62a17ae 188 memset(&sg, 0, sizeof(struct prefix_sg));
189 sg.src = msg->im_src;
190 sg.grp = msg->im_dst;
191
b5469d02 192 if (!(PIM_I_am_DR(pim_ifp))) {
b5469d02 193 if (PIM_DEBUG_MROUTE_DETAIL)
15569c58
DA
194 zlog_debug(
195 "%s: Interface is not the DR blackholing incoming traffic for %s",
196 __func__, pim_str_sg_dump(&sg));
b5469d02
DS
197
198 /*
199 * We are not the DR, but we are still receiving packets
200 * Let's blackhole those packets for the moment
201 * As that they will be coming up to the cpu
202 * and causing us to consider them.
9e132a49
DS
203 *
204 * This *will* create a dangling channel_oil
205 * that I see no way to get rid of. Just noting
206 * this for future reference.
b5469d02 207 */
02434c43 208 up = pim_upstream_find_or_add(
15569c58
DA
209 &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
210 pim_upstream_mroute_add(up->channel_oil, __func__);
b5469d02
DS
211
212 return 0;
213 }
214
d62a17ae 215 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
15569c58 216 __func__);
c29a5806 217
d62a17ae 218 /*
219 * I moved this debug till after the actual add because
220 * I want to take advantage of the up->sg_str being filled in.
221 */
222 if (PIM_DEBUG_MROUTE) {
223 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
15569c58 224 __func__, up->sg_str);
d62a17ae 225 }
8bfb8b67 226
d62a17ae 227 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
19b807ca 228 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
d62a17ae 229
230 up->channel_oil->cc.pktcnt++;
d62a17ae 231 // resolve mfcc_parent prior to mroute_add in channel_add_oif
957d93ea
SP
232 if (up->rpf.source_nexthop.interface &&
233 up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
7984af18 234 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
d62a17ae 235 }
236 pim_register_join(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;
448 struct pim_ifchannel *ch;
449 struct pim_upstream *up;
450 struct prefix_sg star_g;
451 struct prefix_sg sg;
d62a17ae 452
fec883d9
DS
453 pim_ifp = ifp->info;
454
d62a17ae 455 memset(&sg, 0, sizeof(struct prefix_sg));
456 sg.src = ip_hdr->ip_src;
457 sg.grp = ip_hdr->ip_dst;
458
459 ch = pim_ifchannel_find(ifp, &sg);
460 if (ch) {
461 if (PIM_DEBUG_MROUTE)
462 zlog_debug(
463 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
464 ch->sg_str, ifp->name);
465 return -1;
466 }
b7ddd2ec 467
d62a17ae 468 star_g = sg;
469 star_g.src.s_addr = INADDR_ANY;
b7ddd2ec 470#if 0
0490c22d
DS
471 ch = pim_ifchannel_find(ifp, &star_g);
472 if (ch)
473 {
474 if (PIM_DEBUG_MROUTE)
475 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
476 pim_str_sg_dump (&star_g), ifp->name);
477 return -1;
478 }
5cd11e3c 479#endif
08e1fe76 480
9b29ea95 481 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 482 if (up) {
483 struct pim_upstream *parent;
484 struct pim_nexthop source;
fec883d9 485 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
d62a17ae 486 if (!rpf || !rpf->source_nexthop.interface)
487 return 0;
488
489 /*
490 * If we have received a WRVIFWHOLE and are at this
491 * point, we could be receiving the packet on the *,G
492 * tree, let's check and if so we can safely drop
493 * it.
494 */
9b29ea95 495 parent = pim_upstream_find(pim_ifp->pim, &star_g);
d62a17ae 496 if (parent && parent->rpf.source_nexthop.interface == ifp)
497 return 0;
498
499 pim_ifp = rpf->source_nexthop.interface->info;
500
501 memset(&source, 0, sizeof(source));
502 /*
503 * If we are the fhr that means we are getting a callback during
504 * the pimreg period, so I believe we can ignore this packet
505 */
506 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
507 // No if channel, but upstream we are at the RP.
d9c9a9ee 508 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1 509 up->upstream_register, 0)) {
d62a17ae 510 pim_register_stop_send(source.interface, &sg,
511 pim_ifp->primary_address,
512 up->upstream_register);
df766618
DS
513 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
514 }
46dd6edb 515
9b29ea95 516 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 517 if (!up->channel_oil->installed)
69e3538c 518 pim_upstream_mroute_add(up->channel_oil,
15569c58 519 __func__);
d62a17ae 520 } else {
d9c9a9ee
DS
521 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
522 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1
DS
523 up->upstream_register,
524 0))
d62a17ae 525 pim_register_stop_send(
526 source.interface, &sg,
527 pim_ifp->primary_address,
528 up->upstream_register);
529 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
530 }
531 pim_upstream_keep_alive_timer_start(
19b807ca 532 up, pim_ifp->pim->keep_alive_time);
9b29ea95 533 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 534 pim_mroute_msg_wholepkt(fd, ifp, buf);
535 }
536 return 0;
537 }
8e38a2cf 538
d62a17ae 539 pim_ifp = ifp->info;
d62a17ae 540 if (pim_if_connected_to_source(ifp, sg.src)) {
2002dcdb 541 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
15569c58
DA
542 PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
543 NULL);
d62a17ae 544 if (!up) {
545 if (PIM_DEBUG_MROUTE)
546 zlog_debug(
547 "%s: WRONGVIF%s unable to create upstream on interface",
548 pim_str_sg_dump(&sg), ifp->name);
549 return -2;
550 }
551 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
996c9314
LB
552 pim_upstream_keep_alive_timer_start(
553 up, pim_ifp->pim->keep_alive_time);
d62a17ae 554 up->channel_oil->cc.pktcnt++;
555 pim_register_join(up);
9b29ea95 556 pim_upstream_inherited_olist(pim_ifp->pim, up);
69e3538c
AK
557 if (!up->channel_oil->installed)
558 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 559
560 // Send the packet to the RP
561 pim_mroute_msg_wholepkt(fd, ifp, buf);
02434c43
DS
562 } else {
563 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
564 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
15569c58 565 __func__, NULL);
02434c43 566 if (!up->channel_oil->installed)
15569c58 567 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 568 }
08e1fe76 569
d62a17ae 570 return 0;
08e1fe76
DS
571}
572
405d6357 573static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
90450a3d 574 int buf_size, ifindex_t ifindex)
e355e30f 575{
d62a17ae 576 struct interface *ifp;
577 struct pim_interface *pim_ifp;
578 const struct ip *ip_hdr;
579 const struct igmpmsg *msg;
580 char ip_src_str[INET_ADDRSTRLEN] = "";
581 char ip_dst_str[INET_ADDRSTRLEN] = "";
582 char src_str[INET_ADDRSTRLEN] = "<src?>";
583 char grp_str[INET_ADDRSTRLEN] = "<grp?>";
584 struct in_addr ifaddr;
585 struct igmp_sock *igmp;
586
f08e6750
QY
587 if (buf_size < (int)sizeof(struct ip))
588 return 0;
589
d62a17ae 590 ip_hdr = (const struct ip *)buf;
591
592 if (ip_hdr->ip_p == IPPROTO_IGMP) {
593
594 /* We have the IP packet but we do not know which interface this
595 * packet was
596 * received on. Find the interface that is on the same subnet as
597 * the source
598 * of the IP packet.
599 */
90450a3d 600 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
d62a17ae 601
1ef8c24e 602 if (!ifp || !ifp->info)
d62a17ae 603 return 0;
90450a3d 604
d62a17ae 605 pim_ifp = ifp->info;
606 ifaddr = pim_find_primary_addr(ifp);
607 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
608 ifaddr);
609
610 if (PIM_DEBUG_MROUTE) {
611 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
612 sizeof(ip_src_str));
613 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
614 sizeof(ip_dst_str));
615
fb9670aa 616 zlog_debug(
7c2bfc2a 617 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
15569c58
DA
618 __func__, pim->vrf->name, ifp->name, igmp,
619 ip_src_str, ip_dst_str);
d62a17ae 620 }
621 if (igmp)
622 pim_igmp_packet(igmp, (char *)buf, buf_size);
623
624 } else if (ip_hdr->ip_p) {
625 if (PIM_DEBUG_MROUTE_DETAIL) {
626 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
627 sizeof(src_str));
628 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
629 sizeof(grp_str));
630 zlog_debug(
631 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
15569c58
DA
632 __func__, ip_hdr->ip_p, src_str, grp_str,
633 buf_size);
d62a17ae 634 }
635
636 } else {
637 msg = (const struct igmpmsg *)buf;
638
7cfc7bcf 639 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
d62a17ae 640
641 if (!ifp)
642 return 0;
643 if (PIM_DEBUG_MROUTE) {
644 pim_inet4_dump("<src?>", msg->im_src, src_str,
645 sizeof(src_str));
646 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
647 sizeof(grp_str));
fb9670aa 648 zlog_debug(
d62a17ae 649 "%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 650 __func__, igmpmsgtype2str[msg->im_msgtype],
405d6357
DS
651 msg->im_msgtype, ip_hdr->ip_p,
652 pim->mroute_socket, src_str, grp_str, ifp->name,
653 msg->im_vif, buf_size);
d62a17ae 654 }
655
656 switch (msg->im_msgtype) {
657 case IGMPMSG_WRONGVIF:
405d6357
DS
658 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
659 msg);
d62a17ae 660 break;
661 case IGMPMSG_NOCACHE:
405d6357
DS
662 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
663 msg);
d62a17ae 664 break;
665 case IGMPMSG_WHOLEPKT:
405d6357 666 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
d62a17ae 667 (const char *)msg);
668 break;
669 case IGMPMSG_WRVIFWHOLE:
405d6357
DS
670 return pim_mroute_msg_wrvifwhole(
671 pim->mroute_socket, ifp, (const char *)msg);
d62a17ae 672 break;
673 default:
674 break;
675 }
676 }
12e41d03 677
d62a17ae 678 return 0;
12e41d03
DL
679}
680
12e41d03
DL
681static int mroute_read(struct thread *t)
682{
8ea5d944 683 struct pim_instance *pim;
d62a17ae 684 static long long count;
685 char buf[10000];
686 int result = 0;
687 int cont = 1;
d62a17ae 688 int rd;
90450a3d 689 ifindex_t ifindex;
8ea5d944 690 pim = THREAD_ARG(t);
d62a17ae 691
692 while (cont) {
90450a3d
DS
693 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
694 sizeof(buf), NULL, NULL, NULL, NULL,
695 &ifindex);
61e99c94 696 if (rd <= 0) {
d62a17ae 697 if (errno == EINTR)
698 continue;
699 if (errno == EWOULDBLOCK || errno == EAGAIN)
700 break;
701
15569c58
DA
702 zlog_warn(
703 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
704 __func__, rd, pim->mroute_socket, errno,
705 safe_strerror(errno));
d62a17ae 706 goto done;
707 }
708
90450a3d 709 result = pim_mroute_msg(pim, buf, rd, ifindex);
d62a17ae 710
711 count++;
75373cca 712 if (count % router->packet_process == 0)
d62a17ae 713 cont = 0;
714 }
715/* Keep reading */
716done:
8ea5d944 717 mroute_read_on(pim);
12e41d03 718
d62a17ae 719 return result;
12e41d03
DL
720}
721
8ea5d944 722static void mroute_read_on(struct pim_instance *pim)
12e41d03 723{
36417fcc 724 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
8ea5d944 725 &pim->thread);
12e41d03
DL
726}
727
8ea5d944 728static void mroute_read_off(struct pim_instance *pim)
12e41d03 729{
8ea5d944 730 THREAD_OFF(pim->thread);
12e41d03
DL
731}
732
6beed987 733int pim_mroute_socket_enable(struct pim_instance *pim)
12e41d03 734{
d62a17ae 735 int fd;
12e41d03 736
0cf6db21 737 frr_with_privs(&pimd_privs) {
12e41d03 738
01b9e3fd 739 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
12e41d03 740
01b9e3fd
DL
741 if (fd < 0) {
742 zlog_warn("Could not create mroute socket: errno=%d: %s",
743 errno,
744 safe_strerror(errno));
745 return -2;
746 }
e691f179 747
466e4e5b 748#ifdef SO_BINDTODEVICE
01b9e3fd 749 if (pim->vrf->vrf_id != VRF_DEFAULT
633fc9b1
DL
750 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
751 pim->vrf->name, strlen(pim->vrf->name))) {
01b9e3fd
DL
752 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
753 safe_strerror(errno));
754 close(fd);
755 return -3;
756 }
466e4e5b 757#endif
90450a3d 758
01b9e3fd 759 }
12e41d03 760
cdbfaec5
DS
761 pim->mroute_socket = fd;
762 if (pim_mroute_set(pim, 1)) {
d62a17ae 763 zlog_warn(
764 "Could not enable mroute on socket fd=%d: errno=%d: %s",
765 fd, errno, safe_strerror(errno));
766 close(fd);
cdbfaec5 767 pim->mroute_socket = -1;
d62a17ae 768 return -3;
769 }
12e41d03 770
6beed987 771 pim->mroute_socket_creation = pim_time_monotonic_sec();
b45cefcb 772
8ea5d944 773 mroute_read_on(pim);
12e41d03 774
d62a17ae 775 return 0;
12e41d03
DL
776}
777
6beed987 778int pim_mroute_socket_disable(struct pim_instance *pim)
12e41d03 779{
cdbfaec5 780 if (pim_mroute_set(pim, 0)) {
d62a17ae 781 zlog_warn(
782 "Could not disable mroute on socket fd=%d: errno=%d: %s",
405d6357 783 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 784 return -2;
785 }
786
6beed987 787 if (close(pim->mroute_socket)) {
d62a17ae 788 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
405d6357 789 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 790 return -3;
791 }
792
8ea5d944 793 mroute_read_off(pim);
6beed987 794 pim->mroute_socket = -1;
d62a17ae 795
796 return 0;
12e41d03
DL
797}
798
799/*
800 For each network interface (e.g., physical or a virtual tunnel) that
801 would be used for multicast forwarding, a corresponding multicast
802 interface must be added to the kernel.
803 */
d62a17ae 804int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
805 unsigned char flags)
12e41d03 806{
d62a17ae 807 struct pim_interface *pim_ifp = ifp->info;
808 struct vifctl vc;
809 int err;
12e41d03 810
08f4f901 811 if (PIM_DEBUG_MROUTE)
15569c58 812 zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
996c9314
LB
813 pim_ifp->mroute_vif_index, ifp->name,
814 pim_ifp->pim->vrf->name);
08f4f901 815
d62a17ae 816 memset(&vc, 0, sizeof(vc));
817 vc.vifc_vifi = pim_ifp->mroute_vif_index;
b3f2bf7c 818#ifdef VIFF_USE_IFINDEX
d62a17ae 819 vc.vifc_lcl_ifindex = ifp->ifindex;
b3f2bf7c 820#else
d62a17ae 821 if (ifaddr.s_addr == INADDR_ANY) {
822 zlog_warn(
823 "%s: unnumbered interfaces are not supported on this platform",
15569c58 824 __func__);
d62a17ae 825 return -1;
826 }
827 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
b3f2bf7c 828#endif
d62a17ae 829 vc.vifc_flags = flags;
830 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
831 vc.vifc_rate_limit = 0;
832
833#ifdef PIM_DVMRP_TUNNEL
834 if (vc.vifc_flags & VIFF_TUNNEL) {
835 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
836 sizeof(vc.vifc_rmt_addr));
837 }
12e41d03
DL
838#endif
839
ea3d967b 840 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
d62a17ae 841 (void *)&vc, sizeof(vc));
842 if (err) {
843 char ifaddr_str[INET_ADDRSTRLEN];
12e41d03 844
d62a17ae 845 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
846 sizeof(ifaddr_str));
12e41d03 847
d62a17ae 848 zlog_warn(
08f4f901 849 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
15569c58
DA
850 __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
851 ifaddr_str, flags, errno, safe_strerror(errno));
d62a17ae 852 return -2;
853 }
12e41d03 854
d62a17ae 855 return 0;
12e41d03
DL
856}
857
ea3d967b 858int pim_mroute_del_vif(struct interface *ifp)
12e41d03 859{
ea3d967b 860 struct pim_interface *pim_ifp = ifp->info;
d62a17ae 861 struct vifctl vc;
862 int err;
863
ea3d967b 864 if (PIM_DEBUG_MROUTE)
15569c58 865 zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
996c9314
LB
866 pim_ifp->mroute_vif_index, ifp->name,
867 pim_ifp->pim->vrf->name);
12e41d03 868
d62a17ae 869 memset(&vc, 0, sizeof(vc));
ea3d967b 870 vc.vifc_vifi = pim_ifp->mroute_vif_index;
d62a17ae 871
ea3d967b 872 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
d62a17ae 873 (void *)&vc, sizeof(vc));
874 if (err) {
875 zlog_warn(
876 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
15569c58
DA
877 __FILE__, __func__, pim_ifp->pim->mroute_socket,
878 pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
d62a17ae 879 return -2;
880 }
12e41d03 881
d62a17ae 882 return 0;
12e41d03
DL
883}
884
60eb7e6b
AK
885/*
886 * Prevent creating MFC entry with OIF=IIF.
887 *
888 * This is a protection against implementation mistakes.
889 *
890 * PIM protocol implicitely ensures loopfree multicast topology.
891 *
892 * IGMP must be protected against adding looped MFC entries created
893 * by both source and receiver attached to the same interface. See
894 * TODO T22.
895 * We shall allow igmp to create upstream when it is DR for the intf.
896 * Assume RP reachable via non DR.
897 */
898bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
899 int oif_index)
900{
901#ifdef PIM_ENFORCE_LOOPFREE_MFC
902 struct interface *ifp_out;
903 struct pim_interface *pim_ifp;
904
905 if (c_oil->up &&
906 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
907 return true;
908
909 ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
910 if (!ifp_out)
911 return false;
912 pim_ifp = ifp_out->info;
913 if (!pim_ifp)
914 return false;
915 if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_IGMP) &&
916 PIM_I_am_DR(pim_ifp))
917 return true;
918
919 return false;
920#else
921 return true;
922#endif
923}
924
5a5f404e
AK
925static inline void pim_mroute_copy(struct mfcctl *oil,
926 struct channel_oil *c_oil)
927{
928 int i;
929
930 oil->mfcc_origin = c_oil->oil.mfcc_origin;
931 oil->mfcc_mcastgrp = c_oil->oil.mfcc_mcastgrp;
932 oil->mfcc_parent = c_oil->oil.mfcc_parent;
933
934 for (i = 0; i < MAXVIFS; ++i) {
60eb7e6b
AK
935 if ((oil->mfcc_parent == i) &&
936 !pim_mroute_allow_iif_in_oil(c_oil, i)) {
937 oil->mfcc_ttls[i] = 0;
938 continue;
939 }
940
5a5f404e
AK
941 if (c_oil->oif_flags[i] & PIM_OIF_FLAG_MUTE)
942 oil->mfcc_ttls[i] = 0;
943 else
944 oil->mfcc_ttls[i] = c_oil->oil.mfcc_ttls[i];
945 }
946}
947
69e3538c
AK
948/* This function must not be called directly 0
949 * use pim_upstream_mroute_add or pim_static_mroute_add instead
950 */
951static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
12e41d03 952{
9a0f71c9 953 struct pim_instance *pim = c_oil->pim;
5a5f404e 954 struct mfcctl tmp_oil;
d62a17ae 955 int err;
d62a17ae 956
856e863f
DS
957 pim->mroute_add_last = pim_time_monotonic_sec();
958 ++pim->mroute_add_events;
d62a17ae 959
5a5f404e
AK
960 /* Copy the oil to a temporary structure to fixup (without need to
961 * later restore) before sending the mroute add to the dataplane
962 */
963 pim_mroute_copy(&tmp_oil, c_oil);
d3aded99 964
d62a17ae 965 /* The linux kernel *expects* the incoming
966 * vif to be part of the outgoing list
967 * in the case of a (*,G).
968 */
969 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
5a5f404e 970 tmp_oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
76e4825a
AK
971 }
972
d62a17ae 973 /*
974 * If we have an unresolved cache entry for the S,G
975 * it is owned by the pimreg for the incoming IIF
976 * So set pimreg as the IIF temporarily to cause
977 * the packets to be forwarded. Then set it
978 * to the correct IIF afterwords.
979 */
980 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
981 && c_oil->oil.mfcc_parent != 0) {
5a5f404e 982 tmp_oil.mfcc_parent = 0;
d62a17ae 983 }
856e863f 984 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
5a5f404e 985 &tmp_oil, sizeof(tmp_oil));
d62a17ae 986
987 if (!err && !c_oil->installed
988 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
5a5f404e
AK
989 && c_oil->oil.mfcc_parent != 0) {
990 tmp_oil.mfcc_parent = c_oil->oil.mfcc_parent;
856e863f 991 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
5a5f404e 992 &tmp_oil, sizeof(tmp_oil));
42e01756 993 }
37c3fd98 994
d62a17ae 995 if (err) {
996 zlog_warn(
997 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
15569c58
DA
998 __FILE__, __func__, pim->mroute_socket, errno,
999 safe_strerror(errno));
d62a17ae 1000 return -2;
1001 }
12e41d03 1002
d62a17ae 1003 if (PIM_DEBUG_MROUTE) {
1004 char buf[1000];
15569c58
DA
1005 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
1006 pim->vrf->name,
d62a17ae 1007 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1008 }
6a78764e 1009
d62a17ae 1010 c_oil->installed = 1;
e7cd85bd
SP
1011 c_oil->mroute_creation = pim_time_monotonic_sec();
1012
d62a17ae 1013 return 0;
12e41d03
DL
1014}
1015
7984af18
AK
1016static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
1017 const char *name)
69e3538c
AK
1018{
1019 vifi_t iif = MAXVIFS;
69e3538c
AK
1020 struct interface *ifp = NULL;
1021 struct pim_interface *pim_ifp;
1022 struct pim_upstream *up = c_oil->up;
1023
1024 if (up) {
1025 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
1026 if (up->parent)
1027 ifp = up->parent->rpf.source_nexthop.interface;
1028 } else {
1029 ifp = up->rpf.source_nexthop.interface;
1030 }
1031 if (ifp) {
1032 pim_ifp = (struct pim_interface *)ifp->info;
1033 if (pim_ifp)
1034 iif = pim_ifp->mroute_vif_index;
1035 }
1036 }
7984af18
AK
1037 return iif;
1038}
69e3538c 1039
7984af18
AK
1040static int pim_upstream_mroute_update(struct channel_oil *c_oil,
1041 const char *name)
1042{
1043 char buf[1000];
69e3538c
AK
1044
1045 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
1046 /* the c_oil cannot be installed as a mroute yet */
1047 if (PIM_DEBUG_MROUTE)
1048 zlog_debug(
1049 "%s(%s) %s mroute not ready to be installed; %s",
7984af18 1050 __func__, name,
69e3538c
AK
1051 pim_channel_oil_dump(c_oil, buf,
1052 sizeof(buf)),
1053 c_oil->installed ?
1054 "uninstall" : "skip");
1055 /* if already installed flush it out as we are going to stop
1056 * updates to it leaving it in a stale state
1057 */
1058 if (c_oil->installed)
1059 pim_mroute_del(c_oil, name);
1060 /* return success (skipped) */
1061 return 0;
1062 }
1063
1064 return pim_mroute_add(c_oil, name);
1065}
1066
70c86421
AK
1067/* IIF associated with SGrpt entries are re-evaluated when the parent
1068 * (*,G) entries IIF changes
1069 */
1070static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
1071{
1072 struct listnode *listnode;
1073 struct pim_upstream *child;
1074
1075 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
1076 child)) {
1077 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
1078 pim_upstream_mroute_iif_update(child->channel_oil,
1079 __func__);
1080 }
1081}
1082
7984af18
AK
1083/* In the case of "PIM state machine" added mroutes an upstream entry
1084 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1085 */
1086int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
1087{
70c86421
AK
1088 vifi_t iif;
1089
1090 iif = pim_upstream_get_mroute_iif(c_oil, name);
1091
1092 if (c_oil->oil.mfcc_parent != iif) {
1093 c_oil->oil.mfcc_parent = iif;
1094 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY &&
1095 c_oil->up)
1096 pim_upstream_all_sources_iif_update(c_oil->up);
1097 } else {
1098 c_oil->oil.mfcc_parent = iif;
1099 }
7984af18
AK
1100
1101 return pim_upstream_mroute_update(c_oil, name);
1102}
1103
1104/* Look for IIF changes and update the dateplane entry only if the IIF
1105 * has changed.
1106 */
1107int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
1108{
1109 vifi_t iif;
1110 char buf[1000];
1111
1112 iif = pim_upstream_get_mroute_iif(c_oil, name);
1113 if (c_oil->oil.mfcc_parent == iif) {
1114 /* no change */
1115 return 0;
1116 }
1117 c_oil->oil.mfcc_parent = iif;
1118
70c86421
AK
1119 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY &&
1120 c_oil->up)
1121 pim_upstream_all_sources_iif_update(c_oil->up);
1122
7984af18
AK
1123 if (PIM_DEBUG_MROUTE_DETAIL)
1124 zlog_debug("%s(%s) %s mroute iif update %d",
1125 __func__, name,
1126 pim_channel_oil_dump(c_oil, buf,
1127 sizeof(buf)), iif);
1128 /* XXX: is this hack needed? */
1129 c_oil->oil_inherited_rescan = 1;
1130 return pim_upstream_mroute_update(c_oil, name);
1131}
1132
69e3538c
AK
1133int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
1134{
1135 return pim_mroute_add(c_oil, name);
1136}
1137
7984af18
AK
1138void pim_static_mroute_iif_update(struct channel_oil *c_oil,
1139 int input_vif_index,
1140 const char *name)
1141{
1142 if (c_oil->oil.mfcc_parent == input_vif_index)
1143 return;
1144
1145 c_oil->oil.mfcc_parent = input_vif_index;
1146 if (input_vif_index == MAXVIFS)
1147 pim_mroute_del(c_oil, name);
1148 else
1149 pim_static_mroute_add(c_oil, name);
1150}
1151
d62a17ae 1152int pim_mroute_del(struct channel_oil *c_oil, const char *name)
12e41d03 1153{
9a0f71c9 1154 struct pim_instance *pim = c_oil->pim;
d62a17ae 1155 int err;
1156
856e863f
DS
1157 pim->mroute_del_last = pim_time_monotonic_sec();
1158 ++pim->mroute_del_events;
d62a17ae 1159
1160 if (!c_oil->installed) {
1161 if (PIM_DEBUG_MROUTE) {
1162 char buf[1000];
1163 zlog_debug(
1164 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
15569c58 1165 __FILE__, __func__, c_oil->oil.mfcc_parent,
d62a17ae 1166 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1167 }
1168 return -2;
1169 }
12e41d03 1170
856e863f 1171 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
d62a17ae 1172 &c_oil->oil, sizeof(c_oil->oil));
1173 if (err) {
1174 if (PIM_DEBUG_MROUTE)
1175 zlog_warn(
1176 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
15569c58 1177 __FILE__, __func__, pim->mroute_socket, errno,
d62a17ae 1178 safe_strerror(errno));
1179 return -2;
1180 }
429a291b 1181
d62a17ae 1182 if (PIM_DEBUG_MROUTE) {
1183 char buf[1000];
15569c58
DA
1184 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
1185 pim->vrf->name,
d62fd596 1186 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
d62a17ae 1187 }
781a1745 1188
d62a17ae 1189 // Reset kernel installed flag
1190 c_oil->installed = 0;
58302dc7 1191
d62a17ae 1192 return 0;
12e41d03 1193}
3667e8a0 1194
d62a17ae 1195void pim_mroute_update_counters(struct channel_oil *c_oil)
3667e8a0 1196{
9a0f71c9 1197 struct pim_instance *pim = c_oil->pim;
d62a17ae 1198 struct sioc_sg_req sgreq;
1199
1200 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1201 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1202 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1203
1204 if (!c_oil->installed) {
19b807ca 1205 c_oil->cc.lastused = 100 * pim->keep_alive_time;
d62a17ae 1206 if (PIM_DEBUG_MROUTE) {
1207 struct prefix_sg sg;
1208
1209 sg.src = c_oil->oil.mfcc_origin;
1210 sg.grp = c_oil->oil.mfcc_mcastgrp;
1211 if (PIM_DEBUG_MROUTE)
1212 zlog_debug(
41714081 1213 "Channel%s is not installed no need to collect data from kernel",
d62a17ae 1214 pim_str_sg_dump(&sg));
1215 }
1216 return;
c7b1183f 1217 }
c7b1183f 1218
d62a17ae 1219 memset(&sgreq, 0, sizeof(sgreq));
1220 sgreq.src = c_oil->oil.mfcc_origin;
1221 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1222
1223 pim_zlookup_sg_statistics(c_oil);
856e863f 1224 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
fb9670aa 1225 struct prefix_sg sg;
d62a17ae 1226
fb9670aa
DS
1227 sg.src = c_oil->oil.mfcc_origin;
1228 sg.grp = c_oil->oil.mfcc_mcastgrp;
d62a17ae 1229
fb9670aa
DS
1230 zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
1231 (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg),
1232 errno, safe_strerror(errno));
d62a17ae 1233 return;
c7b1183f 1234 }
3667e8a0 1235
d62a17ae 1236 c_oil->cc.pktcnt = sgreq.pktcnt;
1237 c_oil->cc.bytecnt = sgreq.bytecnt;
1238 c_oil->cc.wrong_if = sgreq.wrong_if;
3667e8a0 1239
d62a17ae 1240 return;
3667e8a0 1241}