]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
tests: Reduce some pim test timings to more manageable levels
[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"
a5fa9822 46#include "pim_msg.h"
12e41d03 47
8ea5d944 48static void mroute_read_on(struct pim_instance *pim);
12e41d03 49
d62a17ae 50
a5fa9822 51int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
12e41d03 52{
d62a17ae 53 struct pim_interface *pim_ifp = ifp->info;
54 struct pim_upstream *up;
55 struct pim_rpf *rpg;
6fff2cc6 56 pim_sgaddr sg;
d62a17ae 57
a5fa9822 58 rpg = pim_ifp ? RP(pim_ifp->pim, msg->msg_im_dst) : NULL;
d62a17ae 59 /*
60 * If the incoming interface is unknown OR
61 * the Interface type is SSM we don't need to
62 * do anything here
63 */
cc144e8b 64 if (!rpg || pim_rpf_addr_is_inaddr_any(rpg)) {
d62a17ae 65 if (PIM_DEBUG_MROUTE_DETAIL)
66 zlog_debug(
b5469d02 67 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
15569c58 68 __func__);
b5469d02 69
d62a17ae 70 return 0;
71 }
04b40f02 72
d62a17ae 73 /*
74 * If we've received a multicast packet that isn't connected to
75 * us
76 */
a5fa9822 77 if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) {
d62a17ae 78 if (PIM_DEBUG_MROUTE_DETAIL)
79 zlog_debug(
80 "%s: Received incoming packet that doesn't originate on our seg",
15569c58 81 __func__);
d62a17ae 82 return 0;
83 }
065bee4b 84
6fff2cc6 85 memset(&sg, 0, sizeof(sg));
a5fa9822 86 sg.src = msg->msg_im_src;
87 sg.grp = msg->msg_im_dst;
d62a17ae 88
b5469d02 89 if (!(PIM_I_am_DR(pim_ifp))) {
b5469d02 90 if (PIM_DEBUG_MROUTE_DETAIL)
a5fa9822 91 zlog_debug(
92 "%s: Interface is not the DR blackholing incoming traffic for %pSG",
93 __func__, &sg);
b5469d02
DS
94
95 /*
96 * We are not the DR, but we are still receiving packets
97 * Let's blackhole those packets for the moment
98 * As that they will be coming up to the cpu
99 * and causing us to consider them.
9e132a49
DS
100 *
101 * This *will* create a dangling channel_oil
102 * that I see no way to get rid of. Just noting
103 * this for future reference.
b5469d02 104 */
02434c43 105 up = pim_upstream_find_or_add(
15569c58
DA
106 &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
107 pim_upstream_mroute_add(up->channel_oil, __func__);
b5469d02
DS
108
109 return 0;
110 }
111
d62a17ae 112 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
15569c58 113 __func__);
c29a5806 114
d62a17ae 115 /*
116 * I moved this debug till after the actual add because
117 * I want to take advantage of the up->sg_str being filled in.
118 */
119 if (PIM_DEBUG_MROUTE) {
120 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
15569c58 121 __func__, up->sg_str);
d62a17ae 122 }
8bfb8b67 123
d62a17ae 124 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
19b807ca 125 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
d62a17ae 126
127 up->channel_oil->cc.pktcnt++;
d62a17ae 128 // resolve mfcc_parent prior to mroute_add in channel_add_oif
957d93ea 129 if (up->rpf.source_nexthop.interface &&
a9338fa4 130 *oil_parent(up->channel_oil) >= MAXVIFS) {
7984af18 131 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
d62a17ae 132 }
133 pim_register_join(up);
ac6c8d54 134 /* if we have receiver, inherit from parent */
135 pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
59471fb8 136
d62a17ae 137 return 0;
e355e30f 138}
12e41d03 139
a5fa9822 140int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf)
e355e30f 141{
d62a17ae 142 struct pim_interface *pim_ifp;
6fff2cc6 143 pim_sgaddr sg;
d62a17ae 144 struct pim_rpf *rpg;
a5fa9822 145 const ipv_hdr *ip_hdr;
d62a17ae 146 struct pim_upstream *up;
147
9b29ea95
DS
148 pim_ifp = ifp->info;
149
a5fa9822 150 ip_hdr = (const ipv_hdr *)buf;
d62a17ae 151
6fff2cc6 152 memset(&sg, 0, sizeof(sg));
a5fa9822 153 sg.src = IPV_SRC(ip_hdr);
154 sg.grp = IPV_DST(ip_hdr);
d62a17ae 155
9b29ea95 156 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 157 if (!up) {
6fff2cc6 158 pim_sgaddr star = sg;
bca160c6 159 star.src = PIMADDR_ANY;
d62a17ae 160
9b29ea95 161 up = pim_upstream_find(pim_ifp->pim, &star);
d62a17ae 162
448139e7 163 if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) {
2002dcdb 164 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
d62a17ae 165 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
15569c58 166 __func__, NULL);
d62a17ae 167 if (!up) {
168 if (PIM_DEBUG_MROUTE)
a5fa9822 169 zlog_debug(
170 "%s: Unable to create upstream information for %pSG",
171 __func__, &sg);
d62a17ae 172 return 0;
173 }
174 pim_upstream_keep_alive_timer_start(
19b807ca 175 up, pim_ifp->pim->keep_alive_time);
9b29ea95 176 pim_upstream_inherited_olist(pim_ifp->pim, up);
a53a9b3e 177 pim_upstream_update_join_desired(pim_ifp->pim, up);
d62a17ae 178
179 if (PIM_DEBUG_MROUTE)
180 zlog_debug("%s: Creating %s upstream on LHR",
15569c58 181 __func__, up->sg_str);
d62a17ae 182 return 0;
183 }
184 if (PIM_DEBUG_MROUTE_DETAIL) {
a5fa9822 185 zlog_debug(
186 "%s: Unable to find upstream channel WHOLEPKT%pSG",
187 __func__, &sg);
d62a17ae 188 }
189 return 0;
190 }
59471fb8 191
957d93ea 192 if (!up->rpf.source_nexthop.interface) {
23fc858a 193 if (PIM_DEBUG_PIM_TRACE)
15569c58
DA
194 zlog_debug("%s: up %s RPF is not present", __func__,
195 up->sg_str);
957d93ea
SP
196 return 0;
197 }
198
d62a17ae 199 pim_ifp = up->rpf.source_nexthop.interface->info;
998af219 200
b575a12c 201 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
c8ae3ce8 202
cc144e8b 203 if ((pim_rpf_addr_is_inaddr_any(rpg)) || (!pim_ifp) ||
204 (!(PIM_I_am_DR(pim_ifp)))) {
d62a17ae 205 if (PIM_DEBUG_MROUTE) {
15569c58 206 zlog_debug("%s: Failed Check send packet", __func__);
d62a17ae 207 }
208 return 0;
209 }
84366c7e 210
d62a17ae 211 /*
212 * If we've received a register suppress
213 */
214 if (!up->t_rs_timer) {
6f439a70 215 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
d62a17ae 216 if (PIM_DEBUG_PIM_REG)
a5fa9822 217 zlog_debug(
218 "%pSG register forward skipped as group is SSM",
219 &sg);
d62a17ae 220 return 0;
221 }
2bc31c44
AK
222
223 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
224 if (PIM_DEBUG_PIM_REG)
225 zlog_debug(
226 "%s register forward skipped, not FHR",
227 up->sg_str);
228 return 0;
229 }
230
a5fa9822 231 pim_register_send((uint8_t *)buf + sizeof(ipv_hdr),
232 ntohs(IPV_LEN(ip_hdr)) - sizeof(ipv_hdr),
d62a17ae 233 pim_ifp->primary_address, rpg, 0, up);
234 }
235 return 0;
e355e30f 236}
12e41d03 237
a5fa9822 238int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, const kernmsg *msg)
e355e30f 239{
d62a17ae 240 struct pim_ifchannel *ch;
241 struct pim_interface *pim_ifp;
6fff2cc6 242 pim_sgaddr sg;
d62a17ae 243
6fff2cc6 244 memset(&sg, 0, sizeof(sg));
a5fa9822 245 sg.src = msg->msg_im_src;
246 sg.grp = msg->msg_im_dst;
d62a17ae 247
248 /*
249 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
250
251 RFC 4601 4.8.2. PIM-SSM-Only Routers
252
253 iif is the incoming interface of the packet.
254 if (iif is in inherited_olist(S,G)) {
255 send Assert(S,G) on iif
256 }
257 */
258
259 if (!ifp) {
260 if (PIM_DEBUG_MROUTE)
a5fa9822 261 zlog_debug(
262 "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
263 __func__, &sg, msg->msg_im_vif);
d62a17ae 264 return -1;
265 }
12e41d03 266
d62a17ae 267 pim_ifp = ifp->info;
268 if (!pim_ifp) {
269 if (PIM_DEBUG_MROUTE)
a5fa9822 270 zlog_debug(
271 "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
272 __func__, &sg, ifp->name);
d62a17ae 273 return -2;
274 }
c29a5806 275
d62a17ae 276 ch = pim_ifchannel_find(ifp, &sg);
277 if (!ch) {
6fff2cc6 278 pim_sgaddr star_g = sg;
d62a17ae 279 if (PIM_DEBUG_MROUTE)
a5fa9822 280 zlog_debug(
281 "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
282 __func__, &sg, ifp->name);
d62a17ae 283
bca160c6 284 star_g.src = PIMADDR_ANY;
d62a17ae 285 ch = pim_ifchannel_find(ifp, &star_g);
286 if (!ch) {
287 if (PIM_DEBUG_MROUTE)
a5fa9822 288 zlog_debug(
289 "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
290 __func__, &star_g, ifp->name);
d62a17ae 291 return -3;
292 }
293 }
12e41d03 294
d62a17ae 295 /*
296 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
297
298 Transitions from NoInfo State
299
300 An (S,G) data packet arrives on interface I, AND
301 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
302 downstream interface that is in our (S,G) outgoing interface
303 list. We optimistically assume that we will be the assert
304 winner for this (S,G), and so we transition to the "I am Assert
305 Winner" state and perform Actions A1 (below), which will
306 initiate the assert negotiation for (S,G).
307 */
308
309 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
310 if (PIM_DEBUG_MROUTE) {
311 zlog_debug(
312 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
15569c58 313 __func__, ch->sg_str, ifp->name);
d62a17ae 314 }
315 return -4;
316 }
e355e30f 317
d62a17ae 318 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
319 if (PIM_DEBUG_MROUTE) {
320 zlog_debug(
321 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
15569c58 322 __func__, ch->sg_str, ifp->name);
d62a17ae 323 }
324 return -5;
325 }
326
327 if (assert_action_a1(ch)) {
328 if (PIM_DEBUG_MROUTE) {
329 zlog_debug(
330 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
15569c58 331 __func__, ch->sg_str, ifp->name);
d62a17ae 332 }
333 return -6;
334 }
e355e30f 335
d62a17ae 336 return 0;
e355e30f
DS
337}
338
a5fa9822 339int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf)
08e1fe76 340{
a5fa9822 341 const ipv_hdr *ip_hdr = (const ipv_hdr *)buf;
d62a17ae 342 struct pim_interface *pim_ifp;
a054f6d7 343 struct pim_instance *pim;
d62a17ae 344 struct pim_ifchannel *ch;
345 struct pim_upstream *up;
6fff2cc6
DL
346 pim_sgaddr star_g;
347 pim_sgaddr sg;
d62a17ae 348
fec883d9
DS
349 pim_ifp = ifp->info;
350
6fff2cc6 351 memset(&sg, 0, sizeof(sg));
a5fa9822 352 sg.src = IPV_SRC(ip_hdr);
353 sg.grp = IPV_DST(ip_hdr);
d62a17ae 354
355 ch = pim_ifchannel_find(ifp, &sg);
356 if (ch) {
357 if (PIM_DEBUG_MROUTE)
358 zlog_debug(
359 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
360 ch->sg_str, ifp->name);
361 return -1;
362 }
b7ddd2ec 363
d62a17ae 364 star_g = sg;
bca160c6 365 star_g.src = PIMADDR_ANY;
a054f6d7
DS
366
367 pim = pim_ifp->pim;
368 /*
369 * If the incoming interface is the pimreg, then
370 * we know the callback is associated with a pim register
371 * packet and there is nothing to do here as that
372 * normal pim processing will see the packet and allow
373 * us to do the right thing.
374 */
375 if (ifp == pim->regiface) {
376 return 0;
377 }
08e1fe76 378
9b29ea95 379 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 380 if (up) {
381 struct pim_upstream *parent;
382 struct pim_nexthop source;
fec883d9 383 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
c783249b 384
385 /* No RPF or No RPF interface or No mcast on RPF interface */
a5fa9822 386 if (!rpf || !rpf->source_nexthop.interface ||
387 !rpf->source_nexthop.interface->info)
d62a17ae 388 return 0;
389
390 /*
391 * If we have received a WRVIFWHOLE and are at this
392 * point, we could be receiving the packet on the *,G
393 * tree, let's check and if so we can safely drop
394 * it.
395 */
9b29ea95 396 parent = pim_upstream_find(pim_ifp->pim, &star_g);
d62a17ae 397 if (parent && parent->rpf.source_nexthop.interface == ifp)
398 return 0;
399
400 pim_ifp = rpf->source_nexthop.interface->info;
401
402 memset(&source, 0, sizeof(source));
403 /*
404 * If we are the fhr that means we are getting a callback during
405 * the pimreg period, so I believe we can ignore this packet
406 */
407 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
aeb67246
DS
408 /*
409 * No if channel, but upstream we are at the RP.
410 *
411 * This could be a anycast RP too and we may
412 * not have received a register packet from
413 * the source here at all. So gracefully
414 * bow out of doing a nexthop lookup and
415 * setting the SPTBIT to true
416 */
a5fa9822 417 if (!(pim_addr_is_any(up->upstream_register)) &&
aeb67246 418 pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1 419 up->upstream_register, 0)) {
d62a17ae 420 pim_register_stop_send(source.interface, &sg,
421 pim_ifp->primary_address,
422 up->upstream_register);
df766618
DS
423 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
424 }
46dd6edb 425
9b29ea95 426 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 427 if (!up->channel_oil->installed)
69e3538c 428 pim_upstream_mroute_add(up->channel_oil,
15569c58 429 __func__);
d62a17ae 430 } else {
d9c9a9ee
DS
431 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
432 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1
DS
433 up->upstream_register,
434 0))
d62a17ae 435 pim_register_stop_send(
436 source.interface, &sg,
437 pim_ifp->primary_address,
438 up->upstream_register);
439 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
440 }
441 pim_upstream_keep_alive_timer_start(
19b807ca 442 up, pim_ifp->pim->keep_alive_time);
9b29ea95 443 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 444 pim_mroute_msg_wholepkt(fd, ifp, buf);
445 }
446 return 0;
447 }
8e38a2cf 448
d62a17ae 449 pim_ifp = ifp->info;
d62a17ae 450 if (pim_if_connected_to_source(ifp, sg.src)) {
2002dcdb 451 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
15569c58
DA
452 PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
453 NULL);
d62a17ae 454 if (!up) {
455 if (PIM_DEBUG_MROUTE)
a5fa9822 456 zlog_debug(
457 "%pSG: WRONGVIF%s unable to create upstream on interface",
458 &sg, ifp->name);
d62a17ae 459 return -2;
460 }
461 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
996c9314
LB
462 pim_upstream_keep_alive_timer_start(
463 up, pim_ifp->pim->keep_alive_time);
d62a17ae 464 up->channel_oil->cc.pktcnt++;
465 pim_register_join(up);
9b29ea95 466 pim_upstream_inherited_olist(pim_ifp->pim, up);
69e3538c
AK
467 if (!up->channel_oil->installed)
468 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 469
470 // Send the packet to the RP
471 pim_mroute_msg_wholepkt(fd, ifp, buf);
02434c43
DS
472 } else {
473 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
474 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
15569c58 475 __func__, NULL);
02434c43 476 if (!up->channel_oil->installed)
15569c58 477 pim_upstream_mroute_add(up->channel_oil, __func__);
d62a17ae 478 }
08e1fe76 479
d62a17ae 480 return 0;
08e1fe76
DS
481}
482
cc9f21da 483static void mroute_read(struct thread *t)
12e41d03 484{
8ea5d944 485 struct pim_instance *pim;
d62a17ae 486 static long long count;
487 char buf[10000];
d62a17ae 488 int cont = 1;
d62a17ae 489 int rd;
90450a3d 490 ifindex_t ifindex;
8ea5d944 491 pim = THREAD_ARG(t);
d62a17ae 492
493 while (cont) {
90450a3d
DS
494 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
495 sizeof(buf), NULL, NULL, NULL, NULL,
496 &ifindex);
61e99c94 497 if (rd <= 0) {
d62a17ae 498 if (errno == EINTR)
499 continue;
500 if (errno == EWOULDBLOCK || errno == EAGAIN)
501 break;
502
15569c58
DA
503 zlog_warn(
504 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
505 __func__, rd, pim->mroute_socket, errno,
506 safe_strerror(errno));
d62a17ae 507 goto done;
508 }
509
cc9f21da 510 pim_mroute_msg(pim, buf, rd, ifindex);
d62a17ae 511
512 count++;
75373cca 513 if (count % router->packet_process == 0)
d62a17ae 514 cont = 0;
515 }
516/* Keep reading */
517done:
8ea5d944 518 mroute_read_on(pim);
a5fa9822 519
520 return;
12e41d03
DL
521}
522
8ea5d944 523static void mroute_read_on(struct pim_instance *pim)
12e41d03 524{
36417fcc 525 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
8ea5d944 526 &pim->thread);
12e41d03
DL
527}
528
8ea5d944 529static void mroute_read_off(struct pim_instance *pim)
12e41d03 530{
8ea5d944 531 THREAD_OFF(pim->thread);
12e41d03
DL
532}
533
6beed987 534int pim_mroute_socket_enable(struct pim_instance *pim)
12e41d03 535{
d62a17ae 536 int fd;
12e41d03 537
0cf6db21 538 frr_with_privs(&pimd_privs) {
12e41d03 539
a5fa9822 540#if PIM_IPV == 4
01b9e3fd 541 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
a5fa9822 542#else
543 fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
544#endif
01b9e3fd
DL
545 if (fd < 0) {
546 zlog_warn("Could not create mroute socket: errno=%d: %s",
547 errno,
548 safe_strerror(errno));
549 return -2;
550 }
e691f179 551
466e4e5b 552#ifdef SO_BINDTODEVICE
01b9e3fd 553 if (pim->vrf->vrf_id != VRF_DEFAULT
633fc9b1
DL
554 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
555 pim->vrf->name, strlen(pim->vrf->name))) {
01b9e3fd
DL
556 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
557 safe_strerror(errno));
558 close(fd);
559 return -3;
560 }
466e4e5b 561#endif
90450a3d 562
01b9e3fd 563 }
12e41d03 564
cdbfaec5
DS
565 pim->mroute_socket = fd;
566 if (pim_mroute_set(pim, 1)) {
d62a17ae 567 zlog_warn(
568 "Could not enable mroute on socket fd=%d: errno=%d: %s",
569 fd, errno, safe_strerror(errno));
570 close(fd);
cdbfaec5 571 pim->mroute_socket = -1;
d62a17ae 572 return -3;
573 }
12e41d03 574
6beed987 575 pim->mroute_socket_creation = pim_time_monotonic_sec();
b45cefcb 576
8ea5d944 577 mroute_read_on(pim);
12e41d03 578
d62a17ae 579 return 0;
12e41d03
DL
580}
581
6beed987 582int pim_mroute_socket_disable(struct pim_instance *pim)
12e41d03 583{
cdbfaec5 584 if (pim_mroute_set(pim, 0)) {
d62a17ae 585 zlog_warn(
586 "Could not disable mroute on socket fd=%d: errno=%d: %s",
405d6357 587 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 588 return -2;
589 }
590
6beed987 591 if (close(pim->mroute_socket)) {
d62a17ae 592 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
405d6357 593 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 594 return -3;
595 }
596
8ea5d944 597 mroute_read_off(pim);
6beed987 598 pim->mroute_socket = -1;
d62a17ae 599
600 return 0;
12e41d03
DL
601}
602
603/*
604 For each network interface (e.g., physical or a virtual tunnel) that
605 would be used for multicast forwarding, a corresponding multicast
606 interface must be added to the kernel.
607 */
a9338fa4 608int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
d62a17ae 609 unsigned char flags)
12e41d03 610{
d62a17ae 611 struct pim_interface *pim_ifp = ifp->info;
a5fa9822 612 pim_vifctl vc;
d62a17ae 613 int err;
12e41d03 614
08f4f901 615 if (PIM_DEBUG_MROUTE)
15569c58 616 zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
996c9314
LB
617 pim_ifp->mroute_vif_index, ifp->name,
618 pim_ifp->pim->vrf->name);
08f4f901 619
d62a17ae 620 memset(&vc, 0, sizeof(vc));
a5fa9822 621 vc.vc_vifi = pim_ifp->mroute_vif_index;
622#if PIM_IPV == 4
b3f2bf7c 623#ifdef VIFF_USE_IFINDEX
a5fa9822 624 vc.vc_lcl_ifindex = ifp->ifindex;
b3f2bf7c 625#else
d62a17ae 626 if (ifaddr.s_addr == INADDR_ANY) {
627 zlog_warn(
628 "%s: unnumbered interfaces are not supported on this platform",
15569c58 629 __func__);
d62a17ae 630 return -1;
631 }
a5fa9822 632 memcpy(&vc.vc_lcl_addr, &ifaddr, sizeof(vc.vc_lcl_addr));
633#endif
634#else
635 vc.vc_pifi = ifp->ifindex;
b3f2bf7c 636#endif
a5fa9822 637 vc.vc_flags = flags;
638 vc.vc_threshold = PIM_MROUTE_MIN_TTL;
639 vc.vc_rate_limit = 0;
d62a17ae 640
a5fa9822 641#if PIM_IPV == 4
d62a17ae 642#ifdef PIM_DVMRP_TUNNEL
a5fa9822 643 if (vc.vc_flags & VIFF_TUNNEL) {
644 memcpy(&vc.vc_rmt_addr, &vif_remote_addr,
645 sizeof(vc.vc_rmt_addr));
d62a17ae 646 }
a5fa9822 647#endif
12e41d03
DL
648#endif
649
a5fa9822 650 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
d62a17ae 651 (void *)&vc, sizeof(vc));
652 if (err) {
d62a17ae 653 zlog_warn(
a5fa9822 654 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
15569c58 655 __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
a9338fa4 656 &ifaddr, flags, errno, safe_strerror(errno));
d62a17ae 657 return -2;
658 }
12e41d03 659
d62a17ae 660 return 0;
12e41d03
DL
661}
662
ea3d967b 663int pim_mroute_del_vif(struct interface *ifp)
12e41d03 664{
ea3d967b 665 struct pim_interface *pim_ifp = ifp->info;
a5fa9822 666 pim_vifctl vc;
d62a17ae 667 int err;
668
ea3d967b 669 if (PIM_DEBUG_MROUTE)
15569c58 670 zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
996c9314
LB
671 pim_ifp->mroute_vif_index, ifp->name,
672 pim_ifp->pim->vrf->name);
12e41d03 673
d62a17ae 674 memset(&vc, 0, sizeof(vc));
a5fa9822 675 vc.vc_vifi = pim_ifp->mroute_vif_index;
d62a17ae 676
a5fa9822 677 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_DEL_VIF,
d62a17ae 678 (void *)&vc, sizeof(vc));
679 if (err) {
680 zlog_warn(
a5fa9822 681 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
15569c58
DA
682 __FILE__, __func__, pim_ifp->pim->mroute_socket,
683 pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
d62a17ae 684 return -2;
685 }
12e41d03 686
d62a17ae 687 return 0;
12e41d03
DL
688}
689
60eb7e6b
AK
690/*
691 * Prevent creating MFC entry with OIF=IIF.
692 *
693 * This is a protection against implementation mistakes.
694 *
695 * PIM protocol implicitely ensures loopfree multicast topology.
696 *
697 * IGMP must be protected against adding looped MFC entries created
698 * by both source and receiver attached to the same interface. See
699 * TODO T22.
700 * We shall allow igmp to create upstream when it is DR for the intf.
701 * Assume RP reachable via non DR.
702 */
703bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
704 int oif_index)
705{
706#ifdef PIM_ENFORCE_LOOPFREE_MFC
707 struct interface *ifp_out;
708 struct pim_interface *pim_ifp;
709
710 if (c_oil->up &&
711 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
712 return true;
713
714 ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
715 if (!ifp_out)
716 return false;
717 pim_ifp = ifp_out->info;
718 if (!pim_ifp)
719 return false;
720 if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_IGMP) &&
721 PIM_I_am_DR(pim_ifp))
722 return true;
723
724 return false;
725#else
726 return true;
727#endif
728}
729
a9338fa4
DL
730static inline void pim_mroute_copy(struct channel_oil *out,
731 struct channel_oil *in)
5a5f404e
AK
732{
733 int i;
734
a9338fa4
DL
735 *oil_origin(out) = *oil_origin(in);
736 *oil_mcastgrp(out) = *oil_mcastgrp(in);
737 *oil_parent(out) = *oil_parent(in);
5a5f404e
AK
738
739 for (i = 0; i < MAXVIFS; ++i) {
a9338fa4
DL
740 if (*oil_parent(out) == i &&
741 !pim_mroute_allow_iif_in_oil(in, i)) {
742 oil_if_set(out, i, 0);
60eb7e6b
AK
743 continue;
744 }
745
a9338fa4
DL
746 if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
747 oil_if_set(out, i, 0);
5a5f404e 748 else
a9338fa4 749 oil_if_set(out, i, oil_if_has(in, i));
5a5f404e
AK
750 }
751}
752
69e3538c
AK
753/* This function must not be called directly 0
754 * use pim_upstream_mroute_add or pim_static_mroute_add instead
755 */
756static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
12e41d03 757{
9a0f71c9 758 struct pim_instance *pim = c_oil->pim;
a9338fa4 759 struct channel_oil tmp_oil[1] = { };
d62a17ae 760 int err;
d62a17ae 761
856e863f
DS
762 pim->mroute_add_last = pim_time_monotonic_sec();
763 ++pim->mroute_add_events;
d62a17ae 764
5a5f404e
AK
765 /* Copy the oil to a temporary structure to fixup (without need to
766 * later restore) before sending the mroute add to the dataplane
767 */
a9338fa4 768 pim_mroute_copy(tmp_oil, c_oil);
d3aded99 769
d62a17ae 770 /* The linux kernel *expects* the incoming
771 * vif to be part of the outgoing list
772 * in the case of a (*,G).
773 */
a9338fa4
DL
774 if (pim_addr_is_any(*oil_origin(c_oil))) {
775 oil_if_set(tmp_oil, *oil_parent(c_oil), 1);
76e4825a
AK
776 }
777
d62a17ae 778 /*
779 * If we have an unresolved cache entry for the S,G
780 * it is owned by the pimreg for the incoming IIF
781 * So set pimreg as the IIF temporarily to cause
782 * the packets to be forwarded. Then set it
783 * to the correct IIF afterwords.
784 */
a9338fa4
DL
785 if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil))
786 && *oil_parent(c_oil) != 0) {
787 *oil_parent(tmp_oil) = 0;
d62a17ae 788 }
a5fa9822 789 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
790 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
a9338fa4 791 &tmp_oil->oil, sizeof(tmp_oil->oil));
d62a17ae 792
793 if (!err && !c_oil->installed
a9338fa4
DL
794 && !pim_addr_is_any(*oil_origin(c_oil))
795 && *oil_parent(c_oil) != 0) {
796 *oil_parent(tmp_oil) = *oil_parent(c_oil);
a5fa9822 797 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
a9338fa4 798 &tmp_oil->oil, sizeof(tmp_oil->oil));
42e01756 799 }
37c3fd98 800
d62a17ae 801 if (err) {
802 zlog_warn(
a5fa9822 803 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
15569c58
DA
804 __FILE__, __func__, pim->mroute_socket, errno,
805 safe_strerror(errno));
d62a17ae 806 return -2;
807 }
12e41d03 808
d62a17ae 809 if (PIM_DEBUG_MROUTE) {
810 char buf[1000];
15569c58
DA
811 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
812 pim->vrf->name,
d62a17ae 813 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
814 }
6a78764e 815
fe75a058
SP
816 if (!c_oil->installed) {
817 c_oil->installed = 1;
818 c_oil->mroute_creation = pim_time_monotonic_sec();
819 }
e7cd85bd 820
d62a17ae 821 return 0;
12e41d03
DL
822}
823
7984af18
AK
824static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
825 const char *name)
69e3538c
AK
826{
827 vifi_t iif = MAXVIFS;
69e3538c
AK
828 struct interface *ifp = NULL;
829 struct pim_interface *pim_ifp;
830 struct pim_upstream *up = c_oil->up;
831
832 if (up) {
833 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
834 if (up->parent)
835 ifp = up->parent->rpf.source_nexthop.interface;
836 } else {
837 ifp = up->rpf.source_nexthop.interface;
838 }
839 if (ifp) {
840 pim_ifp = (struct pim_interface *)ifp->info;
841 if (pim_ifp)
842 iif = pim_ifp->mroute_vif_index;
843 }
844 }
7984af18
AK
845 return iif;
846}
69e3538c 847
7984af18
AK
848static int pim_upstream_mroute_update(struct channel_oil *c_oil,
849 const char *name)
850{
851 char buf[1000];
69e3538c 852
a9338fa4 853 if (*oil_parent(c_oil) >= MAXVIFS) {
69e3538c
AK
854 /* the c_oil cannot be installed as a mroute yet */
855 if (PIM_DEBUG_MROUTE)
856 zlog_debug(
857 "%s(%s) %s mroute not ready to be installed; %s",
7984af18 858 __func__, name,
69e3538c
AK
859 pim_channel_oil_dump(c_oil, buf,
860 sizeof(buf)),
861 c_oil->installed ?
862 "uninstall" : "skip");
863 /* if already installed flush it out as we are going to stop
864 * updates to it leaving it in a stale state
865 */
866 if (c_oil->installed)
867 pim_mroute_del(c_oil, name);
868 /* return success (skipped) */
869 return 0;
870 }
871
872 return pim_mroute_add(c_oil, name);
873}
874
70c86421
AK
875/* IIF associated with SGrpt entries are re-evaluated when the parent
876 * (*,G) entries IIF changes
877 */
878static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
879{
880 struct listnode *listnode;
881 struct pim_upstream *child;
882
883 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
884 child)) {
885 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
886 pim_upstream_mroute_iif_update(child->channel_oil,
887 __func__);
888 }
889}
890
7984af18
AK
891/* In the case of "PIM state machine" added mroutes an upstream entry
892 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
893 */
894int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
895{
70c86421
AK
896 vifi_t iif;
897
898 iif = pim_upstream_get_mroute_iif(c_oil, name);
899
a9338fa4
DL
900 if (*oil_parent(c_oil) != iif) {
901 *oil_parent(c_oil) = iif;
902 if (pim_addr_is_any(*oil_origin(c_oil)) &&
70c86421
AK
903 c_oil->up)
904 pim_upstream_all_sources_iif_update(c_oil->up);
905 } else {
a9338fa4 906 *oil_parent(c_oil) = iif;
70c86421 907 }
7984af18
AK
908
909 return pim_upstream_mroute_update(c_oil, name);
910}
911
912/* Look for IIF changes and update the dateplane entry only if the IIF
913 * has changed.
914 */
915int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
916{
917 vifi_t iif;
918 char buf[1000];
919
920 iif = pim_upstream_get_mroute_iif(c_oil, name);
a9338fa4 921 if (*oil_parent(c_oil) == iif) {
7984af18
AK
922 /* no change */
923 return 0;
924 }
a9338fa4 925 *oil_parent(c_oil) = iif;
7984af18 926
a9338fa4 927 if (pim_addr_is_any(*oil_origin(c_oil)) &&
70c86421
AK
928 c_oil->up)
929 pim_upstream_all_sources_iif_update(c_oil->up);
930
7984af18
AK
931 if (PIM_DEBUG_MROUTE_DETAIL)
932 zlog_debug("%s(%s) %s mroute iif update %d",
933 __func__, name,
934 pim_channel_oil_dump(c_oil, buf,
935 sizeof(buf)), iif);
936 /* XXX: is this hack needed? */
937 c_oil->oil_inherited_rescan = 1;
938 return pim_upstream_mroute_update(c_oil, name);
939}
940
69e3538c
AK
941int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
942{
943 return pim_mroute_add(c_oil, name);
944}
945
7984af18
AK
946void pim_static_mroute_iif_update(struct channel_oil *c_oil,
947 int input_vif_index,
948 const char *name)
949{
a9338fa4 950 if (*oil_parent(c_oil) == input_vif_index)
7984af18
AK
951 return;
952
a9338fa4 953 *oil_parent(c_oil) = input_vif_index;
7984af18
AK
954 if (input_vif_index == MAXVIFS)
955 pim_mroute_del(c_oil, name);
956 else
957 pim_static_mroute_add(c_oil, name);
958}
959
d62a17ae 960int pim_mroute_del(struct channel_oil *c_oil, const char *name)
12e41d03 961{
9a0f71c9 962 struct pim_instance *pim = c_oil->pim;
d62a17ae 963 int err;
964
856e863f
DS
965 pim->mroute_del_last = pim_time_monotonic_sec();
966 ++pim->mroute_del_events;
d62a17ae 967
968 if (!c_oil->installed) {
969 if (PIM_DEBUG_MROUTE) {
970 char buf[1000];
971 zlog_debug(
972 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
a9338fa4 973 __FILE__, __func__, *oil_parent(c_oil),
d62a17ae 974 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
975 }
976 return -2;
977 }
12e41d03 978
a5fa9822 979 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_DEL_MFC,
d62a17ae 980 &c_oil->oil, sizeof(c_oil->oil));
981 if (err) {
982 if (PIM_DEBUG_MROUTE)
983 zlog_warn(
a5fa9822 984 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
15569c58 985 __FILE__, __func__, pim->mroute_socket, errno,
d62a17ae 986 safe_strerror(errno));
987 return -2;
988 }
429a291b 989
d62a17ae 990 if (PIM_DEBUG_MROUTE) {
991 char buf[1000];
15569c58
DA
992 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
993 pim->vrf->name,
d62fd596 994 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
d62a17ae 995 }
781a1745 996
d62a17ae 997 // Reset kernel installed flag
998 c_oil->installed = 0;
58302dc7 999
d62a17ae 1000 return 0;
12e41d03 1001}
3667e8a0 1002
d62a17ae 1003void pim_mroute_update_counters(struct channel_oil *c_oil)
3667e8a0 1004{
9a0f71c9 1005 struct pim_instance *pim = c_oil->pim;
a5fa9822 1006 pim_sioc_sg_req sgreq;
d62a17ae 1007
1008 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1009 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1010 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1011
1012 if (!c_oil->installed) {
19b807ca 1013 c_oil->cc.lastused = 100 * pim->keep_alive_time;
d62a17ae 1014 if (PIM_DEBUG_MROUTE) {
6fff2cc6 1015 pim_sgaddr sg;
d62a17ae 1016
a9338fa4
DL
1017 sg.src = *oil_origin(c_oil);
1018 sg.grp = *oil_mcastgrp(c_oil);
98a81d2b
DL
1019 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1020 &sg);
d62a17ae 1021 }
1022 return;
c7b1183f 1023 }
c7b1183f 1024
a9338fa4 1025
d62a17ae 1026 memset(&sgreq, 0, sizeof(sgreq));
a5fa9822 1027
1028#if PIM_IPV == 4
a9338fa4
DL
1029 sgreq.src = *oil_origin(c_oil);
1030 sgreq.grp = *oil_mcastgrp(c_oil);
d62a17ae 1031 pim_zlookup_sg_statistics(c_oil);
a5fa9822 1032#else
1033 sgreq.src = c_oil->oil.mf6cc_origin;
1034 sgreq.grp = c_oil->oil.mf6cc_mcastgrp;
1035 /* TODO Zlookup_sg_statistics for V6 to be added */
1036#endif
1037 if (ioctl(pim->mroute_socket, PIM_SIOCGETSGCNT, &sgreq)) {
6fff2cc6 1038 pim_sgaddr sg;
d62a17ae 1039
a9338fa4
DL
1040 sg.src = *oil_origin(c_oil);
1041 sg.grp = *oil_mcastgrp(c_oil);
d62a17ae 1042
a5fa9822 1043 zlog_warn(
1044 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1045 (unsigned long)PIM_SIOCGETSGCNT, &sg, errno,
1046 safe_strerror(errno));
d62a17ae 1047 return;
c7b1183f 1048 }
3667e8a0 1049
d62a17ae 1050 c_oil->cc.pktcnt = sgreq.pktcnt;
1051 c_oil->cc.bytecnt = sgreq.bytecnt;
1052 c_oil->cc.wrong_if = sgreq.wrong_if;
d62a17ae 1053 return;
3667e8a0 1054}