]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_mroute.c
Merge pull request #10875 from anlancs/doc-mh-esi-1
[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 }
441 pim_upstream_keep_alive_timer_start(
442 up, pim_ifp->pim->keep_alive_time);
443 pim_upstream_inherited_olist(pim_ifp->pim, up);
444 pim_mroute_msg_wholepkt(fd, ifp, buf);
445 }
446 return 0;
447 }
448
449 pim_ifp = ifp->info;
450 if (pim_if_connected_to_source(ifp, sg.src)) {
451 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
452 PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
453 NULL);
454 if (!up) {
455 if (PIM_DEBUG_MROUTE)
456 zlog_debug(
457 "%pSG: WRONGVIF%s unable to create upstream on interface",
458 &sg, ifp->name);
459 return -2;
460 }
461 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
462 pim_upstream_keep_alive_timer_start(
463 up, pim_ifp->pim->keep_alive_time);
464 up->channel_oil->cc.pktcnt++;
465 pim_register_join(up);
466 pim_upstream_inherited_olist(pim_ifp->pim, up);
467 if (!up->channel_oil->installed)
468 pim_upstream_mroute_add(up->channel_oil, __func__);
469
470 // Send the packet to the RP
471 pim_mroute_msg_wholepkt(fd, ifp, buf);
472 } else {
473 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
474 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
475 __func__, NULL);
476 if (!up->channel_oil->installed)
477 pim_upstream_mroute_add(up->channel_oil, __func__);
478 }
479
480 return 0;
481 }
482
483 static void mroute_read(struct thread *t)
484 {
485 struct pim_instance *pim;
486 static long long count;
487 char buf[10000];
488 int cont = 1;
489 int rd;
490 ifindex_t ifindex;
491 pim = THREAD_ARG(t);
492
493 while (cont) {
494 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
495 sizeof(buf), NULL, NULL, NULL, NULL,
496 &ifindex);
497 if (rd <= 0) {
498 if (errno == EINTR)
499 continue;
500 if (errno == EWOULDBLOCK || errno == EAGAIN)
501 break;
502
503 zlog_warn(
504 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
505 __func__, rd, pim->mroute_socket, errno,
506 safe_strerror(errno));
507 goto done;
508 }
509
510 pim_mroute_msg(pim, buf, rd, ifindex);
511
512 count++;
513 if (count % router->packet_process == 0)
514 cont = 0;
515 }
516 /* Keep reading */
517 done:
518 mroute_read_on(pim);
519
520 return;
521 }
522
523 static void mroute_read_on(struct pim_instance *pim)
524 {
525 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
526 &pim->thread);
527 }
528
529 static void mroute_read_off(struct pim_instance *pim)
530 {
531 THREAD_OFF(pim->thread);
532 }
533
534 int pim_mroute_socket_enable(struct pim_instance *pim)
535 {
536 int fd;
537
538 frr_with_privs(&pimd_privs) {
539
540 #if PIM_IPV == 4
541 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
542 #else
543 fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
544 #endif
545 if (fd < 0) {
546 zlog_warn("Could not create mroute socket: errno=%d: %s",
547 errno,
548 safe_strerror(errno));
549 return -2;
550 }
551
552 #ifdef SO_BINDTODEVICE
553 if (pim->vrf->vrf_id != VRF_DEFAULT
554 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
555 pim->vrf->name, strlen(pim->vrf->name))) {
556 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
557 safe_strerror(errno));
558 close(fd);
559 return -3;
560 }
561 #endif
562
563 }
564
565 pim->mroute_socket = fd;
566 if (pim_mroute_set(pim, 1)) {
567 zlog_warn(
568 "Could not enable mroute on socket fd=%d: errno=%d: %s",
569 fd, errno, safe_strerror(errno));
570 close(fd);
571 pim->mroute_socket = -1;
572 return -3;
573 }
574
575 pim->mroute_socket_creation = pim_time_monotonic_sec();
576
577 mroute_read_on(pim);
578
579 return 0;
580 }
581
582 int pim_mroute_socket_disable(struct pim_instance *pim)
583 {
584 if (pim_mroute_set(pim, 0)) {
585 zlog_warn(
586 "Could not disable mroute on socket fd=%d: errno=%d: %s",
587 pim->mroute_socket, errno, safe_strerror(errno));
588 return -2;
589 }
590
591 if (close(pim->mroute_socket)) {
592 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
593 pim->mroute_socket, errno, safe_strerror(errno));
594 return -3;
595 }
596
597 mroute_read_off(pim);
598 pim->mroute_socket = -1;
599
600 return 0;
601 }
602
603 /*
604 For each network interface (e.g., physical or a virtual tunnel) that
605 would be used for multicast forwarding, a corresponding multicast
606 interface must be added to the kernel.
607 */
608 int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
609 unsigned char flags)
610 {
611 struct pim_interface *pim_ifp = ifp->info;
612 pim_vifctl vc;
613 int err;
614
615 if (PIM_DEBUG_MROUTE)
616 zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
617 pim_ifp->mroute_vif_index, ifp->name,
618 pim_ifp->pim->vrf->name);
619
620 memset(&vc, 0, sizeof(vc));
621 vc.vc_vifi = pim_ifp->mroute_vif_index;
622 #if PIM_IPV == 4
623 #ifdef VIFF_USE_IFINDEX
624 vc.vc_lcl_ifindex = ifp->ifindex;
625 #else
626 if (ifaddr.s_addr == INADDR_ANY) {
627 zlog_warn(
628 "%s: unnumbered interfaces are not supported on this platform",
629 __func__);
630 return -1;
631 }
632 memcpy(&vc.vc_lcl_addr, &ifaddr, sizeof(vc.vc_lcl_addr));
633 #endif
634 #else
635 vc.vc_pifi = ifp->ifindex;
636 #endif
637 vc.vc_flags = flags;
638 vc.vc_threshold = PIM_MROUTE_MIN_TTL;
639 vc.vc_rate_limit = 0;
640
641 #if PIM_IPV == 4
642 #ifdef PIM_DVMRP_TUNNEL
643 if (vc.vc_flags & VIFF_TUNNEL) {
644 memcpy(&vc.vc_rmt_addr, &vif_remote_addr,
645 sizeof(vc.vc_rmt_addr));
646 }
647 #endif
648 #endif
649
650 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
651 (void *)&vc, sizeof(vc));
652 if (err) {
653 zlog_warn(
654 "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
655 __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
656 &ifaddr, flags, errno, safe_strerror(errno));
657 return -2;
658 }
659
660 return 0;
661 }
662
663 int pim_mroute_del_vif(struct interface *ifp)
664 {
665 struct pim_interface *pim_ifp = ifp->info;
666 pim_vifctl vc;
667 int err;
668
669 if (PIM_DEBUG_MROUTE)
670 zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
671 pim_ifp->mroute_vif_index, ifp->name,
672 pim_ifp->pim->vrf->name);
673
674 memset(&vc, 0, sizeof(vc));
675 vc.vc_vifi = pim_ifp->mroute_vif_index;
676
677 err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_DEL_VIF,
678 (void *)&vc, sizeof(vc));
679 if (err) {
680 zlog_warn(
681 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
682 __FILE__, __func__, pim_ifp->pim->mroute_socket,
683 pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
684 return -2;
685 }
686
687 return 0;
688 }
689
690 /*
691 * Prevent creating MFC entry with OIF=IIF.
692 *
693 * This is a protection against implementation mistakes.
694 *
695 * PIM protocol implicitely ensures loopfree multicast topology.
696 *
697 * IGMP must be protected against adding looped MFC entries created
698 * by both source and receiver attached to the same interface. See
699 * TODO T22.
700 * We shall allow igmp to create upstream when it is DR for the intf.
701 * Assume RP reachable via non DR.
702 */
703 bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
704 int oif_index)
705 {
706 #ifdef PIM_ENFORCE_LOOPFREE_MFC
707 struct interface *ifp_out;
708 struct pim_interface *pim_ifp;
709
710 if (c_oil->up &&
711 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
712 return true;
713
714 ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
715 if (!ifp_out)
716 return false;
717 pim_ifp = ifp_out->info;
718 if (!pim_ifp)
719 return false;
720 if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_IGMP) &&
721 PIM_I_am_DR(pim_ifp))
722 return true;
723
724 return false;
725 #else
726 return true;
727 #endif
728 }
729
730 static inline void pim_mroute_copy(struct channel_oil *out,
731 struct channel_oil *in)
732 {
733 int i;
734
735 *oil_origin(out) = *oil_origin(in);
736 *oil_mcastgrp(out) = *oil_mcastgrp(in);
737 *oil_parent(out) = *oil_parent(in);
738
739 for (i = 0; i < MAXVIFS; ++i) {
740 if (*oil_parent(out) == i &&
741 !pim_mroute_allow_iif_in_oil(in, i)) {
742 oil_if_set(out, i, 0);
743 continue;
744 }
745
746 if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
747 oil_if_set(out, i, 0);
748 else
749 oil_if_set(out, i, oil_if_has(in, i));
750 }
751 }
752
753 /* This function must not be called directly 0
754 * use pim_upstream_mroute_add or pim_static_mroute_add instead
755 */
756 static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
757 {
758 struct pim_instance *pim = c_oil->pim;
759 struct channel_oil tmp_oil[1] = { };
760 int err;
761
762 pim->mroute_add_last = pim_time_monotonic_sec();
763 ++pim->mroute_add_events;
764
765 /* Copy the oil to a temporary structure to fixup (without need to
766 * later restore) before sending the mroute add to the dataplane
767 */
768 pim_mroute_copy(tmp_oil, c_oil);
769
770 /* The linux kernel *expects* the incoming
771 * vif to be part of the outgoing list
772 * in the case of a (*,G).
773 */
774 if (pim_addr_is_any(*oil_origin(c_oil))) {
775 oil_if_set(tmp_oil, *oil_parent(c_oil), 1);
776 }
777
778 /*
779 * If we have an unresolved cache entry for the S,G
780 * it is owned by the pimreg for the incoming IIF
781 * So set pimreg as the IIF temporarily to cause
782 * the packets to be forwarded. Then set it
783 * to the correct IIF afterwords.
784 */
785 if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil))
786 && *oil_parent(c_oil) != 0) {
787 *oil_parent(tmp_oil) = 0;
788 }
789 /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
790 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
791 &tmp_oil->oil, sizeof(tmp_oil->oil));
792
793 if (!err && !c_oil->installed
794 && !pim_addr_is_any(*oil_origin(c_oil))
795 && *oil_parent(c_oil) != 0) {
796 *oil_parent(tmp_oil) = *oil_parent(c_oil);
797 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
798 &tmp_oil->oil, sizeof(tmp_oil->oil));
799 }
800
801 if (err) {
802 zlog_warn(
803 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
804 __FILE__, __func__, pim->mroute_socket, errno,
805 safe_strerror(errno));
806 return -2;
807 }
808
809 if (PIM_DEBUG_MROUTE) {
810 char buf[1000];
811 zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
812 pim->vrf->name,
813 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
814 }
815
816 if (!c_oil->installed) {
817 c_oil->installed = 1;
818 c_oil->mroute_creation = pim_time_monotonic_sec();
819 }
820
821 return 0;
822 }
823
824 static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
825 const char *name)
826 {
827 vifi_t iif = MAXVIFS;
828 struct interface *ifp = NULL;
829 struct pim_interface *pim_ifp;
830 struct pim_upstream *up = c_oil->up;
831
832 if (up) {
833 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
834 if (up->parent)
835 ifp = up->parent->rpf.source_nexthop.interface;
836 } else {
837 ifp = up->rpf.source_nexthop.interface;
838 }
839 if (ifp) {
840 pim_ifp = (struct pim_interface *)ifp->info;
841 if (pim_ifp)
842 iif = pim_ifp->mroute_vif_index;
843 }
844 }
845 return iif;
846 }
847
848 static int pim_upstream_mroute_update(struct channel_oil *c_oil,
849 const char *name)
850 {
851 char buf[1000];
852
853 if (*oil_parent(c_oil) >= MAXVIFS) {
854 /* the c_oil cannot be installed as a mroute yet */
855 if (PIM_DEBUG_MROUTE)
856 zlog_debug(
857 "%s(%s) %s mroute not ready to be installed; %s",
858 __func__, name,
859 pim_channel_oil_dump(c_oil, buf,
860 sizeof(buf)),
861 c_oil->installed ?
862 "uninstall" : "skip");
863 /* if already installed flush it out as we are going to stop
864 * updates to it leaving it in a stale state
865 */
866 if (c_oil->installed)
867 pim_mroute_del(c_oil, name);
868 /* return success (skipped) */
869 return 0;
870 }
871
872 return pim_mroute_add(c_oil, name);
873 }
874
875 /* IIF associated with SGrpt entries are re-evaluated when the parent
876 * (*,G) entries IIF changes
877 */
878 static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
879 {
880 struct listnode *listnode;
881 struct pim_upstream *child;
882
883 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
884 child)) {
885 if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
886 pim_upstream_mroute_iif_update(child->channel_oil,
887 __func__);
888 }
889 }
890
891 /* In the case of "PIM state machine" added mroutes an upstream entry
892 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
893 */
894 int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
895 {
896 vifi_t iif;
897
898 iif = pim_upstream_get_mroute_iif(c_oil, name);
899
900 if (*oil_parent(c_oil) != iif) {
901 *oil_parent(c_oil) = iif;
902 if (pim_addr_is_any(*oil_origin(c_oil)) &&
903 c_oil->up)
904 pim_upstream_all_sources_iif_update(c_oil->up);
905 } else {
906 *oil_parent(c_oil) = iif;
907 }
908
909 return pim_upstream_mroute_update(c_oil, name);
910 }
911
912 /* Look for IIF changes and update the dateplane entry only if the IIF
913 * has changed.
914 */
915 int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
916 {
917 vifi_t iif;
918 char buf[1000];
919
920 iif = pim_upstream_get_mroute_iif(c_oil, name);
921 if (*oil_parent(c_oil) == iif) {
922 /* no change */
923 return 0;
924 }
925 *oil_parent(c_oil) = iif;
926
927 if (pim_addr_is_any(*oil_origin(c_oil)) &&
928 c_oil->up)
929 pim_upstream_all_sources_iif_update(c_oil->up);
930
931 if (PIM_DEBUG_MROUTE_DETAIL)
932 zlog_debug("%s(%s) %s mroute iif update %d",
933 __func__, name,
934 pim_channel_oil_dump(c_oil, buf,
935 sizeof(buf)), iif);
936 /* XXX: is this hack needed? */
937 c_oil->oil_inherited_rescan = 1;
938 return pim_upstream_mroute_update(c_oil, name);
939 }
940
941 int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
942 {
943 return pim_mroute_add(c_oil, name);
944 }
945
946 void pim_static_mroute_iif_update(struct channel_oil *c_oil,
947 int input_vif_index,
948 const char *name)
949 {
950 if (*oil_parent(c_oil) == input_vif_index)
951 return;
952
953 *oil_parent(c_oil) = input_vif_index;
954 if (input_vif_index == MAXVIFS)
955 pim_mroute_del(c_oil, name);
956 else
957 pim_static_mroute_add(c_oil, name);
958 }
959
960 int pim_mroute_del(struct channel_oil *c_oil, const char *name)
961 {
962 struct pim_instance *pim = c_oil->pim;
963 int err;
964
965 pim->mroute_del_last = pim_time_monotonic_sec();
966 ++pim->mroute_del_events;
967
968 if (!c_oil->installed) {
969 if (PIM_DEBUG_MROUTE) {
970 char buf[1000];
971 zlog_debug(
972 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
973 __FILE__, __func__, *oil_parent(c_oil),
974 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
975 }
976 return -2;
977 }
978
979 err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_DEL_MFC,
980 &c_oil->oil, sizeof(c_oil->oil));
981 if (err) {
982 if (PIM_DEBUG_MROUTE)
983 zlog_warn(
984 "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
985 __FILE__, __func__, pim->mroute_socket, errno,
986 safe_strerror(errno));
987 return -2;
988 }
989
990 if (PIM_DEBUG_MROUTE) {
991 char buf[1000];
992 zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
993 pim->vrf->name,
994 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
995 }
996
997 // Reset kernel installed flag
998 c_oil->installed = 0;
999
1000 return 0;
1001 }
1002
1003 void pim_mroute_update_counters(struct channel_oil *c_oil)
1004 {
1005 struct pim_instance *pim = c_oil->pim;
1006 pim_sioc_sg_req sgreq;
1007
1008 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1009 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1010 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1011
1012 if (!c_oil->installed) {
1013 c_oil->cc.lastused = 100 * pim->keep_alive_time;
1014 if (PIM_DEBUG_MROUTE) {
1015 pim_sgaddr sg;
1016
1017 sg.src = *oil_origin(c_oil);
1018 sg.grp = *oil_mcastgrp(c_oil);
1019 zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1020 &sg);
1021 }
1022 return;
1023 }
1024
1025
1026 memset(&sgreq, 0, sizeof(sgreq));
1027
1028 #if PIM_IPV == 4
1029 sgreq.src = *oil_origin(c_oil);
1030 sgreq.grp = *oil_mcastgrp(c_oil);
1031 pim_zlookup_sg_statistics(c_oil);
1032 #else
1033 sgreq.src = c_oil->oil.mf6cc_origin;
1034 sgreq.grp = c_oil->oil.mf6cc_mcastgrp;
1035 /* TODO Zlookup_sg_statistics for V6 to be added */
1036 #endif
1037 if (ioctl(pim->mroute_socket, PIM_SIOCGETSGCNT, &sgreq)) {
1038 pim_sgaddr sg;
1039
1040 sg.src = *oil_origin(c_oil);
1041 sg.grp = *oil_mcastgrp(c_oil);
1042
1043 zlog_warn(
1044 "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1045 (unsigned long)PIM_SIOCGETSGCNT, &sg, errno,
1046 safe_strerror(errno));
1047 return;
1048 }
1049
1050 c_oil->cc.pktcnt = sgreq.pktcnt;
1051 c_oil->cc.bytecnt = sgreq.bytecnt;
1052 c_oil->cc.wrong_if = sgreq.wrong_if;
1053 return;
1054 }