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