]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[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
237 if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
238 int vif_index = 0;
239 vif_index = pim_if_find_vifindex_by_ifindex(
7cfc7bcf 240 pim_ifp->pim,
d62a17ae 241 up->rpf.source_nexthop.interface->ifindex);
242 up->channel_oil->oil.mfcc_parent = vif_index;
243 }
244 pim_register_join(up);
59471fb8 245
d62a17ae 246 return 0;
e355e30f 247}
12e41d03 248
d62a17ae 249static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
250 const char *buf)
e355e30f 251{
d62a17ae 252 struct pim_interface *pim_ifp;
253 struct prefix_sg sg;
254 struct pim_rpf *rpg;
255 const struct ip *ip_hdr;
256 struct pim_upstream *up;
257
9b29ea95
DS
258 pim_ifp = ifp->info;
259
d62a17ae 260 ip_hdr = (const struct ip *)buf;
261
262 memset(&sg, 0, sizeof(struct prefix_sg));
263 sg.src = ip_hdr->ip_src;
264 sg.grp = ip_hdr->ip_dst;
265
9b29ea95 266 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 267 if (!up) {
268 struct prefix_sg star = sg;
269 star.src.s_addr = INADDR_ANY;
270
9b29ea95 271 up = pim_upstream_find(pim_ifp->pim, &star);
d62a17ae 272
273 if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) {
2002dcdb 274 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
d62a17ae 275 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
0885a9f1 276 __PRETTY_FUNCTION__, NULL);
d62a17ae 277 if (!up) {
278 if (PIM_DEBUG_MROUTE)
279 zlog_debug(
280 "%s: Unable to create upstream information for %s",
281 __PRETTY_FUNCTION__,
282 pim_str_sg_dump(&sg));
283 return 0;
284 }
285 pim_upstream_keep_alive_timer_start(
19b807ca 286 up, pim_ifp->pim->keep_alive_time);
9b29ea95 287 pim_upstream_inherited_olist(pim_ifp->pim, up);
1eca8576
DS
288 pim_upstream_switch(pim_ifp->pim, up,
289 PIM_UPSTREAM_JOINED);
d62a17ae 290
291 if (PIM_DEBUG_MROUTE)
292 zlog_debug("%s: Creating %s upstream on LHR",
293 __PRETTY_FUNCTION__, up->sg_str);
294 return 0;
295 }
296 if (PIM_DEBUG_MROUTE_DETAIL) {
297 zlog_debug(
298 "%s: Unable to find upstream channel WHOLEPKT%s",
299 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
300 }
301 return 0;
302 }
59471fb8 303
d62a17ae 304 pim_ifp = up->rpf.source_nexthop.interface->info;
998af219 305
b575a12c 306 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
c8ae3ce8 307
d62a17ae 308 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
309 || (!(PIM_I_am_DR(pim_ifp)))) {
310 if (PIM_DEBUG_MROUTE) {
311 zlog_debug("%s: Failed Check send packet",
312 __PRETTY_FUNCTION__);
313 }
314 return 0;
315 }
84366c7e 316
d62a17ae 317 /*
318 * If we've received a register suppress
319 */
320 if (!up->t_rs_timer) {
6f439a70 321 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
d62a17ae 322 if (PIM_DEBUG_PIM_REG)
323 zlog_debug(
324 "%s register forward skipped as group is SSM",
325 pim_str_sg_dump(&sg));
326 return 0;
327 }
328 pim_register_send((uint8_t *)buf + sizeof(struct ip),
329 ntohs(ip_hdr->ip_len) - sizeof(struct ip),
330 pim_ifp->primary_address, rpg, 0, up);
331 }
332 return 0;
e355e30f 333}
12e41d03 334
d62a17ae 335static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
336 const struct igmpmsg *msg)
e355e30f 337{
d62a17ae 338 struct pim_ifchannel *ch;
339 struct pim_interface *pim_ifp;
340 struct prefix_sg sg;
341
342 memset(&sg, 0, sizeof(struct prefix_sg));
343 sg.src = msg->im_src;
344 sg.grp = msg->im_dst;
345
346 /*
347 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
348
349 RFC 4601 4.8.2. PIM-SSM-Only Routers
350
351 iif is the incoming interface of the packet.
352 if (iif is in inherited_olist(S,G)) {
353 send Assert(S,G) on iif
354 }
355 */
356
357 if (!ifp) {
358 if (PIM_DEBUG_MROUTE)
359 zlog_debug(
360 "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
361 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
362 msg->im_vif);
363 return -1;
364 }
12e41d03 365
d62a17ae 366 pim_ifp = ifp->info;
367 if (!pim_ifp) {
368 if (PIM_DEBUG_MROUTE)
369 zlog_debug(
370 "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
371 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
372 ifp->name);
373 return -2;
374 }
c29a5806 375
d62a17ae 376 ch = pim_ifchannel_find(ifp, &sg);
377 if (!ch) {
378 struct prefix_sg star_g = sg;
379 if (PIM_DEBUG_MROUTE)
380 zlog_debug(
381 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
382 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
383 ifp->name);
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",
391 __PRETTY_FUNCTION__,
392 pim_str_sg_dump(&star_g), ifp->name);
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",
415 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
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",
424 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
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",
433 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
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;
446 struct pim_ifchannel *ch;
447 struct pim_upstream *up;
448 struct prefix_sg star_g;
449 struct prefix_sg sg;
450 struct channel_oil *oil;
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;
b7ddd2ec 469#if 0
0490c22d
DS
470 ch = pim_ifchannel_find(ifp, &star_g);
471 if (ch)
472 {
473 if (PIM_DEBUG_MROUTE)
474 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
475 pim_str_sg_dump (&star_g), ifp->name);
476 return -1;
477 }
5cd11e3c 478#endif
08e1fe76 479
9b29ea95 480 up = pim_upstream_find(pim_ifp->pim, &sg);
d62a17ae 481 if (up) {
482 struct pim_upstream *parent;
483 struct pim_nexthop source;
fec883d9 484 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
d62a17ae 485 if (!rpf || !rpf->source_nexthop.interface)
486 return 0;
487
488 /*
489 * If we have received a WRVIFWHOLE and are at this
490 * point, we could be receiving the packet on the *,G
491 * tree, let's check and if so we can safely drop
492 * it.
493 */
9b29ea95 494 parent = pim_upstream_find(pim_ifp->pim, &star_g);
d62a17ae 495 if (parent && parent->rpf.source_nexthop.interface == ifp)
496 return 0;
497
498 pim_ifp = rpf->source_nexthop.interface->info;
499
500 memset(&source, 0, sizeof(source));
501 /*
502 * If we are the fhr that means we are getting a callback during
503 * the pimreg period, so I believe we can ignore this packet
504 */
505 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
506 // No if channel, but upstream we are at the RP.
d9c9a9ee
DS
507 if (pim_nexthop_lookup(pim_ifp->pim, &source,
508 up->upstream_register, 0)
df766618 509 == 0) {
d62a17ae 510 pim_register_stop_send(source.interface, &sg,
511 pim_ifp->primary_address,
512 up->upstream_register);
df766618
DS
513 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
514 }
d62a17ae 515 if (!up->channel_oil)
516 up->channel_oil = pim_channel_oil_add(
611925dc
DS
517 pim_ifp->pim, &sg,
518 pim_ifp->mroute_vif_index);
9b29ea95 519 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 520 if (!up->channel_oil->installed)
521 pim_mroute_add(up->channel_oil,
522 __PRETTY_FUNCTION__);
d62a17ae 523 } else {
d9c9a9ee
DS
524 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
525 if (pim_nexthop_lookup(pim_ifp->pim, &source,
d62a17ae 526 up->upstream_register, 0)
527 == 0)
528 pim_register_stop_send(
529 source.interface, &sg,
530 pim_ifp->primary_address,
531 up->upstream_register);
532 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
533 }
534 pim_upstream_keep_alive_timer_start(
19b807ca 535 up, pim_ifp->pim->keep_alive_time);
9b29ea95 536 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 537 pim_mroute_msg_wholepkt(fd, ifp, buf);
538 }
539 return 0;
540 }
8e38a2cf 541
d62a17ae 542 pim_ifp = ifp->info;
611925dc 543 oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index);
d62a17ae 544 if (!oil->installed)
545 pim_mroute_add(oil, __PRETTY_FUNCTION__);
546 if (pim_if_connected_to_source(ifp, sg.src)) {
2002dcdb
DS
547 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
548 PIM_UPSTREAM_FLAG_MASK_FHR,
0885a9f1 549 __PRETTY_FUNCTION__, NULL);
d62a17ae 550 if (!up) {
551 if (PIM_DEBUG_MROUTE)
552 zlog_debug(
553 "%s: WRONGVIF%s unable to create upstream on interface",
554 pim_str_sg_dump(&sg), ifp->name);
555 return -2;
556 }
557 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
996c9314
LB
558 pim_upstream_keep_alive_timer_start(
559 up, pim_ifp->pim->keep_alive_time);
d62a17ae 560 up->channel_oil = oil;
561 up->channel_oil->cc.pktcnt++;
562 pim_register_join(up);
9b29ea95 563 pim_upstream_inherited_olist(pim_ifp->pim, up);
d62a17ae 564
565 // Send the packet to the RP
566 pim_mroute_msg_wholepkt(fd, ifp, buf);
567 }
08e1fe76 568
d62a17ae 569 return 0;
08e1fe76
DS
570}
571
405d6357 572static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
90450a3d 573 int buf_size, ifindex_t ifindex)
e355e30f 574{
d62a17ae 575 struct interface *ifp;
576 struct pim_interface *pim_ifp;
577 const struct ip *ip_hdr;
578 const struct igmpmsg *msg;
579 char ip_src_str[INET_ADDRSTRLEN] = "";
580 char ip_dst_str[INET_ADDRSTRLEN] = "";
581 char src_str[INET_ADDRSTRLEN] = "<src?>";
582 char grp_str[INET_ADDRSTRLEN] = "<grp?>";
583 struct in_addr ifaddr;
584 struct igmp_sock *igmp;
585
586 ip_hdr = (const struct ip *)buf;
587
588 if (ip_hdr->ip_p == IPPROTO_IGMP) {
589
590 /* We have the IP packet but we do not know which interface this
591 * packet was
592 * received on. Find the interface that is on the same subnet as
593 * the source
594 * of the IP packet.
595 */
90450a3d 596 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
d62a17ae 597
1ef8c24e 598 if (!ifp || !ifp->info)
d62a17ae 599 return 0;
90450a3d 600
d62a17ae 601 pim_ifp = ifp->info;
602 ifaddr = pim_find_primary_addr(ifp);
603 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
604 ifaddr);
605
606 if (PIM_DEBUG_MROUTE) {
607 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
608 sizeof(ip_src_str));
609 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
610 sizeof(ip_dst_str));
611
612 zlog_warn(
7c2bfc2a
DS
613 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
614 __PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
615 igmp, ip_src_str, ip_dst_str);
d62a17ae 616 }
617 if (igmp)
618 pim_igmp_packet(igmp, (char *)buf, buf_size);
619
620 } else if (ip_hdr->ip_p) {
621 if (PIM_DEBUG_MROUTE_DETAIL) {
622 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
623 sizeof(src_str));
624 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
625 sizeof(grp_str));
626 zlog_debug(
627 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
628 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str,
629 grp_str, buf_size);
630 }
631
632 } else {
633 msg = (const struct igmpmsg *)buf;
634
7cfc7bcf 635 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
d62a17ae 636
637 if (!ifp)
638 return 0;
639 if (PIM_DEBUG_MROUTE) {
640 pim_inet4_dump("<src?>", msg->im_src, src_str,
641 sizeof(src_str));
642 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
643 sizeof(grp_str));
644 zlog_warn(
645 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
646 __PRETTY_FUNCTION__,
647 igmpmsgtype2str[msg->im_msgtype],
405d6357
DS
648 msg->im_msgtype, ip_hdr->ip_p,
649 pim->mroute_socket, src_str, grp_str, ifp->name,
650 msg->im_vif, buf_size);
d62a17ae 651 }
652
653 switch (msg->im_msgtype) {
654 case IGMPMSG_WRONGVIF:
405d6357
DS
655 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
656 msg);
d62a17ae 657 break;
658 case IGMPMSG_NOCACHE:
405d6357
DS
659 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
660 msg);
d62a17ae 661 break;
662 case IGMPMSG_WHOLEPKT:
405d6357 663 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
d62a17ae 664 (const char *)msg);
665 break;
666 case IGMPMSG_WRVIFWHOLE:
405d6357
DS
667 return pim_mroute_msg_wrvifwhole(
668 pim->mroute_socket, ifp, (const char *)msg);
d62a17ae 669 break;
670 default:
671 break;
672 }
673 }
12e41d03 674
d62a17ae 675 return 0;
12e41d03
DL
676}
677
12e41d03
DL
678static int mroute_read(struct thread *t)
679{
8ea5d944 680 struct pim_instance *pim;
d62a17ae 681 static long long count;
682 char buf[10000];
683 int result = 0;
684 int cont = 1;
d62a17ae 685 int rd;
90450a3d 686 ifindex_t ifindex;
8ea5d944 687 pim = THREAD_ARG(t);
d62a17ae 688
689 while (cont) {
90450a3d
DS
690 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
691 sizeof(buf), NULL, NULL, NULL, NULL,
692 &ifindex);
61e99c94 693 if (rd <= 0) {
d62a17ae 694 if (errno == EINTR)
695 continue;
696 if (errno == EWOULDBLOCK || errno == EAGAIN)
697 break;
698
699 if (PIM_DEBUG_MROUTE)
700 zlog_warn(
61e99c94 701 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
8ea5d944
DS
702 __PRETTY_FUNCTION__, rd,
703 pim->mroute_socket, errno,
d62a17ae 704 safe_strerror(errno));
705 goto done;
706 }
707
90450a3d 708 result = pim_mroute_msg(pim, buf, rd, ifindex);
d62a17ae 709
710 count++;
711 if (count % qpim_packet_process == 0)
712 cont = 0;
713 }
714/* Keep reading */
715done:
8ea5d944 716 mroute_read_on(pim);
12e41d03 717
d62a17ae 718 return result;
12e41d03
DL
719}
720
8ea5d944 721static void mroute_read_on(struct pim_instance *pim)
12e41d03 722{
f509d941 723 thread_add_read(master, mroute_read, pim, pim->mroute_socket,
8ea5d944 724 &pim->thread);
12e41d03
DL
725}
726
8ea5d944 727static void mroute_read_off(struct pim_instance *pim)
12e41d03 728{
8ea5d944 729 THREAD_OFF(pim->thread);
12e41d03
DL
730}
731
6beed987 732int pim_mroute_socket_enable(struct pim_instance *pim)
12e41d03 733{
d62a17ae 734 int fd;
12e41d03 735
01b9e3fd 736 frr_elevate_privs(&pimd_privs) {
12e41d03 737
01b9e3fd 738 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
12e41d03 739
01b9e3fd
DL
740 if (fd < 0) {
741 zlog_warn("Could not create mroute socket: errno=%d: %s",
742 errno,
743 safe_strerror(errno));
744 return -2;
745 }
e691f179 746
466e4e5b 747#ifdef SO_BINDTODEVICE
01b9e3fd 748 if (pim->vrf->vrf_id != VRF_DEFAULT
633fc9b1
DL
749 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
750 pim->vrf->name, strlen(pim->vrf->name))) {
01b9e3fd
DL
751 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
752 safe_strerror(errno));
753 close(fd);
754 return -3;
755 }
466e4e5b 756#endif
90450a3d 757
01b9e3fd 758 }
12e41d03 759
cdbfaec5
DS
760 pim->mroute_socket = fd;
761 if (pim_mroute_set(pim, 1)) {
d62a17ae 762 zlog_warn(
763 "Could not enable mroute on socket fd=%d: errno=%d: %s",
764 fd, errno, safe_strerror(errno));
765 close(fd);
cdbfaec5 766 pim->mroute_socket = -1;
d62a17ae 767 return -3;
768 }
12e41d03 769
6beed987 770 pim->mroute_socket_creation = pim_time_monotonic_sec();
b45cefcb 771
8ea5d944 772 mroute_read_on(pim);
12e41d03 773
d62a17ae 774 return 0;
12e41d03
DL
775}
776
6beed987 777int pim_mroute_socket_disable(struct pim_instance *pim)
12e41d03 778{
cdbfaec5 779 if (pim_mroute_set(pim, 0)) {
d62a17ae 780 zlog_warn(
781 "Could not disable mroute on socket fd=%d: errno=%d: %s",
405d6357 782 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 783 return -2;
784 }
785
6beed987 786 if (close(pim->mroute_socket)) {
d62a17ae 787 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
405d6357 788 pim->mroute_socket, errno, safe_strerror(errno));
d62a17ae 789 return -3;
790 }
791
8ea5d944 792 mroute_read_off(pim);
6beed987 793 pim->mroute_socket = -1;
d62a17ae 794
795 return 0;
12e41d03
DL
796}
797
798/*
799 For each network interface (e.g., physical or a virtual tunnel) that
800 would be used for multicast forwarding, a corresponding multicast
801 interface must be added to the kernel.
802 */
d62a17ae 803int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
804 unsigned char flags)
12e41d03 805{
d62a17ae 806 struct pim_interface *pim_ifp = ifp->info;
807 struct vifctl vc;
808 int err;
12e41d03 809
08f4f901 810 if (PIM_DEBUG_MROUTE)
d62fd596 811 zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__,
996c9314
LB
812 pim_ifp->mroute_vif_index, ifp->name,
813 pim_ifp->pim->vrf->name);
08f4f901 814
d62a17ae 815 memset(&vc, 0, sizeof(vc));
816 vc.vifc_vifi = pim_ifp->mroute_vif_index;
b3f2bf7c 817#ifdef VIFF_USE_IFINDEX
d62a17ae 818 vc.vifc_lcl_ifindex = ifp->ifindex;
b3f2bf7c 819#else
d62a17ae 820 if (ifaddr.s_addr == INADDR_ANY) {
821 zlog_warn(
822 "%s: unnumbered interfaces are not supported on this platform",
823 __PRETTY_FUNCTION__);
824 return -1;
825 }
826 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
b3f2bf7c 827#endif
d62a17ae 828 vc.vifc_flags = flags;
829 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
830 vc.vifc_rate_limit = 0;
831
832#ifdef PIM_DVMRP_TUNNEL
833 if (vc.vifc_flags & VIFF_TUNNEL) {
834 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
835 sizeof(vc.vifc_rmt_addr));
836 }
12e41d03
DL
837#endif
838
ea3d967b 839 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
d62a17ae 840 (void *)&vc, sizeof(vc));
841 if (err) {
842 char ifaddr_str[INET_ADDRSTRLEN];
12e41d03 843
d62a17ae 844 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
845 sizeof(ifaddr_str));
12e41d03 846
d62a17ae 847 zlog_warn(
08f4f901 848 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
996c9314
LB
849 __PRETTY_FUNCTION__, pim_ifp->pim->mroute_socket,
850 ifp->ifindex, ifaddr_str, flags, errno,
851 safe_strerror(errno));
d62a17ae 852 return -2;
853 }
12e41d03 854
d62a17ae 855 return 0;
12e41d03
DL
856}
857
ea3d967b 858int pim_mroute_del_vif(struct interface *ifp)
12e41d03 859{
ea3d967b 860 struct pim_interface *pim_ifp = ifp->info;
d62a17ae 861 struct vifctl vc;
862 int err;
863
ea3d967b 864 if (PIM_DEBUG_MROUTE)
996c9314
LB
865 zlog_debug("%s: Del Vif %d (%s[%s])", __PRETTY_FUNCTION__,
866 pim_ifp->mroute_vif_index, ifp->name,
867 pim_ifp->pim->vrf->name);
12e41d03 868
d62a17ae 869 memset(&vc, 0, sizeof(vc));
ea3d967b 870 vc.vifc_vifi = pim_ifp->mroute_vif_index;
d62a17ae 871
ea3d967b 872 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
d62a17ae 873 (void *)&vc, sizeof(vc));
874 if (err) {
875 zlog_warn(
876 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
ea3d967b
DS
877 __FILE__, __PRETTY_FUNCTION__,
878 pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index,
879 errno, safe_strerror(errno));
d62a17ae 880 return -2;
881 }
12e41d03 882
d62a17ae 883 return 0;
12e41d03
DL
884}
885
6a78764e 886int pim_mroute_add(struct channel_oil *c_oil, const char *name)
12e41d03 887{
9a0f71c9 888 struct pim_instance *pim = c_oil->pim;
d62a17ae 889 int err;
890 int orig = 0;
891 int orig_iif_vif = 0;
892
856e863f
DS
893 pim->mroute_add_last = pim_time_monotonic_sec();
894 ++pim->mroute_add_events;
d62a17ae 895
896 /* Do not install route if incoming interface is undefined. */
897 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
898 if (PIM_DEBUG_MROUTE) {
899 char buf[1000];
900 zlog_debug(
901 "%s(%s) %s Attempting to add vifi that is invalid to mroute table",
902 __PRETTY_FUNCTION__, name,
903 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
904 }
905 return -2;
906 }
d3aded99 907
d62a17ae 908 /* The linux kernel *expects* the incoming
909 * vif to be part of the outgoing list
910 * in the case of a (*,G).
911 */
912 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
913 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
914 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
915 }
d3aded99 916
d62a17ae 917 /*
918 * If we have an unresolved cache entry for the S,G
919 * it is owned by the pimreg for the incoming IIF
920 * So set pimreg as the IIF temporarily to cause
921 * the packets to be forwarded. Then set it
922 * to the correct IIF afterwords.
923 */
924 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
925 && c_oil->oil.mfcc_parent != 0) {
926 orig_iif_vif = c_oil->oil.mfcc_parent;
927 c_oil->oil.mfcc_parent = 0;
928 }
856e863f 929 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
d62a17ae 930 &c_oil->oil, sizeof(c_oil->oil));
931
932 if (!err && !c_oil->installed
933 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
934 && orig_iif_vif != 0) {
935 c_oil->oil.mfcc_parent = orig_iif_vif;
856e863f 936 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
d62a17ae 937 &c_oil->oil, sizeof(c_oil->oil));
938 }
0365f56b 939
d62a17ae 940 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
941 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
d3aded99 942
d62a17ae 943 if (err) {
944 zlog_warn(
945 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
856e863f 946 __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
d62a17ae 947 errno, safe_strerror(errno));
948 return -2;
949 }
12e41d03 950
d62a17ae 951 if (PIM_DEBUG_MROUTE) {
952 char buf[1000];
996c9314
LB
953 zlog_debug("%s(%s), vrf %s Added Route: %s",
954 __PRETTY_FUNCTION__, name, pim->vrf->name,
d62a17ae 955 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
956 }
6a78764e 957
d62a17ae 958 c_oil->installed = 1;
959 return 0;
12e41d03
DL
960}
961
d62a17ae 962int pim_mroute_del(struct channel_oil *c_oil, const char *name)
12e41d03 963{
9a0f71c9 964 struct pim_instance *pim = c_oil->pim;
d62a17ae 965 int err;
966
856e863f
DS
967 pim->mroute_del_last = pim_time_monotonic_sec();
968 ++pim->mroute_del_events;
d62a17ae 969
970 if (!c_oil->installed) {
971 if (PIM_DEBUG_MROUTE) {
972 char buf[1000];
973 zlog_debug(
974 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
975 __FILE__, __PRETTY_FUNCTION__,
976 c_oil->oil.mfcc_parent,
977 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
978 }
979 return -2;
980 }
12e41d03 981
856e863f 982 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
d62a17ae 983 &c_oil->oil, sizeof(c_oil->oil));
984 if (err) {
985 if (PIM_DEBUG_MROUTE)
986 zlog_warn(
987 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
988 __FILE__, __PRETTY_FUNCTION__,
856e863f 989 pim->mroute_socket, errno,
d62a17ae 990 safe_strerror(errno));
991 return -2;
992 }
429a291b 993
d62a17ae 994 if (PIM_DEBUG_MROUTE) {
995 char buf[1000];
996c9314
LB
996 zlog_debug("%s(%s), vrf %s Deleted Route: %s",
997 __PRETTY_FUNCTION__, name, pim->vrf->name,
d62fd596 998 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
d62a17ae 999 }
781a1745 1000
d62a17ae 1001 // Reset kernel installed flag
1002 c_oil->installed = 0;
58302dc7 1003
d62a17ae 1004 return 0;
12e41d03 1005}
3667e8a0 1006
d62a17ae 1007void pim_mroute_update_counters(struct channel_oil *c_oil)
3667e8a0 1008{
9a0f71c9 1009 struct pim_instance *pim = c_oil->pim;
d62a17ae 1010 struct sioc_sg_req sgreq;
1011
1012 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1013 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1014 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1015
1016 if (!c_oil->installed) {
19b807ca 1017 c_oil->cc.lastused = 100 * pim->keep_alive_time;
d62a17ae 1018 if (PIM_DEBUG_MROUTE) {
1019 struct prefix_sg sg;
1020
1021 sg.src = c_oil->oil.mfcc_origin;
1022 sg.grp = c_oil->oil.mfcc_mcastgrp;
1023 if (PIM_DEBUG_MROUTE)
1024 zlog_debug(
1025 "Channel(%s) is not installed no need to collect data from kernel",
1026 pim_str_sg_dump(&sg));
1027 }
1028 return;
c7b1183f 1029 }
c7b1183f 1030
d62a17ae 1031 memset(&sgreq, 0, sizeof(sgreq));
1032 sgreq.src = c_oil->oil.mfcc_origin;
1033 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1034
1035 pim_zlookup_sg_statistics(c_oil);
856e863f 1036 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
d62a17ae 1037 if (PIM_DEBUG_MROUTE) {
1038 struct prefix_sg sg;
1039
1040 sg.src = c_oil->oil.mfcc_origin;
1041 sg.grp = c_oil->oil.mfcc_mcastgrp;
1042
1043 zlog_warn(
1044 "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
1045 (unsigned long)SIOCGETSGCNT,
1046 pim_str_sg_dump(&sg), errno,
1047 safe_strerror(errno));
1048 }
1049 return;
c7b1183f 1050 }
3667e8a0 1051
d62a17ae 1052 c_oil->cc.pktcnt = sgreq.pktcnt;
1053 c_oil->cc.bytecnt = sgreq.bytecnt;
1054 c_oil->cc.wrong_if = sgreq.wrong_if;
3667e8a0 1055
d62a17ae 1056 return;
3667e8a0 1057}