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