]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_mroute.c
pim6d: get into a kinda-working state wrt. zebra
[mirror_frr.git] / pimd / pim_mroute.c
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
47 static void mroute_read_on(struct pim_instance *pim);
48
49 static 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->vrf_id != VRF_DEFAULT) {
60 frr_with_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__, __func__, pim->mroute_socket,
70 data, errno, safe_strerror(errno));
71 return -1;
72 }
73
74 }
75 }
76
77 frr_with_privs(&pimd_privs) {
78 opt = enable ? MRT_INIT : MRT_DONE;
79 /*
80 * *BSD *cares* about what value we pass down
81 * here
82 */
83 data = 1;
84 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
85 opt, &data, data_len);
86 if (err) {
87 zlog_warn(
88 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
89 __FILE__, __func__, pim->mroute_socket,
90 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
91 safe_strerror(errno));
92 return -1;
93 }
94 }
95
96 #if defined(HAVE_IP_PKTINFO)
97 if (enable) {
98 /* Linux and Solaris IP_PKTINFO */
99 data = 1;
100 if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
101 &data, data_len)) {
102 zlog_warn(
103 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
104 pim->mroute_socket, errno,
105 safe_strerror(errno));
106 }
107 }
108 #endif
109
110 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
111
112 flags = fcntl(pim->mroute_socket, F_GETFL, 0);
113 if (flags < 0) {
114 zlog_warn("Could not get flags on socket fd:%d %d %s",
115 pim->mroute_socket, errno, safe_strerror(errno));
116 close(pim->mroute_socket);
117 return -1;
118 }
119 if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
120 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
121 pim->mroute_socket, errno, safe_strerror(errno));
122 close(pim->mroute_socket);
123 return -1;
124 }
125
126 if (enable) {
127 #if defined linux
128 int upcalls = IGMPMSG_WRVIFWHOLE;
129 opt = MRT_PIM;
130
131 err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
132 sizeof(upcalls));
133 if (err) {
134 zlog_warn(
135 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
136 errno, safe_strerror(errno));
137 return -1;
138 }
139 #else
140 zlog_warn(
141 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
142 #endif
143 }
144
145 return 0;
146 }
147
148 #if PIM_IPV == 4
149 static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
150 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
151
152 static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
153 const struct igmpmsg *msg)
154 {
155 struct pim_interface *pim_ifp = ifp->info;
156 struct pim_upstream *up;
157 struct pim_rpf *rpg;
158 pim_sgaddr sg;
159
160 rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
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 */
166 if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) {
167 if (PIM_DEBUG_MROUTE_DETAIL)
168 zlog_debug(
169 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
170 __func__);
171
172 return 0;
173 }
174
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 __func__);
184 return 0;
185 }
186
187 memset(&sg, 0, sizeof(sg));
188 sg.src = msg->im_src;
189 sg.grp = msg->im_dst;
190
191 if (!(PIM_I_am_DR(pim_ifp))) {
192 if (PIM_DEBUG_MROUTE_DETAIL)
193 zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %pSG",
194 __func__, &sg);
195
196 /*
197 * We are not the DR, but we are still receiving packets
198 * Let's blackhole those packets for the moment
199 * As that they will be coming up to the cpu
200 * and causing us to consider them.
201 *
202 * This *will* create a dangling channel_oil
203 * that I see no way to get rid of. Just noting
204 * this for future reference.
205 */
206 up = pim_upstream_find_or_add(
207 &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
208 pim_upstream_mroute_add(up->channel_oil, __func__);
209
210 return 0;
211 }
212
213 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
214 __func__);
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 __func__, 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 // resolve mfcc_parent prior to mroute_add in channel_add_oif
230 if (up->rpf.source_nexthop.interface &&
231 *oil_parent(up->channel_oil) >= MAXVIFS) {
232 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
233 }
234 pim_register_join(up);
235 /* if we have receiver, inherit from parent */
236 pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
237
238 return 0;
239 }
240
241 static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
242 const char *buf)
243 {
244 struct pim_interface *pim_ifp;
245 pim_sgaddr sg;
246 struct pim_rpf *rpg;
247 const struct ip *ip_hdr;
248 struct pim_upstream *up;
249
250 pim_ifp = ifp->info;
251
252 ip_hdr = (const struct ip *)buf;
253
254 memset(&sg, 0, sizeof(sg));
255 sg.src = ip_hdr->ip_src;
256 sg.grp = ip_hdr->ip_dst;
257
258 up = pim_upstream_find(pim_ifp->pim, &sg);
259 if (!up) {
260 pim_sgaddr star = sg;
261 star.src = PIMADDR_ANY;
262
263 up = pim_upstream_find(pim_ifp->pim, &star);
264
265 if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) {
266 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
267 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
268 __func__, NULL);
269 if (!up) {
270 if (PIM_DEBUG_MROUTE)
271 zlog_debug("%s: Unable to create upstream information for %pSG",
272 __func__, &sg);
273 return 0;
274 }
275 pim_upstream_keep_alive_timer_start(
276 up, pim_ifp->pim->keep_alive_time);
277 pim_upstream_inherited_olist(pim_ifp->pim, up);
278 pim_upstream_update_join_desired(pim_ifp->pim, up);
279
280 if (PIM_DEBUG_MROUTE)
281 zlog_debug("%s: Creating %s upstream on LHR",
282 __func__, up->sg_str);
283 return 0;
284 }
285 if (PIM_DEBUG_MROUTE_DETAIL) {
286 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%pSG",
287 __func__, &sg);
288 }
289 return 0;
290 }
291
292 if (!up->rpf.source_nexthop.interface) {
293 if (PIM_DEBUG_PIM_TRACE)
294 zlog_debug("%s: up %s RPF is not present", __func__,
295 up->sg_str);
296 return 0;
297 }
298
299 pim_ifp = up->rpf.source_nexthop.interface->info;
300
301 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
302
303 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
304 || (!(PIM_I_am_DR(pim_ifp)))) {
305 if (PIM_DEBUG_MROUTE) {
306 zlog_debug("%s: Failed Check send packet", __func__);
307 }
308 return 0;
309 }
310
311 /*
312 * If we've received a register suppress
313 */
314 if (!up->t_rs_timer) {
315 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
316 if (PIM_DEBUG_PIM_REG)
317 zlog_debug("%pSG register forward skipped as group is SSM",
318 &sg);
319 return 0;
320 }
321
322 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
323 if (PIM_DEBUG_PIM_REG)
324 zlog_debug(
325 "%s register forward skipped, not FHR",
326 up->sg_str);
327 return 0;
328 }
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
337 static 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 pim_sgaddr sg;
343
344 memset(&sg, 0, sizeof(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("%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
362 __func__, &sg, msg->im_vif);
363 return -1;
364 }
365
366 pim_ifp = ifp->info;
367 if (!pim_ifp) {
368 if (PIM_DEBUG_MROUTE)
369 zlog_debug("%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
370 __func__, &sg, ifp->name);
371 return -2;
372 }
373
374 ch = pim_ifchannel_find(ifp, &sg);
375 if (!ch) {
376 pim_sgaddr star_g = sg;
377 if (PIM_DEBUG_MROUTE)
378 zlog_debug("%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
379 __func__, &sg, ifp->name);
380
381 star_g.src = PIMADDR_ANY;
382 ch = pim_ifchannel_find(ifp, &star_g);
383 if (!ch) {
384 if (PIM_DEBUG_MROUTE)
385 zlog_debug("%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
386 __func__, &star_g,
387 ifp->name);
388 return -3;
389 }
390 }
391
392 /*
393 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
394
395 Transitions from NoInfo State
396
397 An (S,G) data packet arrives on interface I, AND
398 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
399 downstream interface that is in our (S,G) outgoing interface
400 list. We optimistically assume that we will be the assert
401 winner for this (S,G), and so we transition to the "I am Assert
402 Winner" state and perform Actions A1 (below), which will
403 initiate the assert negotiation for (S,G).
404 */
405
406 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
407 if (PIM_DEBUG_MROUTE) {
408 zlog_debug(
409 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
410 __func__, ch->sg_str, ifp->name);
411 }
412 return -4;
413 }
414
415 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
416 if (PIM_DEBUG_MROUTE) {
417 zlog_debug(
418 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
419 __func__, ch->sg_str, ifp->name);
420 }
421 return -5;
422 }
423
424 if (assert_action_a1(ch)) {
425 if (PIM_DEBUG_MROUTE) {
426 zlog_debug(
427 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
428 __func__, ch->sg_str, ifp->name);
429 }
430 return -6;
431 }
432
433 return 0;
434 }
435
436 static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
437 const char *buf)
438 {
439 const struct ip *ip_hdr = (const struct ip *)buf;
440 struct pim_interface *pim_ifp;
441 struct pim_instance *pim;
442 struct pim_ifchannel *ch;
443 struct pim_upstream *up;
444 pim_sgaddr star_g;
445 pim_sgaddr sg;
446
447 pim_ifp = ifp->info;
448
449 memset(&sg, 0, sizeof(sg));
450 sg.src = ip_hdr->ip_src;
451 sg.grp = ip_hdr->ip_dst;
452
453 ch = pim_ifchannel_find(ifp, &sg);
454 if (ch) {
455 if (PIM_DEBUG_MROUTE)
456 zlog_debug(
457 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
458 ch->sg_str, ifp->name);
459 return -1;
460 }
461
462 star_g = sg;
463 star_g.src = PIMADDR_ANY;
464
465 pim = pim_ifp->pim;
466 /*
467 * If the incoming interface is the pimreg, then
468 * we know the callback is associated with a pim register
469 * packet and there is nothing to do here as that
470 * normal pim processing will see the packet and allow
471 * us to do the right thing.
472 */
473 if (ifp == pim->regiface) {
474 return 0;
475 }
476
477 up = pim_upstream_find(pim_ifp->pim, &sg);
478 if (up) {
479 struct pim_upstream *parent;
480 struct pim_nexthop source;
481 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
482
483 /* No RPF or No RPF interface or No mcast on RPF interface */
484 if (!rpf || !rpf->source_nexthop.interface
485 || !rpf->source_nexthop.interface->info)
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 */
494 parent = pim_upstream_find(pim_ifp->pim, &star_g);
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 /*
507 * No if channel, but upstream we are at the RP.
508 *
509 * This could be a anycast RP too and we may
510 * not have received a register packet from
511 * the source here at all. So gracefully
512 * bow out of doing a nexthop lookup and
513 * setting the SPTBIT to true
514 */
515 if (up->upstream_register.s_addr != INADDR_ANY &&
516 pim_nexthop_lookup(pim_ifp->pim, &source,
517 up->upstream_register, 0)) {
518 pim_register_stop_send(source.interface, &sg,
519 pim_ifp->primary_address,
520 up->upstream_register);
521 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
522 }
523
524 pim_upstream_inherited_olist(pim_ifp->pim, up);
525 if (!up->channel_oil->installed)
526 pim_upstream_mroute_add(up->channel_oil,
527 __func__);
528 } else {
529 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
530 if (pim_nexthop_lookup(pim_ifp->pim, &source,
531 up->upstream_register,
532 0))
533 pim_register_stop_send(
534 source.interface, &sg,
535 pim_ifp->primary_address,
536 up->upstream_register);
537 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
538 }
539 pim_upstream_keep_alive_timer_start(
540 up, pim_ifp->pim->keep_alive_time);
541 pim_upstream_inherited_olist(pim_ifp->pim, up);
542 pim_mroute_msg_wholepkt(fd, ifp, buf);
543 }
544 return 0;
545 }
546
547 pim_ifp = ifp->info;
548 if (pim_if_connected_to_source(ifp, sg.src)) {
549 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
550 PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
551 NULL);
552 if (!up) {
553 if (PIM_DEBUG_MROUTE)
554 zlog_debug("%pSG: WRONGVIF%s unable to create upstream on interface",
555 &sg, ifp->name);
556 return -2;
557 }
558 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
559 pim_upstream_keep_alive_timer_start(
560 up, pim_ifp->pim->keep_alive_time);
561 up->channel_oil->cc.pktcnt++;
562 pim_register_join(up);
563 pim_upstream_inherited_olist(pim_ifp->pim, up);
564 if (!up->channel_oil->installed)
565 pim_upstream_mroute_add(up->channel_oil, __func__);
566
567 // Send the packet to the RP
568 pim_mroute_msg_wholepkt(fd, ifp, buf);
569 } else {
570 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
571 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
572 __func__, NULL);
573 if (!up->channel_oil->installed)
574 pim_upstream_mroute_add(up->channel_oil, __func__);
575 }
576
577 return 0;
578 }
579
580 static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
581 int buf_size, ifindex_t ifindex)
582 {
583 struct interface *ifp;
584 const struct ip *ip_hdr;
585 const struct igmpmsg *msg;
586
587 if (buf_size < (int)sizeof(struct ip))
588 return 0;
589
590 ip_hdr = (const struct ip *)buf;
591
592 if (ip_hdr->ip_p == IPPROTO_IGMP) {
593 #if PIM_IPV == 4
594 struct pim_interface *pim_ifp;
595 struct in_addr ifaddr;
596 struct gm_sock *igmp;
597 const struct prefix *connected_src;
598
599 /* We have the IP packet but we do not know which interface this
600 * packet was
601 * received on. Find the interface that is on the same subnet as
602 * the source
603 * of the IP packet.
604 */
605 ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
606
607 if (!ifp || !ifp->info)
608 return 0;
609
610 connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src);
611
612 if (!connected_src) {
613 if (PIM_DEBUG_IGMP_PACKETS) {
614 zlog_debug("Recv IGMP packet on interface: %s from a non-connected source: %pI4",
615 ifp->name, &ip_hdr->ip_src);
616 }
617 return 0;
618 }
619
620 pim_ifp = ifp->info;
621 ifaddr = connected_src->u.prefix4;
622 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
623 ifaddr);
624
625 if (PIM_DEBUG_IGMP_PACKETS) {
626 zlog_debug(
627 "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
628 __func__, pim->vrf->name, ifp->name, igmp,
629 &ip_hdr->ip_src, &ip_hdr->ip_dst);
630 }
631 if (igmp)
632 pim_igmp_packet(igmp, (char *)buf, buf_size);
633 else if (PIM_DEBUG_IGMP_PACKETS) {
634 zlog_debug("No IGMP socket on interface: %s with connected source: %pFX",
635 ifp->name, connected_src);
636 }
637 #endif
638 } else if (ip_hdr->ip_p) {
639 if (PIM_DEBUG_MROUTE_DETAIL) {
640 zlog_debug(
641 "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%d",
642 __func__, ip_hdr->ip_p, &ip_hdr->ip_src, &ip_hdr->ip_dst,
643 buf_size);
644 }
645
646 } else {
647 msg = (const struct igmpmsg *)buf;
648
649 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
650
651 if (!ifp)
652 return 0;
653 if (PIM_DEBUG_MROUTE) {
654 zlog_debug(
655 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d size=%d",
656 __func__, igmpmsgtype2str[msg->im_msgtype],
657 msg->im_msgtype, ip_hdr->ip_p,
658 pim->mroute_socket, &msg->im_src, &msg->im_dst, ifp->name,
659 msg->im_vif, buf_size);
660 }
661
662 switch (msg->im_msgtype) {
663 case IGMPMSG_WRONGVIF:
664 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
665 msg);
666 case IGMPMSG_NOCACHE:
667 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
668 msg);
669 case IGMPMSG_WHOLEPKT:
670 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
671 (const char *)msg);
672 case IGMPMSG_WRVIFWHOLE:
673 return pim_mroute_msg_wrvifwhole(
674 pim->mroute_socket, ifp, (const char *)msg);
675 default:
676 break;
677 }
678 }
679
680 return 0;
681 }
682 #else /* PIM_IPV != 4 */
683
684 static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
685 int buf_size, ifindex_t ifindex)
686 {
687 return 0;
688 }
689 #endif /* PIM_IPV != 4 */
690
691 static int mroute_read(struct thread *t)
692 {
693 struct pim_instance *pim;
694 static long long count;
695 char buf[10000];
696 int result = 0;
697 int cont = 1;
698 int rd;
699 ifindex_t ifindex;
700 pim = THREAD_ARG(t);
701
702 while (cont) {
703 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
704 sizeof(buf), NULL, NULL, NULL, NULL,
705 &ifindex);
706 if (rd <= 0) {
707 if (errno == EINTR)
708 continue;
709 if (errno == EWOULDBLOCK || errno == EAGAIN)
710 break;
711
712 zlog_warn(
713 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
714 __func__, rd, pim->mroute_socket, errno,
715 safe_strerror(errno));
716 goto done;
717 }
718
719 result = pim_mroute_msg(pim, buf, rd, ifindex);
720
721 count++;
722 if (count % router->packet_process == 0)
723 cont = 0;
724 }
725 /* Keep reading */
726 done:
727 mroute_read_on(pim);
728
729 return result;
730 }
731
732 static void mroute_read_on(struct pim_instance *pim)
733 {
734 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
735 &pim->thread);
736 }
737
738 static void mroute_read_off(struct pim_instance *pim)
739 {
740 THREAD_OFF(pim->thread);
741 }
742
743 int pim_mroute_socket_enable(struct pim_instance *pim)
744 {
745 int fd;
746
747 frr_with_privs(&pimd_privs) {
748
749 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
750
751 if (fd < 0) {
752 zlog_warn("Could not create mroute socket: errno=%d: %s",
753 errno,
754 safe_strerror(errno));
755 return -2;
756 }
757
758 #ifdef SO_BINDTODEVICE
759 if (pim->vrf->vrf_id != VRF_DEFAULT
760 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
761 pim->vrf->name, strlen(pim->vrf->name))) {
762 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
763 safe_strerror(errno));
764 close(fd);
765 return -3;
766 }
767 #endif
768
769 }
770
771 pim->mroute_socket = fd;
772 if (pim_mroute_set(pim, 1)) {
773 zlog_warn(
774 "Could not enable mroute on socket fd=%d: errno=%d: %s",
775 fd, errno, safe_strerror(errno));
776 close(fd);
777 pim->mroute_socket = -1;
778 return -3;
779 }
780
781 pim->mroute_socket_creation = pim_time_monotonic_sec();
782
783 mroute_read_on(pim);
784
785 return 0;
786 }
787
788 int pim_mroute_socket_disable(struct pim_instance *pim)
789 {
790 if (pim_mroute_set(pim, 0)) {
791 zlog_warn(
792 "Could not disable mroute on socket fd=%d: errno=%d: %s",
793 pim->mroute_socket, errno, safe_strerror(errno));
794 return -2;
795 }
796
797 if (close(pim->mroute_socket)) {
798 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
799 pim->mroute_socket, errno, safe_strerror(errno));
800 return -3;
801 }
802
803 mroute_read_off(pim);
804 pim->mroute_socket = -1;
805
806 return 0;
807 }
808
809 /*
810 For each network interface (e.g., physical or a virtual tunnel) that
811 would be used for multicast forwarding, a corresponding multicast
812 interface must be added to the kernel.
813 */
814 int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
815 unsigned char flags)
816 {
817 struct pim_interface *pim_ifp = ifp->info;
818 struct vifctl vc;
819 int err;
820
821 if (PIM_DEBUG_MROUTE)
822 zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
823 pim_ifp->mroute_vif_index, ifp->name,
824 pim_ifp->pim->vrf->name);
825
826 memset(&vc, 0, sizeof(vc));
827 vc.vifc_vifi = pim_ifp->mroute_vif_index;
828 #ifdef VIFF_USE_IFINDEX
829 vc.vifc_lcl_ifindex = ifp->ifindex;
830 #else
831 if (ifaddr.s_addr == INADDR_ANY) {
832 zlog_warn(
833 "%s: unnumbered interfaces are not supported on this platform",
834 __func__);
835 return -1;
836 }
837 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
838 #endif
839 vc.vifc_flags = flags;
840 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
841 vc.vifc_rate_limit = 0;
842
843 #ifdef PIM_DVMRP_TUNNEL
844 if (vc.vifc_flags & VIFF_TUNNEL) {
845 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
846 sizeof(vc.vifc_rmt_addr));
847 }
848 #endif
849
850 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
851 (void *)&vc, sizeof(vc));
852 if (err) {
853 zlog_warn(
854 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
855 __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
856 &ifaddr, flags, errno, safe_strerror(errno));
857 return -2;
858 }
859
860 return 0;
861 }
862
863 int pim_mroute_del_vif(struct interface *ifp)
864 {
865 struct pim_interface *pim_ifp = ifp->info;
866 struct vifctl vc;
867 int err;
868
869 if (PIM_DEBUG_MROUTE)
870 zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
871 pim_ifp->mroute_vif_index, ifp->name,
872 pim_ifp->pim->vrf->name);
873
874 memset(&vc, 0, sizeof(vc));
875 vc.vifc_vifi = pim_ifp->mroute_vif_index;
876
877 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
878 (void *)&vc, sizeof(vc));
879 if (err) {
880 zlog_warn(
881 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
882 __FILE__, __func__, pim_ifp->pim->mroute_socket,
883 pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
884 return -2;
885 }
886
887 return 0;
888 }
889
890 /*
891 * Prevent creating MFC entry with OIF=IIF.
892 *
893 * This is a protection against implementation mistakes.
894 *
895 * PIM protocol implicitely ensures loopfree multicast topology.
896 *
897 * IGMP must be protected against adding looped MFC entries created
898 * by both source and receiver attached to the same interface. See
899 * TODO T22.
900 * We shall allow igmp to create upstream when it is DR for the intf.
901 * Assume RP reachable via non DR.
902 */
903 bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
904 int oif_index)
905 {
906 #ifdef PIM_ENFORCE_LOOPFREE_MFC
907 struct interface *ifp_out;
908 struct pim_interface *pim_ifp;
909
910 if (c_oil->up &&
911 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
912 return true;
913
914 ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
915 if (!ifp_out)
916 return false;
917 pim_ifp = ifp_out->info;
918 if (!pim_ifp)
919 return false;
920 if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_IGMP) &&
921 PIM_I_am_DR(pim_ifp))
922 return true;
923
924 return false;
925 #else
926 return true;
927 #endif
928 }
929
930 static inline void pim_mroute_copy(struct channel_oil *out,
931 struct channel_oil *in)
932 {
933 int i;
934
935 *oil_origin(out) = *oil_origin(in);
936 *oil_mcastgrp(out) = *oil_mcastgrp(in);
937 *oil_parent(out) = *oil_parent(in);
938
939 for (i = 0; i < MAXVIFS; ++i) {
940 if (*oil_parent(out) == i &&
941 !pim_mroute_allow_iif_in_oil(in, i)) {
942 oil_if_set(out, i, 0);
943 continue;
944 }
945
946 if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
947 oil_if_set(out, i, 0);
948 else
949 oil_if_set(out, i, oil_if_has(in, i));
950 }
951 }
952
953 /* This function must not be called directly 0
954 * use pim_upstream_mroute_add or pim_static_mroute_add instead
955 */
956 static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
957 {
958 struct pim_instance *pim = c_oil->pim;
959 struct channel_oil tmp_oil[1] = { };
960 int err;
961
962 pim->mroute_add_last = pim_time_monotonic_sec();
963 ++pim->mroute_add_events;
964
965 /* Copy the oil to a temporary structure to fixup (without need to
966 * later restore) before sending the mroute add to the dataplane
967 */
968 pim_mroute_copy(tmp_oil, c_oil);
969
970 /* The linux kernel *expects* the incoming
971 * vif to be part of the outgoing list
972 * in the case of a (*,G).
973 */
974 if (pim_addr_is_any(*oil_origin(c_oil))) {
975 oil_if_set(tmp_oil, *oil_parent(c_oil), 1);
976 }
977
978 /*
979 * If we have an unresolved cache entry for the S,G
980 * it is owned by the pimreg for the incoming IIF
981 * So set pimreg as the IIF temporarily to cause
982 * the packets to be forwarded. Then set it
983 * to the correct IIF afterwords.
984 */
985 if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil))
986 && *oil_parent(c_oil) != 0) {
987 *oil_parent(tmp_oil) = 0;
988 }
989 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
990 &tmp_oil->oil, sizeof(tmp_oil->oil));
991
992 if (!err && !c_oil->installed
993 && !pim_addr_is_any(*oil_origin(c_oil))
994 && *oil_parent(c_oil) != 0) {
995 *oil_parent(tmp_oil) = *oil_parent(c_oil);
996 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
997 &tmp_oil->oil, sizeof(tmp_oil->oil));
998 }
999
1000 if (err) {
1001 zlog_warn(
1002 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
1003 __FILE__, __func__, pim->mroute_socket, errno,
1004 safe_strerror(errno));
1005 return -2;
1006 }
1007
1008 if (PIM_DEBUG_MROUTE) {
1009 char buf[1000];
1010 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
1011 pim->vrf->name,
1012 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1013 }
1014
1015 if (!c_oil->installed) {
1016 c_oil->installed = 1;
1017 c_oil->mroute_creation = pim_time_monotonic_sec();
1018 }
1019
1020 return 0;
1021 }
1022
1023 static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
1024 const char *name)
1025 {
1026 vifi_t iif = MAXVIFS;
1027 struct interface *ifp = NULL;
1028 struct pim_interface *pim_ifp;
1029 struct pim_upstream *up = c_oil->up;
1030
1031 if (up) {
1032 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
1033 if (up->parent)
1034 ifp = up->parent->rpf.source_nexthop.interface;
1035 } else {
1036 ifp = up->rpf.source_nexthop.interface;
1037 }
1038 if (ifp) {
1039 pim_ifp = (struct pim_interface *)ifp->info;
1040 if (pim_ifp)
1041 iif = pim_ifp->mroute_vif_index;
1042 }
1043 }
1044 return iif;
1045 }
1046
1047 static int pim_upstream_mroute_update(struct channel_oil *c_oil,
1048 const char *name)
1049 {
1050 char buf[1000];
1051
1052 if (*oil_parent(c_oil) >= MAXVIFS) {
1053 /* the c_oil cannot be installed as a mroute yet */
1054 if (PIM_DEBUG_MROUTE)
1055 zlog_debug(
1056 "%s(%s) %s mroute not ready to be installed; %s",
1057 __func__, name,
1058 pim_channel_oil_dump(c_oil, buf,
1059 sizeof(buf)),
1060 c_oil->installed ?
1061 "uninstall" : "skip");
1062 /* if already installed flush it out as we are going to stop
1063 * updates to it leaving it in a stale state
1064 */
1065 if (c_oil->installed)
1066 pim_mroute_del(c_oil, name);
1067 /* return success (skipped) */
1068 return 0;
1069 }
1070
1071 return pim_mroute_add(c_oil, name);
1072 }
1073
1074 /* IIF associated with SGrpt entries are re-evaluated when the parent
1075 * (*,G) entries IIF changes
1076 */
1077 static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
1078 {
1079 struct listnode *listnode;
1080 struct pim_upstream *child;
1081
1082 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
1083 child)) {
1084 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
1085 pim_upstream_mroute_iif_update(child->channel_oil,
1086 __func__);
1087 }
1088 }
1089
1090 /* In the case of "PIM state machine" added mroutes an upstream entry
1091 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1092 */
1093 int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
1094 {
1095 vifi_t iif;
1096
1097 iif = pim_upstream_get_mroute_iif(c_oil, name);
1098
1099 if (*oil_parent(c_oil) != iif) {
1100 *oil_parent(c_oil) = iif;
1101 if (pim_addr_is_any(*oil_origin(c_oil)) &&
1102 c_oil->up)
1103 pim_upstream_all_sources_iif_update(c_oil->up);
1104 } else {
1105 *oil_parent(c_oil) = iif;
1106 }
1107
1108 return pim_upstream_mroute_update(c_oil, name);
1109 }
1110
1111 /* Look for IIF changes and update the dateplane entry only if the IIF
1112 * has changed.
1113 */
1114 int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
1115 {
1116 vifi_t iif;
1117 char buf[1000];
1118
1119 iif = pim_upstream_get_mroute_iif(c_oil, name);
1120 if (*oil_parent(c_oil) == iif) {
1121 /* no change */
1122 return 0;
1123 }
1124 *oil_parent(c_oil) = iif;
1125
1126 if (pim_addr_is_any(*oil_origin(c_oil)) &&
1127 c_oil->up)
1128 pim_upstream_all_sources_iif_update(c_oil->up);
1129
1130 if (PIM_DEBUG_MROUTE_DETAIL)
1131 zlog_debug("%s(%s) %s mroute iif update %d",
1132 __func__, name,
1133 pim_channel_oil_dump(c_oil, buf,
1134 sizeof(buf)), iif);
1135 /* XXX: is this hack needed? */
1136 c_oil->oil_inherited_rescan = 1;
1137 return pim_upstream_mroute_update(c_oil, name);
1138 }
1139
1140 int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
1141 {
1142 return pim_mroute_add(c_oil, name);
1143 }
1144
1145 void pim_static_mroute_iif_update(struct channel_oil *c_oil,
1146 int input_vif_index,
1147 const char *name)
1148 {
1149 if (*oil_parent(c_oil) == input_vif_index)
1150 return;
1151
1152 *oil_parent(c_oil) = input_vif_index;
1153 if (input_vif_index == MAXVIFS)
1154 pim_mroute_del(c_oil, name);
1155 else
1156 pim_static_mroute_add(c_oil, name);
1157 }
1158
1159 int pim_mroute_del(struct channel_oil *c_oil, const char *name)
1160 {
1161 struct pim_instance *pim = c_oil->pim;
1162 int err;
1163
1164 pim->mroute_del_last = pim_time_monotonic_sec();
1165 ++pim->mroute_del_events;
1166
1167 if (!c_oil->installed) {
1168 if (PIM_DEBUG_MROUTE) {
1169 char buf[1000];
1170 zlog_debug(
1171 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1172 __FILE__, __func__, *oil_parent(c_oil),
1173 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1174 }
1175 return -2;
1176 }
1177
1178 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
1179 &c_oil->oil, sizeof(c_oil->oil));
1180 if (err) {
1181 if (PIM_DEBUG_MROUTE)
1182 zlog_warn(
1183 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
1184 __FILE__, __func__, pim->mroute_socket, errno,
1185 safe_strerror(errno));
1186 return -2;
1187 }
1188
1189 if (PIM_DEBUG_MROUTE) {
1190 char buf[1000];
1191 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
1192 pim->vrf->name,
1193 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1194 }
1195
1196 // Reset kernel installed flag
1197 c_oil->installed = 0;
1198
1199 return 0;
1200 }
1201
1202 void pim_mroute_update_counters(struct channel_oil *c_oil)
1203 {
1204 struct pim_instance *pim = c_oil->pim;
1205
1206 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1207 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1208 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1209
1210 if (!c_oil->installed) {
1211 c_oil->cc.lastused = 100 * pim->keep_alive_time;
1212 if (PIM_DEBUG_MROUTE) {
1213 pim_sgaddr sg;
1214
1215 sg.src = *oil_origin(c_oil);
1216 sg.grp = *oil_mcastgrp(c_oil);
1217 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1218 &sg);
1219 }
1220 return;
1221 }
1222
1223 #if PIM_IPV == 4
1224 struct sioc_sg_req sgreq;
1225
1226 memset(&sgreq, 0, sizeof(sgreq));
1227 sgreq.src = *oil_origin(c_oil);
1228 sgreq.grp = *oil_mcastgrp(c_oil);
1229
1230 pim_zlookup_sg_statistics(c_oil);
1231 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
1232 pim_sgaddr sg;
1233
1234 sg.src = *oil_origin(c_oil);
1235 sg.grp = *oil_mcastgrp(c_oil);
1236
1237 zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1238 (unsigned long)SIOCGETSGCNT, &sg,
1239 errno, safe_strerror(errno));
1240 return;
1241 }
1242
1243 c_oil->cc.pktcnt = sgreq.pktcnt;
1244 c_oil->cc.bytecnt = sgreq.bytecnt;
1245 c_oil->cc.wrong_if = sgreq.wrong_if;
1246 #endif
1247 return;
1248 }