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