]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
pimd: allow mroutes with IIF in the OIL
[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"
12e41d03 45
8ea5d944 46static void mroute_read_on(struct pim_instance *pim);
12e41d03 47
cdbfaec5 48static int pim_mroute_set(struct pim_instance *pim, int enable)
12e41d03 49{
d62a17ae 50 int err;
e5a2ebe6
DS
51 int opt, data;
52 socklen_t data_len = sizeof(data);
d62a17ae 53 long flags;
54
cdbfaec5
DS
55 /*
56 * We need to create the VRF table for the pim mroute_socket
57 */
58 if (pim->vrf_id != VRF_DEFAULT) {
01b9e3fd 59 frr_elevate_privs(&pimd_privs) {
f507c196 60
e5a2ebe6 61 data = pim->vrf->data.l.table_id;
01b9e3fd
DL
62 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
63 MRT_TABLE,
e5a2ebe6 64 &data, data_len);
01b9e3fd
DL
65 if (err) {
66 zlog_warn(
67 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
68 __FILE__, __PRETTY_FUNCTION__,
e5a2ebe6 69 pim->mroute_socket, data, errno,
01b9e3fd
DL
70 safe_strerror(errno));
71 return -1;
72 }
f507c196 73
01b9e3fd 74 }
f507c196
DS
75 }
76
f0b009a4
DS
77 frr_elevate_privs(&pimd_privs) {
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(
88 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
89 __FILE__, __PRETTY_FUNCTION__,
90 pim->mroute_socket,
e5a2ebe6 91 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
f0b009a4
DS
92 safe_strerror(errno));
93 return -1;
94 }
cdbfaec5
DS
95 }
96
466e4e5b
DS
97#if defined(HAVE_IP_PKTINFO)
98 if (enable) {
99 /* Linux and Solaris IP_PKTINFO */
e5a2ebe6
DS
100 data = 1;
101 if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
102 &data, data_len)) {
466e4e5b
DS
103 zlog_warn(
104 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
105 pim->mroute_socket, errno,
106 safe_strerror(errno));
107 }
108 }
109#endif
110
cdbfaec5 111 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
d62a17ae 112
cdbfaec5 113 flags = fcntl(pim->mroute_socket, F_GETFL, 0);
d62a17ae 114 if (flags < 0) {
cdbfaec5
DS
115 zlog_warn("Could not get flags on socket fd:%d %d %s",
116 pim->mroute_socket, errno, safe_strerror(errno));
117 close(pim->mroute_socket);
d62a17ae 118 return -1;
119 }
cdbfaec5
DS
120 if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
121 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
122 pim->mroute_socket, errno, safe_strerror(errno));
123 close(pim->mroute_socket);
d62a17ae 124 return -1;
125 }
126
127 if (enable) {
77b7d90b 128#if defined linux
d62a17ae 129 int upcalls = IGMPMSG_WRVIFWHOLE;
130 opt = MRT_PIM;
131
cdbfaec5 132 err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
d62a17ae 133 sizeof(upcalls));
134 if (err) {
135 zlog_warn(
136 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
137 errno, safe_strerror(errno));
138 return -1;
139 }
77b7d90b 140#else
d62a17ae 141 zlog_warn(
142 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
77b7d90b 143#endif
d62a17ae 144 }
145
146 return 0;
12e41d03
DL
147}
148
08e1fe76 149static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
d62a17ae 150 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
151
152static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
153 const struct igmpmsg *msg)
12e41d03 154{
d62a17ae 155 struct pim_interface *pim_ifp = ifp->info;
156 struct pim_upstream *up;
157 struct pim_rpf *rpg;
158 struct prefix_sg sg;
159
b575a12c 160 rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
d62a17ae 161 /*
162 * If the incoming interface is unknown OR
163 * the Interface type is SSM we don't need to
164 * do anything here
165 */
b5469d02 166 if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) {
d62a17ae 167 if (PIM_DEBUG_MROUTE_DETAIL)
168 zlog_debug(
b5469d02 169 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
d62a17ae 170 __PRETTY_FUNCTION__);
b5469d02 171
d62a17ae 172 return 0;
173 }
04b40f02 174
d62a17ae 175 /*
176 * If we've received a multicast packet that isn't connected to
177 * us
178 */
179 if (!pim_if_connected_to_source(ifp, msg->im_src)) {
180 if (PIM_DEBUG_MROUTE_DETAIL)
181 zlog_debug(
182 "%s: Received incoming packet that doesn't originate on our seg",
183 __PRETTY_FUNCTION__);
184 return 0;
185 }
065bee4b 186
d62a17ae 187 memset(&sg, 0, sizeof(struct prefix_sg));
188 sg.src = msg->im_src;
189 sg.grp = msg->im_dst;
190
b5469d02
DS
191 if (!(PIM_I_am_DR(pim_ifp))) {
192 struct channel_oil *c_oil;
193
194 if (PIM_DEBUG_MROUTE_DETAIL)
195 zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %s",
196 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
197
198 /*
199 * We are not the DR, but we are still receiving packets
200 * Let's blackhole those packets for the moment
201 * As that they will be coming up to the cpu
202 * and causing us to consider them.
203 */
204 c_oil = pim_channel_oil_add(pim_ifp->pim, &sg,
205 pim_ifp->mroute_vif_index);
206 pim_mroute_add(c_oil, __PRETTY_FUNCTION__);
207
208 return 0;
209 }
210
d62a17ae 211 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
212 __PRETTY_FUNCTION__);
213 if (!up) {
214 if (PIM_DEBUG_MROUTE) {
215 zlog_debug(
216 "%s: Failure to add upstream information for %s",
217 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
218 }
219 return 0;
220 }
c29a5806 221
d62a17ae 222 /*
223 * I moved this debug till after the actual add because
224 * I want to take advantage of the up->sg_str being filled in.
225 */
226 if (PIM_DEBUG_MROUTE) {
227 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
228 __PRETTY_FUNCTION__, up->sg_str);
229 }
8bfb8b67 230
d62a17ae 231 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
19b807ca 232 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
d62a17ae 233
234 up->channel_oil->cc.pktcnt++;
235 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
236 // resolve mfcc_parent prior to mroute_add in channel_add_oif
957d93ea
SP
237 if (up->rpf.source_nexthop.interface &&
238 up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
d62a17ae 239 int vif_index = 0;
240 vif_index = pim_if_find_vifindex_by_ifindex(
7cfc7bcf 241 pim_ifp->pim,
d62a17ae 242 up->rpf.source_nexthop.interface->ifindex);
243 up->channel_oil->oil.mfcc_parent = vif_index;
244 }
245 pim_register_join(up);
59471fb8 246
d62a17ae 247 return 0;
e355e30f 248}
12e41d03 249
d62a17ae 250static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
251 const char *buf)
e355e30f 252{
d62a17ae 253 struct pim_interface *pim_ifp;
254 struct prefix_sg sg;
255 struct pim_rpf *rpg;
256 const struct ip *ip_hdr;
257 struct pim_upstream *up;
258
9b29ea95
DS
259 pim_ifp = ifp->info;
260
d62a17ae 261 ip_hdr = (const struct ip *)buf;
262
263 memset(&sg, 0, sizeof(struct prefix_sg));
264 sg.src = ip_hdr->ip_src;
265 sg.grp = ip_hdr->ip_dst;
266
9b29ea95 267 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 268 if (!up) {
269 struct prefix_sg star = sg;
270 star.src.s_addr = INADDR_ANY;
271
9b29ea95 272 up = pim_upstream_find(pim_ifp->pim, &star);
d62a17ae 273
274 if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) {
2002dcdb 275 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
d62a17ae 276 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
0885a9f1 277 __PRETTY_FUNCTION__, NULL);
d62a17ae 278 if (!up) {
279 if (PIM_DEBUG_MROUTE)
280 zlog_debug(
281 "%s: Unable to create upstream information for %s",
282 __PRETTY_FUNCTION__,
283 pim_str_sg_dump(&sg));
284 return 0;
285 }
286 pim_upstream_keep_alive_timer_start(
19b807ca 287 up, pim_ifp->pim->keep_alive_time);
9b29ea95 288 pim_upstream_inherited_olist(pim_ifp->pim, up);
1eca8576
DS
289 pim_upstream_switch(pim_ifp->pim, up,
290 PIM_UPSTREAM_JOINED);
d62a17ae 291
292 if (PIM_DEBUG_MROUTE)
293 zlog_debug("%s: Creating %s upstream on LHR",
294 __PRETTY_FUNCTION__, up->sg_str);
295 return 0;
296 }
297 if (PIM_DEBUG_MROUTE_DETAIL) {
298 zlog_debug(
299 "%s: Unable to find upstream channel WHOLEPKT%s",
300 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
301 }
302 return 0;
303 }
59471fb8 304
957d93ea
SP
305 if (!up->rpf.source_nexthop.interface) {
306 if (PIM_DEBUG_TRACE)
307 zlog_debug("%s: up %s RPF is not present",
308 __PRETTY_FUNCTION__, up->sg_str);
309 return 0;
310 }
311
d62a17ae 312 pim_ifp = up->rpf.source_nexthop.interface->info;
998af219 313
b575a12c 314 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
c8ae3ce8 315
d62a17ae 316 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
317 || (!(PIM_I_am_DR(pim_ifp)))) {
318 if (PIM_DEBUG_MROUTE) {
319 zlog_debug("%s: Failed Check send packet",
320 __PRETTY_FUNCTION__);
321 }
322 return 0;
323 }
84366c7e 324
d62a17ae 325 /*
326 * If we've received a register suppress
327 */
328 if (!up->t_rs_timer) {
6f439a70 329 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
d62a17ae 330 if (PIM_DEBUG_PIM_REG)
331 zlog_debug(
332 "%s register forward skipped as group is SSM",
333 pim_str_sg_dump(&sg));
334 return 0;
335 }
336 pim_register_send((uint8_t *)buf + sizeof(struct ip),
337 ntohs(ip_hdr->ip_len) - sizeof(struct ip),
338 pim_ifp->primary_address, rpg, 0, up);
339 }
340 return 0;
e355e30f 341}
12e41d03 342
d62a17ae 343static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
344 const struct igmpmsg *msg)
e355e30f 345{
d62a17ae 346 struct pim_ifchannel *ch;
347 struct pim_interface *pim_ifp;
348 struct prefix_sg sg;
349
350 memset(&sg, 0, sizeof(struct prefix_sg));
351 sg.src = msg->im_src;
352 sg.grp = msg->im_dst;
353
354 /*
355 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
356
357 RFC 4601 4.8.2. PIM-SSM-Only Routers
358
359 iif is the incoming interface of the packet.
360 if (iif is in inherited_olist(S,G)) {
361 send Assert(S,G) on iif
362 }
363 */
364
365 if (!ifp) {
366 if (PIM_DEBUG_MROUTE)
367 zlog_debug(
368 "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
369 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
370 msg->im_vif);
371 return -1;
372 }
12e41d03 373
d62a17ae 374 pim_ifp = ifp->info;
375 if (!pim_ifp) {
376 if (PIM_DEBUG_MROUTE)
377 zlog_debug(
378 "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
379 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
380 ifp->name);
381 return -2;
382 }
c29a5806 383
d62a17ae 384 ch = pim_ifchannel_find(ifp, &sg);
385 if (!ch) {
386 struct prefix_sg star_g = sg;
387 if (PIM_DEBUG_MROUTE)
388 zlog_debug(
389 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
390 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
391 ifp->name);
392
393 star_g.src.s_addr = INADDR_ANY;
394 ch = pim_ifchannel_find(ifp, &star_g);
395 if (!ch) {
396 if (PIM_DEBUG_MROUTE)
397 zlog_debug(
398 "%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
399 __PRETTY_FUNCTION__,
400 pim_str_sg_dump(&star_g), ifp->name);
401 return -3;
402 }
403 }
12e41d03 404
d62a17ae 405 /*
406 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
407
408 Transitions from NoInfo State
409
410 An (S,G) data packet arrives on interface I, AND
411 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
412 downstream interface that is in our (S,G) outgoing interface
413 list. We optimistically assume that we will be the assert
414 winner for this (S,G), and so we transition to the "I am Assert
415 Winner" state and perform Actions A1 (below), which will
416 initiate the assert negotiation for (S,G).
417 */
418
419 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
420 if (PIM_DEBUG_MROUTE) {
421 zlog_debug(
422 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
423 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
424 }
425 return -4;
426 }
e355e30f 427
d62a17ae 428 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
429 if (PIM_DEBUG_MROUTE) {
430 zlog_debug(
431 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
432 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
433 }
434 return -5;
435 }
436
437 if (assert_action_a1(ch)) {
438 if (PIM_DEBUG_MROUTE) {
439 zlog_debug(
440 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
441 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
442 }
443 return -6;
444 }
e355e30f 445
d62a17ae 446 return 0;
e355e30f
DS
447}
448
d62a17ae 449static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
450 const char *buf)
08e1fe76 451{
d62a17ae 452 const struct ip *ip_hdr = (const struct ip *)buf;
453 struct pim_interface *pim_ifp;
454 struct pim_ifchannel *ch;
455 struct pim_upstream *up;
456 struct prefix_sg star_g;
457 struct prefix_sg sg;
458 struct channel_oil *oil;
459
fec883d9
DS
460 pim_ifp = ifp->info;
461
d62a17ae 462 memset(&sg, 0, sizeof(struct prefix_sg));
463 sg.src = ip_hdr->ip_src;
464 sg.grp = ip_hdr->ip_dst;
465
466 ch = pim_ifchannel_find(ifp, &sg);
467 if (ch) {
468 if (PIM_DEBUG_MROUTE)
469 zlog_debug(
470 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
471 ch->sg_str, ifp->name);
472 return -1;
473 }
b7ddd2ec 474
d62a17ae 475 star_g = sg;
476 star_g.src.s_addr = INADDR_ANY;
b7ddd2ec 477#if 0
0490c22d
DS
478 ch = pim_ifchannel_find(ifp, &star_g);
479 if (ch)
480 {
481 if (PIM_DEBUG_MROUTE)
482 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
483 pim_str_sg_dump (&star_g), ifp->name);
484 return -1;
485 }
5cd11e3c 486#endif
08e1fe76 487
9b29ea95 488 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 489 if (up) {
490 struct pim_upstream *parent;
491 struct pim_nexthop source;
fec883d9 492 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
d62a17ae 493 if (!rpf || !rpf->source_nexthop.interface)
494 return 0;
495
496 /*
497 * If we have received a WRVIFWHOLE and are at this
498 * point, we could be receiving the packet on the *,G
499 * tree, let's check and if so we can safely drop
500 * it.
501 */
9b29ea95 502 parent = pim_upstream_find(pim_ifp->pim, &star_g);
d62a17ae 503 if (parent && parent->rpf.source_nexthop.interface == ifp)
504 return 0;
505
506 pim_ifp = rpf->source_nexthop.interface->info;
507
508 memset(&source, 0, sizeof(source));
509 /*
510 * If we are the fhr that means we are getting a callback during
511 * the pimreg period, so I believe we can ignore this packet
512 */
513 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
514 // No if channel, but upstream we are at the RP.
d9c9a9ee 515 if (pim_nexthop_lookup(pim_ifp->pim, &source,
ade155e1 516 up->upstream_register, 0)) {
d62a17ae 517 pim_register_stop_send(source.interface, &sg,
518 pim_ifp->primary_address,
519 up->upstream_register);
df766618
DS
520 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
521 }
d62a17ae 522 if (!up->channel_oil)
523 up->channel_oil = pim_channel_oil_add(
611925dc
DS
524 pim_ifp->pim, &sg,
525 pim_ifp->mroute_vif_index);
9b29ea95 526 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 527 if (!up->channel_oil->installed)
528 pim_mroute_add(up->channel_oil,
529 __PRETTY_FUNCTION__);
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;
611925dc 550 oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index);
d62a17ae 551 if (!oil->installed)
552 pim_mroute_add(oil, __PRETTY_FUNCTION__);
553 if (pim_if_connected_to_source(ifp, sg.src)) {
2002dcdb
DS
554 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
555 PIM_UPSTREAM_FLAG_MASK_FHR,
0885a9f1 556 __PRETTY_FUNCTION__, NULL);
d62a17ae 557 if (!up) {
558 if (PIM_DEBUG_MROUTE)
559 zlog_debug(
560 "%s: WRONGVIF%s unable to create upstream on interface",
561 pim_str_sg_dump(&sg), ifp->name);
562 return -2;
563 }
564 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
996c9314
LB
565 pim_upstream_keep_alive_timer_start(
566 up, pim_ifp->pim->keep_alive_time);
d62a17ae 567 up->channel_oil = oil;
568 up->channel_oil->cc.pktcnt++;
569 pim_register_join(up);
9b29ea95 570 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 571
572 // Send the packet to the RP
573 pim_mroute_msg_wholepkt(fd, ifp, buf);
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
593 ip_hdr = (const struct ip *)buf;
594
595 if (ip_hdr->ip_p == IPPROTO_IGMP) {
596
597 /* We have the IP packet but we do not know which interface this
598 * packet was
599 * received on. Find the interface that is on the same subnet as
600 * the source
601 * of the IP packet.
602 */
90450a3d 603 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
d62a17ae 604
1ef8c24e 605 if (!ifp || !ifp->info)
d62a17ae 606 return 0;
90450a3d 607
d62a17ae 608 pim_ifp = ifp->info;
609 ifaddr = pim_find_primary_addr(ifp);
610 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
611 ifaddr);
612
613 if (PIM_DEBUG_MROUTE) {
614 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
615 sizeof(ip_src_str));
616 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
617 sizeof(ip_dst_str));
618
619 zlog_warn(
7c2bfc2a
DS
620 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
621 __PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
622 igmp, ip_src_str, ip_dst_str);
d62a17ae 623 }
624 if (igmp)
625 pim_igmp_packet(igmp, (char *)buf, buf_size);
626
627 } else if (ip_hdr->ip_p) {
628 if (PIM_DEBUG_MROUTE_DETAIL) {
629 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
630 sizeof(src_str));
631 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
632 sizeof(grp_str));
633 zlog_debug(
634 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
635 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str,
636 grp_str, buf_size);
637 }
638
639 } else {
640 msg = (const struct igmpmsg *)buf;
641
7cfc7bcf 642 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
d62a17ae 643
644 if (!ifp)
645 return 0;
646 if (PIM_DEBUG_MROUTE) {
647 pim_inet4_dump("<src?>", msg->im_src, src_str,
648 sizeof(src_str));
649 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
650 sizeof(grp_str));
651 zlog_warn(
652 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
653 __PRETTY_FUNCTION__,
654 igmpmsgtype2str[msg->im_msgtype],
405d6357
DS
655 msg->im_msgtype, ip_hdr->ip_p,
656 pim->mroute_socket, src_str, grp_str, ifp->name,
657 msg->im_vif, buf_size);
d62a17ae 658 }
659
660 switch (msg->im_msgtype) {
661 case IGMPMSG_WRONGVIF:
405d6357
DS
662 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
663 msg);
d62a17ae 664 break;
665 case IGMPMSG_NOCACHE:
405d6357
DS
666 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
667 msg);
d62a17ae 668 break;
669 case IGMPMSG_WHOLEPKT:
405d6357 670 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
d62a17ae 671 (const char *)msg);
672 break;
673 case IGMPMSG_WRVIFWHOLE:
405d6357
DS
674 return pim_mroute_msg_wrvifwhole(
675 pim->mroute_socket, ifp, (const char *)msg);
d62a17ae 676 break;
677 default:
678 break;
679 }
680 }
12e41d03 681
d62a17ae 682 return 0;
12e41d03
DL
683}
684
12e41d03
DL
685static int mroute_read(struct thread *t)
686{
8ea5d944 687 struct pim_instance *pim;
d62a17ae 688 static long long count;
689 char buf[10000];
690 int result = 0;
691 int cont = 1;
d62a17ae 692 int rd;
90450a3d 693 ifindex_t ifindex;
8ea5d944 694 pim = THREAD_ARG(t);
d62a17ae 695
696 while (cont) {
90450a3d
DS
697 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
698 sizeof(buf), NULL, NULL, NULL, NULL,
699 &ifindex);
61e99c94 700 if (rd <= 0) {
d62a17ae 701 if (errno == EINTR)
702 continue;
703 if (errno == EWOULDBLOCK || errno == EAGAIN)
704 break;
705
706 if (PIM_DEBUG_MROUTE)
707 zlog_warn(
61e99c94 708 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
8ea5d944
DS
709 __PRETTY_FUNCTION__, rd,
710 pim->mroute_socket, errno,
d62a17ae 711 safe_strerror(errno));
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
01b9e3fd 743 frr_elevate_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
6a78764e 893int pim_mroute_add(struct channel_oil *c_oil, const char *name)
12e41d03 894{
9a0f71c9 895 struct pim_instance *pim = c_oil->pim;
d62a17ae 896 int err;
897 int orig = 0;
898 int orig_iif_vif = 0;
899
856e863f
DS
900 pim->mroute_add_last = pim_time_monotonic_sec();
901 ++pim->mroute_add_events;
d62a17ae 902
903 /* Do not install route if incoming interface is undefined. */
904 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
905 if (PIM_DEBUG_MROUTE) {
906 char buf[1000];
907 zlog_debug(
908 "%s(%s) %s Attempting to add vifi that is invalid to mroute table",
909 __PRETTY_FUNCTION__, name,
910 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
911 }
912 return -2;
913 }
d3aded99 914
d62a17ae 915 /* The linux kernel *expects* the incoming
916 * vif to be part of the outgoing list
917 * in the case of a (*,G).
918 */
919 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
920 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
921 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
922 }
d3aded99 923
d62a17ae 924 /*
925 * If we have an unresolved cache entry for the S,G
926 * it is owned by the pimreg for the incoming IIF
927 * So set pimreg as the IIF temporarily to cause
928 * the packets to be forwarded. Then set it
929 * to the correct IIF afterwords.
930 */
931 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
932 && c_oil->oil.mfcc_parent != 0) {
933 orig_iif_vif = c_oil->oil.mfcc_parent;
934 c_oil->oil.mfcc_parent = 0;
935 }
856e863f 936 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
d62a17ae 937 &c_oil->oil, sizeof(c_oil->oil));
938
939 if (!err && !c_oil->installed
940 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
941 && orig_iif_vif != 0) {
942 c_oil->oil.mfcc_parent = orig_iif_vif;
856e863f 943 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
d62a17ae 944 &c_oil->oil, sizeof(c_oil->oil));
945 }
0365f56b 946
d62a17ae 947 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
948 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
d3aded99 949
d62a17ae 950 if (err) {
951 zlog_warn(
952 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
856e863f 953 __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
d62a17ae 954 errno, safe_strerror(errno));
955 return -2;
956 }
12e41d03 957
d62a17ae 958 if (PIM_DEBUG_MROUTE) {
959 char buf[1000];
996c9314
LB
960 zlog_debug("%s(%s), vrf %s Added Route: %s",
961 __PRETTY_FUNCTION__, name, pim->vrf->name,
d62a17ae 962 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
963 }
6a78764e 964
d62a17ae 965 c_oil->installed = 1;
e7cd85bd
SP
966 c_oil->mroute_creation = pim_time_monotonic_sec();
967
d62a17ae 968 return 0;
12e41d03
DL
969}
970
d62a17ae 971int pim_mroute_del(struct channel_oil *c_oil, const char *name)
12e41d03 972{
9a0f71c9 973 struct pim_instance *pim = c_oil->pim;
d62a17ae 974 int err;
975
856e863f
DS
976 pim->mroute_del_last = pim_time_monotonic_sec();
977 ++pim->mroute_del_events;
d62a17ae 978
979 if (!c_oil->installed) {
980 if (PIM_DEBUG_MROUTE) {
981 char buf[1000];
982 zlog_debug(
983 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
984 __FILE__, __PRETTY_FUNCTION__,
985 c_oil->oil.mfcc_parent,
986 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
987 }
988 return -2;
989 }
12e41d03 990
856e863f 991 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
d62a17ae 992 &c_oil->oil, sizeof(c_oil->oil));
993 if (err) {
994 if (PIM_DEBUG_MROUTE)
995 zlog_warn(
996 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
997 __FILE__, __PRETTY_FUNCTION__,
856e863f 998 pim->mroute_socket, errno,
d62a17ae 999 safe_strerror(errno));
1000 return -2;
1001 }
429a291b 1002
d62a17ae 1003 if (PIM_DEBUG_MROUTE) {
1004 char buf[1000];
996c9314
LB
1005 zlog_debug("%s(%s), vrf %s Deleted Route: %s",
1006 __PRETTY_FUNCTION__, name, pim->vrf->name,
d62fd596 1007 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
d62a17ae 1008 }
781a1745 1009
d62a17ae 1010 // Reset kernel installed flag
1011 c_oil->installed = 0;
58302dc7 1012
d62a17ae 1013 return 0;
12e41d03 1014}
3667e8a0 1015
d62a17ae 1016void pim_mroute_update_counters(struct channel_oil *c_oil)
3667e8a0 1017{
9a0f71c9 1018 struct pim_instance *pim = c_oil->pim;
d62a17ae 1019 struct sioc_sg_req sgreq;
1020
1021 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1022 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1023 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1024
1025 if (!c_oil->installed) {
19b807ca 1026 c_oil->cc.lastused = 100 * pim->keep_alive_time;
d62a17ae 1027 if (PIM_DEBUG_MROUTE) {
1028 struct prefix_sg sg;
1029
1030 sg.src = c_oil->oil.mfcc_origin;
1031 sg.grp = c_oil->oil.mfcc_mcastgrp;
1032 if (PIM_DEBUG_MROUTE)
1033 zlog_debug(
41714081 1034 "Channel%s is not installed no need to collect data from kernel",
d62a17ae 1035 pim_str_sg_dump(&sg));
1036 }
1037 return;
c7b1183f 1038 }
c7b1183f 1039
d62a17ae 1040 memset(&sgreq, 0, sizeof(sgreq));
1041 sgreq.src = c_oil->oil.mfcc_origin;
1042 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1043
1044 pim_zlookup_sg_statistics(c_oil);
856e863f 1045 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
d62a17ae 1046 if (PIM_DEBUG_MROUTE) {
1047 struct prefix_sg sg;
1048
1049 sg.src = c_oil->oil.mfcc_origin;
1050 sg.grp = c_oil->oil.mfcc_mcastgrp;
1051
1052 zlog_warn(
41714081 1053 "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
d62a17ae 1054 (unsigned long)SIOCGETSGCNT,
1055 pim_str_sg_dump(&sg), errno,
1056 safe_strerror(errno));
1057 }
1058 return;
c7b1183f 1059 }
3667e8a0 1060
d62a17ae 1061 c_oil->cc.pktcnt = sgreq.pktcnt;
1062 c_oil->cc.bytecnt = sgreq.bytecnt;
1063 c_oil->cc.wrong_if = sgreq.wrong_if;
3667e8a0 1064
d62a17ae 1065 return;
3667e8a0 1066}