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