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