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