]> git.proxmox.com Git - mirror_frr.git/blame_incremental - pimd/pim_mroute.c
pimd: ALLOC functions cannot fail.
[mirror_frr.git] / pimd / pim_mroute.c
... / ...
CommitLineData
1/*
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 */
19
20#include <zebra.h>
21#include "log.h"
22#include "privs.h"
23#include "if.h"
24#include "prefix.h"
25#include "vty.h"
26#include "plist.h"
27#include "sockopt.h"
28#include "lib_errors.h"
29
30#include "pimd.h"
31#include "pim_rpf.h"
32#include "pim_mroute.h"
33#include "pim_oil.h"
34#include "pim_str.h"
35#include "pim_time.h"
36#include "pim_iface.h"
37#include "pim_macro.h"
38#include "pim_rp.h"
39#include "pim_oil.h"
40#include "pim_register.h"
41#include "pim_ifchannel.h"
42#include "pim_zlookup.h"
43#include "pim_ssm.h"
44#include "pim_sock.h"
45#include "pim_vxlan.h"
46
47static void mroute_read_on(struct pim_instance *pim);
48
49static int pim_mroute_set(struct pim_instance *pim, int enable)
50{
51 int err;
52 int opt, data;
53 socklen_t data_len = sizeof(data);
54 long flags;
55
56 /*
57 * We need to create the VRF table for the pim mroute_socket
58 */
59 if (pim->vrf_id != VRF_DEFAULT) {
60 frr_elevate_privs(&pimd_privs) {
61
62 data = pim->vrf->data.l.table_id;
63 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
64 MRT_TABLE,
65 &data, data_len);
66 if (err) {
67 zlog_warn(
68 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
69 __FILE__, __PRETTY_FUNCTION__,
70 pim->mroute_socket, data, errno,
71 safe_strerror(errno));
72 return -1;
73 }
74
75 }
76 }
77
78 frr_elevate_privs(&pimd_privs) {
79 opt = enable ? MRT_INIT : MRT_DONE;
80 /*
81 * *BSD *cares* about what value we pass down
82 * here
83 */
84 data = 1;
85 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
86 opt, &data, data_len);
87 if (err) {
88 zlog_warn(
89 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
90 __FILE__, __PRETTY_FUNCTION__,
91 pim->mroute_socket,
92 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
93 safe_strerror(errno));
94 return -1;
95 }
96 }
97
98#if defined(HAVE_IP_PKTINFO)
99 if (enable) {
100 /* Linux and Solaris IP_PKTINFO */
101 data = 1;
102 if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
103 &data, data_len)) {
104 zlog_warn(
105 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
106 pim->mroute_socket, errno,
107 safe_strerror(errno));
108 }
109 }
110#endif
111
112 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
113
114 flags = fcntl(pim->mroute_socket, F_GETFL, 0);
115 if (flags < 0) {
116 zlog_warn("Could not get flags on socket fd:%d %d %s",
117 pim->mroute_socket, errno, safe_strerror(errno));
118 close(pim->mroute_socket);
119 return -1;
120 }
121 if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
122 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
123 pim->mroute_socket, errno, safe_strerror(errno));
124 close(pim->mroute_socket);
125 return -1;
126 }
127
128 if (enable) {
129#if defined linux
130 int upcalls = IGMPMSG_WRVIFWHOLE;
131 opt = MRT_PIM;
132
133 err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
134 sizeof(upcalls));
135 if (err) {
136 zlog_warn(
137 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
138 errno, safe_strerror(errno));
139 return -1;
140 }
141#else
142 zlog_warn(
143 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
144#endif
145 }
146
147 return 0;
148}
149
150static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
151 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
152
153static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
154 const struct igmpmsg *msg)
155{
156 struct pim_interface *pim_ifp = ifp->info;
157 struct pim_upstream *up;
158 struct pim_rpf *rpg;
159 struct prefix_sg sg;
160
161 rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
162 /*
163 * If the incoming interface is unknown OR
164 * the Interface type is SSM we don't need to
165 * do anything here
166 */
167 if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) {
168 if (PIM_DEBUG_MROUTE_DETAIL)
169 zlog_debug(
170 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
171 __PRETTY_FUNCTION__);
172
173 return 0;
174 }
175
176 /*
177 * If we've received a multicast packet that isn't connected to
178 * us
179 */
180 if (!pim_if_connected_to_source(ifp, msg->im_src)) {
181 if (PIM_DEBUG_MROUTE_DETAIL)
182 zlog_debug(
183 "%s: Received incoming packet that doesn't originate on our seg",
184 __PRETTY_FUNCTION__);
185 return 0;
186 }
187
188 memset(&sg, 0, sizeof(struct prefix_sg));
189 sg.src = msg->im_src;
190 sg.grp = msg->im_dst;
191
192 if (!(PIM_I_am_DR(pim_ifp))) {
193 struct channel_oil *c_oil;
194
195 if (PIM_DEBUG_MROUTE_DETAIL)
196 zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %s",
197 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
198
199 /*
200 * We are not the DR, but we are still receiving packets
201 * Let's blackhole those packets for the moment
202 * As that they will be coming up to the cpu
203 * and causing us to consider them.
204 */
205 c_oil = pim_channel_oil_add(pim_ifp->pim, &sg,
206 pim_ifp->mroute_vif_index,
207 __PRETTY_FUNCTION__);
208 pim_mroute_add(c_oil, __PRETTY_FUNCTION__);
209
210 return 0;
211 }
212
213 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
214 __PRETTY_FUNCTION__);
215
216 /*
217 * I moved this debug till after the actual add because
218 * I want to take advantage of the up->sg_str being filled in.
219 */
220 if (PIM_DEBUG_MROUTE) {
221 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
222 __PRETTY_FUNCTION__, up->sg_str);
223 }
224
225 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
226 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
227
228 up->channel_oil->cc.pktcnt++;
229 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
230 // resolve mfcc_parent prior to mroute_add in channel_add_oif
231 if (up->rpf.source_nexthop.interface &&
232 up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
233 int vif_index = 0;
234 vif_index = pim_if_find_vifindex_by_ifindex(
235 pim_ifp->pim,
236 up->rpf.source_nexthop.interface->ifindex);
237 up->channel_oil->oil.mfcc_parent = vif_index;
238 }
239 pim_register_join(up);
240
241 return 0;
242}
243
244static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
245 const char *buf)
246{
247 struct pim_interface *pim_ifp;
248 struct prefix_sg sg;
249 struct pim_rpf *rpg;
250 const struct ip *ip_hdr;
251 struct pim_upstream *up;
252
253 pim_ifp = ifp->info;
254
255 ip_hdr = (const struct ip *)buf;
256
257 memset(&sg, 0, sizeof(struct prefix_sg));
258 sg.src = ip_hdr->ip_src;
259 sg.grp = ip_hdr->ip_dst;
260
261 up = pim_upstream_find(pim_ifp->pim, &sg);
262 if (!up) {
263 struct prefix_sg star = sg;
264 star.src.s_addr = INADDR_ANY;
265
266 up = pim_upstream_find(pim_ifp->pim, &star);
267
268 if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) {
269 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
270 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
271 __PRETTY_FUNCTION__, NULL);
272 if (!up) {
273 if (PIM_DEBUG_MROUTE)
274 zlog_debug(
275 "%s: Unable to create upstream information for %s",
276 __PRETTY_FUNCTION__,
277 pim_str_sg_dump(&sg));
278 return 0;
279 }
280 pim_upstream_keep_alive_timer_start(
281 up, pim_ifp->pim->keep_alive_time);
282 pim_upstream_inherited_olist(pim_ifp->pim, up);
283 pim_upstream_switch(pim_ifp->pim, up,
284 PIM_UPSTREAM_JOINED);
285
286 if (PIM_DEBUG_MROUTE)
287 zlog_debug("%s: Creating %s upstream on LHR",
288 __PRETTY_FUNCTION__, up->sg_str);
289 return 0;
290 }
291 if (PIM_DEBUG_MROUTE_DETAIL) {
292 zlog_debug(
293 "%s: Unable to find upstream channel WHOLEPKT%s",
294 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
295 }
296 return 0;
297 }
298
299 if (!up->rpf.source_nexthop.interface) {
300 if (PIM_DEBUG_TRACE)
301 zlog_debug("%s: up %s RPF is not present",
302 __PRETTY_FUNCTION__, up->sg_str);
303 return 0;
304 }
305
306 pim_ifp = up->rpf.source_nexthop.interface->info;
307
308 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
309
310 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
311 || (!(PIM_I_am_DR(pim_ifp)))) {
312 if (PIM_DEBUG_MROUTE) {
313 zlog_debug("%s: Failed Check send packet",
314 __PRETTY_FUNCTION__);
315 }
316 return 0;
317 }
318
319 /*
320 * If we've received a register suppress
321 */
322 if (!up->t_rs_timer) {
323 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
324 if (PIM_DEBUG_PIM_REG)
325 zlog_debug(
326 "%s register forward skipped as group is SSM",
327 pim_str_sg_dump(&sg));
328 return 0;
329 }
330 pim_register_send((uint8_t *)buf + sizeof(struct ip),
331 ntohs(ip_hdr->ip_len) - sizeof(struct ip),
332 pim_ifp->primary_address, rpg, 0, up);
333 }
334 return 0;
335}
336
337static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
338 const struct igmpmsg *msg)
339{
340 struct pim_ifchannel *ch;
341 struct pim_interface *pim_ifp;
342 struct prefix_sg sg;
343
344 memset(&sg, 0, sizeof(struct prefix_sg));
345 sg.src = msg->im_src;
346 sg.grp = msg->im_dst;
347
348 /*
349 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
350
351 RFC 4601 4.8.2. PIM-SSM-Only Routers
352
353 iif is the incoming interface of the packet.
354 if (iif is in inherited_olist(S,G)) {
355 send Assert(S,G) on iif
356 }
357 */
358
359 if (!ifp) {
360 if (PIM_DEBUG_MROUTE)
361 zlog_debug(
362 "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
363 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
364 msg->im_vif);
365 return -1;
366 }
367
368 pim_ifp = ifp->info;
369 if (!pim_ifp) {
370 if (PIM_DEBUG_MROUTE)
371 zlog_debug(
372 "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
373 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
374 ifp->name);
375 return -2;
376 }
377
378 ch = pim_ifchannel_find(ifp, &sg);
379 if (!ch) {
380 struct prefix_sg star_g = sg;
381 if (PIM_DEBUG_MROUTE)
382 zlog_debug(
383 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
384 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
385 ifp->name);
386
387 star_g.src.s_addr = INADDR_ANY;
388 ch = pim_ifchannel_find(ifp, &star_g);
389 if (!ch) {
390 if (PIM_DEBUG_MROUTE)
391 zlog_debug(
392 "%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
393 __PRETTY_FUNCTION__,
394 pim_str_sg_dump(&star_g), ifp->name);
395 return -3;
396 }
397 }
398
399 /*
400 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
401
402 Transitions from NoInfo State
403
404 An (S,G) data packet arrives on interface I, AND
405 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
406 downstream interface that is in our (S,G) outgoing interface
407 list. We optimistically assume that we will be the assert
408 winner for this (S,G), and so we transition to the "I am Assert
409 Winner" state and perform Actions A1 (below), which will
410 initiate the assert negotiation for (S,G).
411 */
412
413 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
414 if (PIM_DEBUG_MROUTE) {
415 zlog_debug(
416 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
417 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
418 }
419 return -4;
420 }
421
422 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
423 if (PIM_DEBUG_MROUTE) {
424 zlog_debug(
425 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
426 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
427 }
428 return -5;
429 }
430
431 if (assert_action_a1(ch)) {
432 if (PIM_DEBUG_MROUTE) {
433 zlog_debug(
434 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
435 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
436 }
437 return -6;
438 }
439
440 return 0;
441}
442
443static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
444 const char *buf)
445{
446 const struct ip *ip_hdr = (const struct ip *)buf;
447 struct pim_interface *pim_ifp;
448 struct pim_ifchannel *ch;
449 struct pim_upstream *up;
450 struct prefix_sg star_g;
451 struct prefix_sg sg;
452 struct channel_oil *oil;
453
454 pim_ifp = ifp->info;
455
456 memset(&sg, 0, sizeof(struct prefix_sg));
457 sg.src = ip_hdr->ip_src;
458 sg.grp = ip_hdr->ip_dst;
459
460 ch = pim_ifchannel_find(ifp, &sg);
461 if (ch) {
462 if (PIM_DEBUG_MROUTE)
463 zlog_debug(
464 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
465 ch->sg_str, ifp->name);
466 return -1;
467 }
468
469 star_g = sg;
470 star_g.src.s_addr = INADDR_ANY;
471#if 0
472 ch = pim_ifchannel_find(ifp, &star_g);
473 if (ch)
474 {
475 if (PIM_DEBUG_MROUTE)
476 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
477 pim_str_sg_dump (&star_g), ifp->name);
478 return -1;
479 }
480#endif
481
482 up = pim_upstream_find(pim_ifp->pim, &sg);
483 if (up) {
484 struct pim_upstream *parent;
485 struct pim_nexthop source;
486 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
487 if (!rpf || !rpf->source_nexthop.interface)
488 return 0;
489
490 /*
491 * If we have received a WRVIFWHOLE and are at this
492 * point, we could be receiving the packet on the *,G
493 * tree, let's check and if so we can safely drop
494 * it.
495 */
496 parent = pim_upstream_find(pim_ifp->pim, &star_g);
497 if (parent && parent->rpf.source_nexthop.interface == ifp)
498 return 0;
499
500 pim_ifp = rpf->source_nexthop.interface->info;
501
502 memset(&source, 0, sizeof(source));
503 /*
504 * If we are the fhr that means we are getting a callback during
505 * the pimreg period, so I believe we can ignore this packet
506 */
507 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
508 // No if channel, but upstream we are at the RP.
509 if (pim_nexthop_lookup(pim_ifp->pim, &source,
510 up->upstream_register, 0)) {
511 pim_register_stop_send(source.interface, &sg,
512 pim_ifp->primary_address,
513 up->upstream_register);
514 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
515 }
516 if (!up->channel_oil)
517 up->channel_oil = pim_channel_oil_add(
518 pim_ifp->pim, &sg,
519 pim_ifp->mroute_vif_index,
520 __PRETTY_FUNCTION__);
521 pim_upstream_inherited_olist(pim_ifp->pim, up);
522 if (!up->channel_oil->installed)
523 pim_mroute_add(up->channel_oil,
524 __PRETTY_FUNCTION__);
525 } else {
526 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
527 if (pim_nexthop_lookup(pim_ifp->pim, &source,
528 up->upstream_register,
529 0))
530 pim_register_stop_send(
531 source.interface, &sg,
532 pim_ifp->primary_address,
533 up->upstream_register);
534 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
535 }
536 pim_upstream_keep_alive_timer_start(
537 up, pim_ifp->pim->keep_alive_time);
538 pim_upstream_inherited_olist(pim_ifp->pim, up);
539 pim_mroute_msg_wholepkt(fd, ifp, buf);
540 }
541 return 0;
542 }
543
544 pim_ifp = ifp->info;
545 oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index,
546 __PRETTY_FUNCTION__);
547 if (!oil->installed)
548 pim_mroute_add(oil, __PRETTY_FUNCTION__);
549 if (pim_if_connected_to_source(ifp, sg.src)) {
550 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
551 PIM_UPSTREAM_FLAG_MASK_FHR,
552 __PRETTY_FUNCTION__, NULL);
553 if (!up) {
554 if (PIM_DEBUG_MROUTE)
555 zlog_debug(
556 "%s: WRONGVIF%s unable to create upstream on interface",
557 pim_str_sg_dump(&sg), ifp->name);
558 return -2;
559 }
560 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
561 pim_upstream_keep_alive_timer_start(
562 up, pim_ifp->pim->keep_alive_time);
563 up->channel_oil = oil;
564 up->channel_oil->cc.pktcnt++;
565 pim_register_join(up);
566 pim_upstream_inherited_olist(pim_ifp->pim, up);
567
568 // Send the packet to the RP
569 pim_mroute_msg_wholepkt(fd, ifp, buf);
570 }
571
572 return 0;
573}
574
575static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
576 int buf_size, ifindex_t ifindex)
577{
578 struct interface *ifp;
579 struct pim_interface *pim_ifp;
580 const struct ip *ip_hdr;
581 const struct igmpmsg *msg;
582 char ip_src_str[INET_ADDRSTRLEN] = "";
583 char ip_dst_str[INET_ADDRSTRLEN] = "";
584 char src_str[INET_ADDRSTRLEN] = "<src?>";
585 char grp_str[INET_ADDRSTRLEN] = "<grp?>";
586 struct in_addr ifaddr;
587 struct igmp_sock *igmp;
588
589 ip_hdr = (const struct ip *)buf;
590
591 if (ip_hdr->ip_p == IPPROTO_IGMP) {
592
593 /* We have the IP packet but we do not know which interface this
594 * packet was
595 * received on. Find the interface that is on the same subnet as
596 * the source
597 * of the IP packet.
598 */
599 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
600
601 if (!ifp || !ifp->info)
602 return 0;
603
604 pim_ifp = ifp->info;
605 ifaddr = pim_find_primary_addr(ifp);
606 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
607 ifaddr);
608
609 if (PIM_DEBUG_MROUTE) {
610 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
611 sizeof(ip_src_str));
612 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
613 sizeof(ip_dst_str));
614
615 zlog_warn(
616 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
617 __PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
618 igmp, ip_src_str, ip_dst_str);
619 }
620 if (igmp)
621 pim_igmp_packet(igmp, (char *)buf, buf_size);
622
623 } else if (ip_hdr->ip_p) {
624 if (PIM_DEBUG_MROUTE_DETAIL) {
625 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
626 sizeof(src_str));
627 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
628 sizeof(grp_str));
629 zlog_debug(
630 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
631 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str,
632 grp_str, buf_size);
633 }
634
635 } else {
636 msg = (const struct igmpmsg *)buf;
637
638 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
639
640 if (!ifp)
641 return 0;
642 if (PIM_DEBUG_MROUTE) {
643 pim_inet4_dump("<src?>", msg->im_src, src_str,
644 sizeof(src_str));
645 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
646 sizeof(grp_str));
647 zlog_warn(
648 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
649 __PRETTY_FUNCTION__,
650 igmpmsgtype2str[msg->im_msgtype],
651 msg->im_msgtype, ip_hdr->ip_p,
652 pim->mroute_socket, src_str, grp_str, ifp->name,
653 msg->im_vif, buf_size);
654 }
655
656 switch (msg->im_msgtype) {
657 case IGMPMSG_WRONGVIF:
658 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
659 msg);
660 break;
661 case IGMPMSG_NOCACHE:
662 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
663 msg);
664 break;
665 case IGMPMSG_WHOLEPKT:
666 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
667 (const char *)msg);
668 break;
669 case IGMPMSG_WRVIFWHOLE:
670 return pim_mroute_msg_wrvifwhole(
671 pim->mroute_socket, ifp, (const char *)msg);
672 break;
673 default:
674 break;
675 }
676 }
677
678 return 0;
679}
680
681static int mroute_read(struct thread *t)
682{
683 struct pim_instance *pim;
684 static long long count;
685 char buf[10000];
686 int result = 0;
687 int cont = 1;
688 int rd;
689 ifindex_t ifindex;
690 pim = THREAD_ARG(t);
691
692 while (cont) {
693 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
694 sizeof(buf), NULL, NULL, NULL, NULL,
695 &ifindex);
696 if (rd <= 0) {
697 if (errno == EINTR)
698 continue;
699 if (errno == EWOULDBLOCK || errno == EAGAIN)
700 break;
701
702 if (PIM_DEBUG_MROUTE)
703 zlog_warn(
704 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
705 __PRETTY_FUNCTION__, rd,
706 pim->mroute_socket, errno,
707 safe_strerror(errno));
708 goto done;
709 }
710
711 result = pim_mroute_msg(pim, buf, rd, ifindex);
712
713 count++;
714 if (count % router->packet_process == 0)
715 cont = 0;
716 }
717/* Keep reading */
718done:
719 mroute_read_on(pim);
720
721 return result;
722}
723
724static void mroute_read_on(struct pim_instance *pim)
725{
726 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
727 &pim->thread);
728}
729
730static void mroute_read_off(struct pim_instance *pim)
731{
732 THREAD_OFF(pim->thread);
733}
734
735int pim_mroute_socket_enable(struct pim_instance *pim)
736{
737 int fd;
738
739 frr_elevate_privs(&pimd_privs) {
740
741 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
742
743 if (fd < 0) {
744 zlog_warn("Could not create mroute socket: errno=%d: %s",
745 errno,
746 safe_strerror(errno));
747 return -2;
748 }
749
750#ifdef SO_BINDTODEVICE
751 if (pim->vrf->vrf_id != VRF_DEFAULT
752 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
753 pim->vrf->name, strlen(pim->vrf->name))) {
754 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
755 safe_strerror(errno));
756 close(fd);
757 return -3;
758 }
759#endif
760
761 }
762
763 pim->mroute_socket = fd;
764 if (pim_mroute_set(pim, 1)) {
765 zlog_warn(
766 "Could not enable mroute on socket fd=%d: errno=%d: %s",
767 fd, errno, safe_strerror(errno));
768 close(fd);
769 pim->mroute_socket = -1;
770 return -3;
771 }
772
773 pim->mroute_socket_creation = pim_time_monotonic_sec();
774
775 mroute_read_on(pim);
776
777 return 0;
778}
779
780int pim_mroute_socket_disable(struct pim_instance *pim)
781{
782 if (pim_mroute_set(pim, 0)) {
783 zlog_warn(
784 "Could not disable mroute on socket fd=%d: errno=%d: %s",
785 pim->mroute_socket, errno, safe_strerror(errno));
786 return -2;
787 }
788
789 if (close(pim->mroute_socket)) {
790 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
791 pim->mroute_socket, errno, safe_strerror(errno));
792 return -3;
793 }
794
795 mroute_read_off(pim);
796 pim->mroute_socket = -1;
797
798 return 0;
799}
800
801/*
802 For each network interface (e.g., physical or a virtual tunnel) that
803 would be used for multicast forwarding, a corresponding multicast
804 interface must be added to the kernel.
805 */
806int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
807 unsigned char flags)
808{
809 struct pim_interface *pim_ifp = ifp->info;
810 struct vifctl vc;
811 int err;
812
813 if (PIM_DEBUG_MROUTE)
814 zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__,
815 pim_ifp->mroute_vif_index, ifp->name,
816 pim_ifp->pim->vrf->name);
817
818 memset(&vc, 0, sizeof(vc));
819 vc.vifc_vifi = pim_ifp->mroute_vif_index;
820#ifdef VIFF_USE_IFINDEX
821 vc.vifc_lcl_ifindex = ifp->ifindex;
822#else
823 if (ifaddr.s_addr == INADDR_ANY) {
824 zlog_warn(
825 "%s: unnumbered interfaces are not supported on this platform",
826 __PRETTY_FUNCTION__);
827 return -1;
828 }
829 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
830#endif
831 vc.vifc_flags = flags;
832 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
833 vc.vifc_rate_limit = 0;
834
835#ifdef PIM_DVMRP_TUNNEL
836 if (vc.vifc_flags & VIFF_TUNNEL) {
837 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
838 sizeof(vc.vifc_rmt_addr));
839 }
840#endif
841
842 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
843 (void *)&vc, sizeof(vc));
844 if (err) {
845 char ifaddr_str[INET_ADDRSTRLEN];
846
847 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
848 sizeof(ifaddr_str));
849
850 zlog_warn(
851 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
852 __PRETTY_FUNCTION__, pim_ifp->pim->mroute_socket,
853 ifp->ifindex, ifaddr_str, flags, errno,
854 safe_strerror(errno));
855 return -2;
856 }
857
858 return 0;
859}
860
861int pim_mroute_del_vif(struct interface *ifp)
862{
863 struct pim_interface *pim_ifp = ifp->info;
864 struct vifctl vc;
865 int err;
866
867 if (PIM_DEBUG_MROUTE)
868 zlog_debug("%s: Del Vif %d (%s[%s])", __PRETTY_FUNCTION__,
869 pim_ifp->mroute_vif_index, ifp->name,
870 pim_ifp->pim->vrf->name);
871
872 memset(&vc, 0, sizeof(vc));
873 vc.vifc_vifi = pim_ifp->mroute_vif_index;
874
875 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
876 (void *)&vc, sizeof(vc));
877 if (err) {
878 zlog_warn(
879 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
880 __FILE__, __PRETTY_FUNCTION__,
881 pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index,
882 errno, safe_strerror(errno));
883 return -2;
884 }
885
886 return 0;
887}
888
889int pim_mroute_add(struct channel_oil *c_oil, const char *name)
890{
891 struct pim_instance *pim = c_oil->pim;
892 int err;
893 int orig = 0;
894 int orig_iif_vif = 0;
895 struct pim_interface *pim_reg_ifp = NULL;
896 int orig_pimreg_ttl = 0;
897 bool pimreg_ttl_reset = false;
898 struct pim_interface *vxlan_ifp = NULL;
899 int orig_term_ttl = 0;
900 bool orig_term_ttl_reset = false;
901
902 pim->mroute_add_last = pim_time_monotonic_sec();
903 ++pim->mroute_add_events;
904
905 /* Do not install route if incoming interface is undefined. */
906 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
907 if (PIM_DEBUG_MROUTE) {
908 char buf[1000];
909 zlog_debug(
910 "%s(%s) %s Attempting to add vifi that is invalid to mroute table",
911 __PRETTY_FUNCTION__, name,
912 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
913 }
914 return -2;
915 }
916
917 /* The linux kernel *expects* the incoming
918 * vif to be part of the outgoing list
919 * in the case of a (*,G).
920 */
921 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
922 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
923 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
924 }
925
926 if (c_oil->up) {
927 /* suppress pimreg in the OIL if the mroute is not supposed to
928 * trigger register encapsulated data
929 */
930 if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags)) {
931 pim_reg_ifp = pim->regiface->info;
932 orig_pimreg_ttl =
933 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index];
934 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] = 0;
935 /* remember to flip it back after MFC programming */
936 pimreg_ttl_reset = true;
937 }
938
939 vxlan_ifp = pim_vxlan_get_term_ifp(pim);
940 /* 1. vxlan termination device must never be added to the
941 * origination mroute (and that can actually happen because
942 * of XG inheritance from the termination mroute) otherwise
943 * traffic will end up looping.
944 * 2. vxlan termination device should be removed from the non-DF
945 * to prevent duplicates to the overlay rxer
946 */
947 if (vxlan_ifp &&
948 (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
949 PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags))) {
950 orig_term_ttl_reset = true;
951 orig_term_ttl =
952 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index];
953 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] = 0;
954 }
955 }
956
957 /*
958 * If we have an unresolved cache entry for the S,G
959 * it is owned by the pimreg for the incoming IIF
960 * So set pimreg as the IIF temporarily to cause
961 * the packets to be forwarded. Then set it
962 * to the correct IIF afterwords.
963 */
964 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
965 && c_oil->oil.mfcc_parent != 0) {
966 orig_iif_vif = c_oil->oil.mfcc_parent;
967 c_oil->oil.mfcc_parent = 0;
968 }
969 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
970 &c_oil->oil, sizeof(c_oil->oil));
971
972 if (!err && !c_oil->installed
973 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
974 && orig_iif_vif != 0) {
975 c_oil->oil.mfcc_parent = orig_iif_vif;
976 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
977 &c_oil->oil, sizeof(c_oil->oil));
978 }
979
980 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
981 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
982
983 if (pimreg_ttl_reset) {
984 assert(pim_reg_ifp);
985 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] =
986 orig_pimreg_ttl;
987 }
988
989 if (orig_term_ttl_reset)
990 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] =
991 orig_term_ttl;
992
993 if (err) {
994 zlog_warn(
995 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
996 __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
997 errno, safe_strerror(errno));
998 return -2;
999 }
1000
1001 if (PIM_DEBUG_MROUTE) {
1002 char buf[1000];
1003 zlog_debug("%s(%s), vrf %s Added Route: %s",
1004 __PRETTY_FUNCTION__, name, pim->vrf->name,
1005 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1006 }
1007
1008 c_oil->installed = 1;
1009 c_oil->mroute_creation = pim_time_monotonic_sec();
1010
1011 return 0;
1012}
1013
1014int pim_mroute_del(struct channel_oil *c_oil, const char *name)
1015{
1016 struct pim_instance *pim = c_oil->pim;
1017 int err;
1018
1019 pim->mroute_del_last = pim_time_monotonic_sec();
1020 ++pim->mroute_del_events;
1021
1022 if (!c_oil->installed) {
1023 if (PIM_DEBUG_MROUTE) {
1024 char buf[1000];
1025 zlog_debug(
1026 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1027 __FILE__, __PRETTY_FUNCTION__,
1028 c_oil->oil.mfcc_parent,
1029 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1030 }
1031 return -2;
1032 }
1033
1034 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
1035 &c_oil->oil, sizeof(c_oil->oil));
1036 if (err) {
1037 if (PIM_DEBUG_MROUTE)
1038 zlog_warn(
1039 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
1040 __FILE__, __PRETTY_FUNCTION__,
1041 pim->mroute_socket, errno,
1042 safe_strerror(errno));
1043 return -2;
1044 }
1045
1046 if (PIM_DEBUG_MROUTE) {
1047 char buf[1000];
1048 zlog_debug("%s(%s), vrf %s Deleted Route: %s",
1049 __PRETTY_FUNCTION__, name, pim->vrf->name,
1050 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1051 }
1052
1053 // Reset kernel installed flag
1054 c_oil->installed = 0;
1055
1056 return 0;
1057}
1058
1059void pim_mroute_update_counters(struct channel_oil *c_oil)
1060{
1061 struct pim_instance *pim = c_oil->pim;
1062 struct sioc_sg_req sgreq;
1063
1064 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1065 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1066 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1067
1068 if (!c_oil->installed) {
1069 c_oil->cc.lastused = 100 * pim->keep_alive_time;
1070 if (PIM_DEBUG_MROUTE) {
1071 struct prefix_sg sg;
1072
1073 sg.src = c_oil->oil.mfcc_origin;
1074 sg.grp = c_oil->oil.mfcc_mcastgrp;
1075 if (PIM_DEBUG_MROUTE)
1076 zlog_debug(
1077 "Channel%s is not installed no need to collect data from kernel",
1078 pim_str_sg_dump(&sg));
1079 }
1080 return;
1081 }
1082
1083 memset(&sgreq, 0, sizeof(sgreq));
1084 sgreq.src = c_oil->oil.mfcc_origin;
1085 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1086
1087 pim_zlookup_sg_statistics(c_oil);
1088 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
1089 if (PIM_DEBUG_MROUTE) {
1090 struct prefix_sg sg;
1091
1092 sg.src = c_oil->oil.mfcc_origin;
1093 sg.grp = c_oil->oil.mfcc_mcastgrp;
1094
1095 zlog_warn(
1096 "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
1097 (unsigned long)SIOCGETSGCNT,
1098 pim_str_sg_dump(&sg), errno,
1099 safe_strerror(errno));
1100 }
1101 return;
1102 }
1103
1104 c_oil->cc.pktcnt = sgreq.pktcnt;
1105 c_oil->cc.bytecnt = sgreq.bytecnt;
1106 c_oil->cc.wrong_if = sgreq.wrong_if;
1107
1108 return;
1109}