]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_mroute.c
Merge pull request #4604 from opensourcerouting/mutex-sugar
[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 *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_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 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
232 // resolve mfcc_parent prior to mroute_add in channel_add_oif
233 if (up->rpf.source_nexthop.interface &&
234 up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
235 int vif_index = 0;
236 vif_index = pim_if_find_vifindex_by_ifindex(
237 pim_ifp->pim,
238 up->rpf.source_nexthop.interface->ifindex);
239 pim_channel_oil_change_iif(pim_ifp->pim, up->channel_oil,
240 vif_index, __PRETTY_FUNCTION__);
241 }
242 pim_register_join(up);
243
244 return 0;
245 }
246
247 static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
248 const char *buf)
249 {
250 struct pim_interface *pim_ifp;
251 struct prefix_sg sg;
252 struct pim_rpf *rpg;
253 const struct ip *ip_hdr;
254 struct pim_upstream *up;
255
256 pim_ifp = ifp->info;
257
258 ip_hdr = (const struct ip *)buf;
259
260 memset(&sg, 0, sizeof(struct prefix_sg));
261 sg.src = ip_hdr->ip_src;
262 sg.grp = ip_hdr->ip_dst;
263
264 up = pim_upstream_find(pim_ifp->pim, &sg);
265 if (!up) {
266 struct prefix_sg star = sg;
267 star.src.s_addr = INADDR_ANY;
268
269 up = pim_upstream_find(pim_ifp->pim, &star);
270
271 if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) {
272 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
273 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
274 __PRETTY_FUNCTION__, NULL);
275 if (!up) {
276 if (PIM_DEBUG_MROUTE)
277 zlog_debug(
278 "%s: Unable to create upstream information for %s",
279 __PRETTY_FUNCTION__,
280 pim_str_sg_dump(&sg));
281 return 0;
282 }
283 pim_upstream_keep_alive_timer_start(
284 up, pim_ifp->pim->keep_alive_time);
285 pim_upstream_inherited_olist(pim_ifp->pim, up);
286 pim_upstream_switch(pim_ifp->pim, up,
287 PIM_UPSTREAM_JOINED);
288
289 if (PIM_DEBUG_MROUTE)
290 zlog_debug("%s: Creating %s upstream on LHR",
291 __PRETTY_FUNCTION__, up->sg_str);
292 return 0;
293 }
294 if (PIM_DEBUG_MROUTE_DETAIL) {
295 zlog_debug(
296 "%s: Unable to find upstream channel WHOLEPKT%s",
297 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
298 }
299 return 0;
300 }
301
302 if (!up->rpf.source_nexthop.interface) {
303 if (PIM_DEBUG_TRACE)
304 zlog_debug("%s: up %s RPF is not present",
305 __PRETTY_FUNCTION__, up->sg_str);
306 return 0;
307 }
308
309 pim_ifp = up->rpf.source_nexthop.interface->info;
310
311 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
312
313 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
314 || (!(PIM_I_am_DR(pim_ifp)))) {
315 if (PIM_DEBUG_MROUTE) {
316 zlog_debug("%s: Failed Check send packet",
317 __PRETTY_FUNCTION__);
318 }
319 return 0;
320 }
321
322 /*
323 * If we've received a register suppress
324 */
325 if (!up->t_rs_timer) {
326 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
327 if (PIM_DEBUG_PIM_REG)
328 zlog_debug(
329 "%s register forward skipped as group is SSM",
330 pim_str_sg_dump(&sg));
331 return 0;
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 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
367 msg->im_vif);
368 return -1;
369 }
370
371 pim_ifp = ifp->info;
372 if (!pim_ifp) {
373 if (PIM_DEBUG_MROUTE)
374 zlog_debug(
375 "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
376 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
377 ifp->name);
378 return -2;
379 }
380
381 ch = pim_ifchannel_find(ifp, &sg);
382 if (!ch) {
383 struct prefix_sg star_g = sg;
384 if (PIM_DEBUG_MROUTE)
385 zlog_debug(
386 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
387 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
388 ifp->name);
389
390 star_g.src.s_addr = INADDR_ANY;
391 ch = pim_ifchannel_find(ifp, &star_g);
392 if (!ch) {
393 if (PIM_DEBUG_MROUTE)
394 zlog_debug(
395 "%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
396 __PRETTY_FUNCTION__,
397 pim_str_sg_dump(&star_g), ifp->name);
398 return -3;
399 }
400 }
401
402 /*
403 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
404
405 Transitions from NoInfo State
406
407 An (S,G) data packet arrives on interface I, AND
408 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
409 downstream interface that is in our (S,G) outgoing interface
410 list. We optimistically assume that we will be the assert
411 winner for this (S,G), and so we transition to the "I am Assert
412 Winner" state and perform Actions A1 (below), which will
413 initiate the assert negotiation for (S,G).
414 */
415
416 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
417 if (PIM_DEBUG_MROUTE) {
418 zlog_debug(
419 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
420 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
421 }
422 return -4;
423 }
424
425 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
426 if (PIM_DEBUG_MROUTE) {
427 zlog_debug(
428 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
429 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
430 }
431 return -5;
432 }
433
434 if (assert_action_a1(ch)) {
435 if (PIM_DEBUG_MROUTE) {
436 zlog_debug(
437 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
438 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
439 }
440 return -6;
441 }
442
443 return 0;
444 }
445
446 static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
447 const char *buf)
448 {
449 const struct ip *ip_hdr = (const struct ip *)buf;
450 struct pim_interface *pim_ifp;
451 struct pim_ifchannel *ch;
452 struct pim_upstream *up;
453 struct prefix_sg star_g;
454 struct prefix_sg sg;
455
456 pim_ifp = ifp->info;
457
458 memset(&sg, 0, sizeof(struct prefix_sg));
459 sg.src = ip_hdr->ip_src;
460 sg.grp = ip_hdr->ip_dst;
461
462 ch = pim_ifchannel_find(ifp, &sg);
463 if (ch) {
464 if (PIM_DEBUG_MROUTE)
465 zlog_debug(
466 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
467 ch->sg_str, ifp->name);
468 return -1;
469 }
470
471 star_g = sg;
472 star_g.src.s_addr = INADDR_ANY;
473 #if 0
474 ch = pim_ifchannel_find(ifp, &star_g);
475 if (ch)
476 {
477 if (PIM_DEBUG_MROUTE)
478 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
479 pim_str_sg_dump (&star_g), ifp->name);
480 return -1;
481 }
482 #endif
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 if (!rpf || !rpf->source_nexthop.interface)
490 return 0;
491
492 /*
493 * If we have received a WRVIFWHOLE and are at this
494 * point, we could be receiving the packet on the *,G
495 * tree, let's check and if so we can safely drop
496 * it.
497 */
498 parent = pim_upstream_find(pim_ifp->pim, &star_g);
499 if (parent && parent->rpf.source_nexthop.interface == ifp)
500 return 0;
501
502 pim_ifp = rpf->source_nexthop.interface->info;
503
504 memset(&source, 0, sizeof(source));
505 /*
506 * If we are the fhr that means we are getting a callback during
507 * the pimreg period, so I believe we can ignore this packet
508 */
509 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
510 // No if channel, but upstream we are at the RP.
511 if (pim_nexthop_lookup(pim_ifp->pim, &source,
512 up->upstream_register, 0)) {
513 pim_register_stop_send(source.interface, &sg,
514 pim_ifp->primary_address,
515 up->upstream_register);
516 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
517 }
518
519 pim_upstream_inherited_olist(pim_ifp->pim, up);
520 if (!up->channel_oil->installed)
521 pim_mroute_add(up->channel_oil,
522 __PRETTY_FUNCTION__);
523 } else {
524 if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
525 if (pim_nexthop_lookup(pim_ifp->pim, &source,
526 up->upstream_register,
527 0))
528 pim_register_stop_send(
529 source.interface, &sg,
530 pim_ifp->primary_address,
531 up->upstream_register);
532 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
533 }
534 pim_upstream_keep_alive_timer_start(
535 up, pim_ifp->pim->keep_alive_time);
536 pim_upstream_inherited_olist(pim_ifp->pim, up);
537 pim_mroute_msg_wholepkt(fd, ifp, buf);
538 }
539 return 0;
540 }
541
542 pim_ifp = ifp->info;
543 if (pim_if_connected_to_source(ifp, sg.src)) {
544 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
545 PIM_UPSTREAM_FLAG_MASK_FHR,
546 __PRETTY_FUNCTION__, NULL);
547 if (!up) {
548 if (PIM_DEBUG_MROUTE)
549 zlog_debug(
550 "%s: WRONGVIF%s unable to create upstream on interface",
551 pim_str_sg_dump(&sg), ifp->name);
552 return -2;
553 }
554 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
555 pim_upstream_keep_alive_timer_start(
556 up, pim_ifp->pim->keep_alive_time);
557 up->channel_oil->cc.pktcnt++;
558 pim_register_join(up);
559 pim_upstream_inherited_olist(pim_ifp->pim, up);
560
561 // Send the packet to the RP
562 pim_mroute_msg_wholepkt(fd, ifp, buf);
563 } else {
564 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
565 PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
566 __PRETTY_FUNCTION__, NULL);
567 if (!up->channel_oil->installed)
568 pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
569 }
570
571 return 0;
572 }
573
574 static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
575 int buf_size, ifindex_t ifindex)
576 {
577 struct interface *ifp;
578 struct pim_interface *pim_ifp;
579 const struct ip *ip_hdr;
580 const struct igmpmsg *msg;
581 char ip_src_str[INET_ADDRSTRLEN] = "";
582 char ip_dst_str[INET_ADDRSTRLEN] = "";
583 char src_str[INET_ADDRSTRLEN] = "<src?>";
584 char grp_str[INET_ADDRSTRLEN] = "<grp?>";
585 struct in_addr ifaddr;
586 struct igmp_sock *igmp;
587
588 ip_hdr = (const struct ip *)buf;
589
590 if (ip_hdr->ip_p == IPPROTO_IGMP) {
591
592 /* We have the IP packet but we do not know which interface this
593 * packet was
594 * received on. Find the interface that is on the same subnet as
595 * the source
596 * of the IP packet.
597 */
598 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
599
600 if (!ifp || !ifp->info)
601 return 0;
602
603 pim_ifp = ifp->info;
604 ifaddr = pim_find_primary_addr(ifp);
605 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
606 ifaddr);
607
608 if (PIM_DEBUG_MROUTE) {
609 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
610 sizeof(ip_src_str));
611 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
612 sizeof(ip_dst_str));
613
614 zlog_warn(
615 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
616 __PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
617 igmp, ip_src_str, ip_dst_str);
618 }
619 if (igmp)
620 pim_igmp_packet(igmp, (char *)buf, buf_size);
621
622 } else if (ip_hdr->ip_p) {
623 if (PIM_DEBUG_MROUTE_DETAIL) {
624 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
625 sizeof(src_str));
626 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
627 sizeof(grp_str));
628 zlog_debug(
629 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
630 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str,
631 grp_str, buf_size);
632 }
633
634 } else {
635 msg = (const struct igmpmsg *)buf;
636
637 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
638
639 if (!ifp)
640 return 0;
641 if (PIM_DEBUG_MROUTE) {
642 pim_inet4_dump("<src?>", msg->im_src, src_str,
643 sizeof(src_str));
644 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
645 sizeof(grp_str));
646 zlog_warn(
647 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
648 __PRETTY_FUNCTION__,
649 igmpmsgtype2str[msg->im_msgtype],
650 msg->im_msgtype, ip_hdr->ip_p,
651 pim->mroute_socket, src_str, grp_str, ifp->name,
652 msg->im_vif, buf_size);
653 }
654
655 switch (msg->im_msgtype) {
656 case IGMPMSG_WRONGVIF:
657 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
658 msg);
659 break;
660 case IGMPMSG_NOCACHE:
661 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
662 msg);
663 break;
664 case IGMPMSG_WHOLEPKT:
665 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
666 (const char *)msg);
667 break;
668 case IGMPMSG_WRVIFWHOLE:
669 return pim_mroute_msg_wrvifwhole(
670 pim->mroute_socket, ifp, (const char *)msg);
671 break;
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 if (PIM_DEBUG_MROUTE)
702 zlog_warn(
703 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
704 __PRETTY_FUNCTION__, rd,
705 pim->mroute_socket, errno,
706 safe_strerror(errno));
707 goto done;
708 }
709
710 result = pim_mroute_msg(pim, buf, rd, ifindex);
711
712 count++;
713 if (count % router->packet_process == 0)
714 cont = 0;
715 }
716 /* Keep reading */
717 done:
718 mroute_read_on(pim);
719
720 return result;
721 }
722
723 static void mroute_read_on(struct pim_instance *pim)
724 {
725 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
726 &pim->thread);
727 }
728
729 static void mroute_read_off(struct pim_instance *pim)
730 {
731 THREAD_OFF(pim->thread);
732 }
733
734 int pim_mroute_socket_enable(struct pim_instance *pim)
735 {
736 int fd;
737
738 frr_with_privs(&pimd_privs) {
739
740 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
741
742 if (fd < 0) {
743 zlog_warn("Could not create mroute socket: errno=%d: %s",
744 errno,
745 safe_strerror(errno));
746 return -2;
747 }
748
749 #ifdef SO_BINDTODEVICE
750 if (pim->vrf->vrf_id != VRF_DEFAULT
751 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
752 pim->vrf->name, strlen(pim->vrf->name))) {
753 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
754 safe_strerror(errno));
755 close(fd);
756 return -3;
757 }
758 #endif
759
760 }
761
762 pim->mroute_socket = fd;
763 if (pim_mroute_set(pim, 1)) {
764 zlog_warn(
765 "Could not enable mroute on socket fd=%d: errno=%d: %s",
766 fd, errno, safe_strerror(errno));
767 close(fd);
768 pim->mroute_socket = -1;
769 return -3;
770 }
771
772 pim->mroute_socket_creation = pim_time_monotonic_sec();
773
774 mroute_read_on(pim);
775
776 return 0;
777 }
778
779 int pim_mroute_socket_disable(struct pim_instance *pim)
780 {
781 if (pim_mroute_set(pim, 0)) {
782 zlog_warn(
783 "Could not disable mroute on socket fd=%d: errno=%d: %s",
784 pim->mroute_socket, errno, safe_strerror(errno));
785 return -2;
786 }
787
788 if (close(pim->mroute_socket)) {
789 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
790 pim->mroute_socket, errno, safe_strerror(errno));
791 return -3;
792 }
793
794 mroute_read_off(pim);
795 pim->mroute_socket = -1;
796
797 return 0;
798 }
799
800 /*
801 For each network interface (e.g., physical or a virtual tunnel) that
802 would be used for multicast forwarding, a corresponding multicast
803 interface must be added to the kernel.
804 */
805 int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
806 unsigned char flags)
807 {
808 struct pim_interface *pim_ifp = ifp->info;
809 struct vifctl vc;
810 int err;
811
812 if (PIM_DEBUG_MROUTE)
813 zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__,
814 pim_ifp->mroute_vif_index, ifp->name,
815 pim_ifp->pim->vrf->name);
816
817 memset(&vc, 0, sizeof(vc));
818 vc.vifc_vifi = pim_ifp->mroute_vif_index;
819 #ifdef VIFF_USE_IFINDEX
820 vc.vifc_lcl_ifindex = ifp->ifindex;
821 #else
822 if (ifaddr.s_addr == INADDR_ANY) {
823 zlog_warn(
824 "%s: unnumbered interfaces are not supported on this platform",
825 __PRETTY_FUNCTION__);
826 return -1;
827 }
828 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
829 #endif
830 vc.vifc_flags = flags;
831 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
832 vc.vifc_rate_limit = 0;
833
834 #ifdef PIM_DVMRP_TUNNEL
835 if (vc.vifc_flags & VIFF_TUNNEL) {
836 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
837 sizeof(vc.vifc_rmt_addr));
838 }
839 #endif
840
841 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
842 (void *)&vc, sizeof(vc));
843 if (err) {
844 char ifaddr_str[INET_ADDRSTRLEN];
845
846 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
847 sizeof(ifaddr_str));
848
849 zlog_warn(
850 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
851 __PRETTY_FUNCTION__, pim_ifp->pim->mroute_socket,
852 ifp->ifindex, ifaddr_str, flags, errno,
853 safe_strerror(errno));
854 return -2;
855 }
856
857 return 0;
858 }
859
860 int pim_mroute_del_vif(struct interface *ifp)
861 {
862 struct pim_interface *pim_ifp = ifp->info;
863 struct vifctl vc;
864 int err;
865
866 if (PIM_DEBUG_MROUTE)
867 zlog_debug("%s: Del Vif %d (%s[%s])", __PRETTY_FUNCTION__,
868 pim_ifp->mroute_vif_index, ifp->name,
869 pim_ifp->pim->vrf->name);
870
871 memset(&vc, 0, sizeof(vc));
872 vc.vifc_vifi = pim_ifp->mroute_vif_index;
873
874 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
875 (void *)&vc, sizeof(vc));
876 if (err) {
877 zlog_warn(
878 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
879 __FILE__, __PRETTY_FUNCTION__,
880 pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index,
881 errno, safe_strerror(errno));
882 return -2;
883 }
884
885 return 0;
886 }
887
888 int pim_mroute_add(struct channel_oil *c_oil, const char *name)
889 {
890 struct pim_instance *pim = c_oil->pim;
891 int err;
892 int orig = 0;
893 int orig_iif_vif = 0;
894 struct pim_interface *pim_reg_ifp = NULL;
895 int orig_pimreg_ttl = 0;
896 bool pimreg_ttl_reset = false;
897 struct pim_interface *vxlan_ifp = NULL;
898 int orig_term_ttl = 0;
899 bool orig_term_ttl_reset = false;
900
901 pim->mroute_add_last = pim_time_monotonic_sec();
902 ++pim->mroute_add_events;
903
904 /* Do not install route if incoming interface is undefined. */
905 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
906 if (PIM_DEBUG_MROUTE) {
907 char buf[1000];
908 zlog_debug(
909 "%s(%s) %s Attempting to add vifi that is invalid to mroute table",
910 __PRETTY_FUNCTION__, name,
911 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
912 }
913 return -2;
914 }
915
916 /* The linux kernel *expects* the incoming
917 * vif to be part of the outgoing list
918 * in the case of a (*,G).
919 */
920 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
921 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
922 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
923 }
924
925 if (c_oil->up) {
926 /* suppress pimreg in the OIL if the mroute is not supposed to
927 * trigger register encapsulated data
928 */
929 if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags)) {
930 pim_reg_ifp = pim->regiface->info;
931 orig_pimreg_ttl =
932 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index];
933 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] = 0;
934 /* remember to flip it back after MFC programming */
935 pimreg_ttl_reset = true;
936 }
937
938 vxlan_ifp = pim_vxlan_get_term_ifp(pim);
939 /* 1. vxlan termination device must never be added to the
940 * origination mroute (and that can actually happen because
941 * of XG inheritance from the termination mroute) otherwise
942 * traffic will end up looping.
943 * 2. vxlan termination device should be removed from the non-DF
944 * to prevent duplicates to the overlay rxer
945 */
946 if (vxlan_ifp &&
947 (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
948 PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags))) {
949 orig_term_ttl_reset = true;
950 orig_term_ttl =
951 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index];
952 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] = 0;
953 }
954 }
955
956 /*
957 * If we have an unresolved cache entry for the S,G
958 * it is owned by the pimreg for the incoming IIF
959 * So set pimreg as the IIF temporarily to cause
960 * the packets to be forwarded. Then set it
961 * to the correct IIF afterwords.
962 */
963 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
964 && c_oil->oil.mfcc_parent != 0) {
965 orig_iif_vif = c_oil->oil.mfcc_parent;
966 c_oil->oil.mfcc_parent = 0;
967 }
968 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
969 &c_oil->oil, sizeof(c_oil->oil));
970
971 if (!err && !c_oil->installed
972 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
973 && orig_iif_vif != 0) {
974 c_oil->oil.mfcc_parent = orig_iif_vif;
975 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
976 &c_oil->oil, sizeof(c_oil->oil));
977 }
978
979 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
980 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
981
982 if (pimreg_ttl_reset) {
983 assert(pim_reg_ifp);
984 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] =
985 orig_pimreg_ttl;
986 }
987
988 if (orig_term_ttl_reset)
989 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] =
990 orig_term_ttl;
991
992 if (err) {
993 zlog_warn(
994 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
995 __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
996 errno, safe_strerror(errno));
997 return -2;
998 }
999
1000 if (PIM_DEBUG_MROUTE) {
1001 char buf[1000];
1002 zlog_debug("%s(%s), vrf %s Added Route: %s",
1003 __PRETTY_FUNCTION__, name, pim->vrf->name,
1004 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1005 }
1006
1007 c_oil->installed = 1;
1008 c_oil->mroute_creation = pim_time_monotonic_sec();
1009
1010 return 0;
1011 }
1012
1013 int pim_mroute_del(struct channel_oil *c_oil, const char *name)
1014 {
1015 struct pim_instance *pim = c_oil->pim;
1016 int err;
1017
1018 pim->mroute_del_last = pim_time_monotonic_sec();
1019 ++pim->mroute_del_events;
1020
1021 if (!c_oil->installed) {
1022 if (PIM_DEBUG_MROUTE) {
1023 char buf[1000];
1024 zlog_debug(
1025 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1026 __FILE__, __PRETTY_FUNCTION__,
1027 c_oil->oil.mfcc_parent,
1028 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1029 }
1030 return -2;
1031 }
1032
1033 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
1034 &c_oil->oil, sizeof(c_oil->oil));
1035 if (err) {
1036 if (PIM_DEBUG_MROUTE)
1037 zlog_warn(
1038 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
1039 __FILE__, __PRETTY_FUNCTION__,
1040 pim->mroute_socket, errno,
1041 safe_strerror(errno));
1042 return -2;
1043 }
1044
1045 if (PIM_DEBUG_MROUTE) {
1046 char buf[1000];
1047 zlog_debug("%s(%s), vrf %s Deleted Route: %s",
1048 __PRETTY_FUNCTION__, name, pim->vrf->name,
1049 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1050 }
1051
1052 // Reset kernel installed flag
1053 c_oil->installed = 0;
1054
1055 return 0;
1056 }
1057
1058 void pim_mroute_update_counters(struct channel_oil *c_oil)
1059 {
1060 struct pim_instance *pim = c_oil->pim;
1061 struct sioc_sg_req sgreq;
1062
1063 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1064 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1065 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1066
1067 if (!c_oil->installed) {
1068 c_oil->cc.lastused = 100 * pim->keep_alive_time;
1069 if (PIM_DEBUG_MROUTE) {
1070 struct prefix_sg sg;
1071
1072 sg.src = c_oil->oil.mfcc_origin;
1073 sg.grp = c_oil->oil.mfcc_mcastgrp;
1074 if (PIM_DEBUG_MROUTE)
1075 zlog_debug(
1076 "Channel%s is not installed no need to collect data from kernel",
1077 pim_str_sg_dump(&sg));
1078 }
1079 return;
1080 }
1081
1082 memset(&sgreq, 0, sizeof(sgreq));
1083 sgreq.src = c_oil->oil.mfcc_origin;
1084 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1085
1086 pim_zlookup_sg_statistics(c_oil);
1087 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
1088 if (PIM_DEBUG_MROUTE) {
1089 struct prefix_sg sg;
1090
1091 sg.src = c_oil->oil.mfcc_origin;
1092 sg.grp = c_oil->oil.mfcc_mcastgrp;
1093
1094 zlog_warn(
1095 "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
1096 (unsigned long)SIOCGETSGCNT,
1097 pim_str_sg_dump(&sg), errno,
1098 safe_strerror(errno));
1099 }
1100 return;
1101 }
1102
1103 c_oil->cc.pktcnt = sgreq.pktcnt;
1104 c_oil->cc.bytecnt = sgreq.bytecnt;
1105 c_oil->cc.wrong_if = sgreq.wrong_if;
1106
1107 return;
1108 }