]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_mroute.c
Merge pull request #5430 from taruta811/build-docker-centos
[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_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_PIM_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_debug(
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_debug(
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 zlog_warn("%s: failure reading rd=%d: fd=%d: errno=%d: %s",
702 __PRETTY_FUNCTION__, rd, pim->mroute_socket,
703 errno, safe_strerror(errno));
704 goto done;
705 }
706
707 result = pim_mroute_msg(pim, buf, rd, ifindex);
708
709 count++;
710 if (count % router->packet_process == 0)
711 cont = 0;
712 }
713 /* Keep reading */
714 done:
715 mroute_read_on(pim);
716
717 return result;
718 }
719
720 static void mroute_read_on(struct pim_instance *pim)
721 {
722 thread_add_read(router->master, mroute_read, pim, pim->mroute_socket,
723 &pim->thread);
724 }
725
726 static void mroute_read_off(struct pim_instance *pim)
727 {
728 THREAD_OFF(pim->thread);
729 }
730
731 int pim_mroute_socket_enable(struct pim_instance *pim)
732 {
733 int fd;
734
735 frr_with_privs(&pimd_privs) {
736
737 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
738
739 if (fd < 0) {
740 zlog_warn("Could not create mroute socket: errno=%d: %s",
741 errno,
742 safe_strerror(errno));
743 return -2;
744 }
745
746 #ifdef SO_BINDTODEVICE
747 if (pim->vrf->vrf_id != VRF_DEFAULT
748 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
749 pim->vrf->name, strlen(pim->vrf->name))) {
750 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
751 safe_strerror(errno));
752 close(fd);
753 return -3;
754 }
755 #endif
756
757 }
758
759 pim->mroute_socket = fd;
760 if (pim_mroute_set(pim, 1)) {
761 zlog_warn(
762 "Could not enable mroute on socket fd=%d: errno=%d: %s",
763 fd, errno, safe_strerror(errno));
764 close(fd);
765 pim->mroute_socket = -1;
766 return -3;
767 }
768
769 pim->mroute_socket_creation = pim_time_monotonic_sec();
770
771 mroute_read_on(pim);
772
773 return 0;
774 }
775
776 int pim_mroute_socket_disable(struct pim_instance *pim)
777 {
778 if (pim_mroute_set(pim, 0)) {
779 zlog_warn(
780 "Could not disable mroute on socket fd=%d: errno=%d: %s",
781 pim->mroute_socket, errno, safe_strerror(errno));
782 return -2;
783 }
784
785 if (close(pim->mroute_socket)) {
786 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
787 pim->mroute_socket, errno, safe_strerror(errno));
788 return -3;
789 }
790
791 mroute_read_off(pim);
792 pim->mroute_socket = -1;
793
794 return 0;
795 }
796
797 /*
798 For each network interface (e.g., physical or a virtual tunnel) that
799 would be used for multicast forwarding, a corresponding multicast
800 interface must be added to the kernel.
801 */
802 int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
803 unsigned char flags)
804 {
805 struct pim_interface *pim_ifp = ifp->info;
806 struct vifctl vc;
807 int err;
808
809 if (PIM_DEBUG_MROUTE)
810 zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__,
811 pim_ifp->mroute_vif_index, ifp->name,
812 pim_ifp->pim->vrf->name);
813
814 memset(&vc, 0, sizeof(vc));
815 vc.vifc_vifi = pim_ifp->mroute_vif_index;
816 #ifdef VIFF_USE_IFINDEX
817 vc.vifc_lcl_ifindex = ifp->ifindex;
818 #else
819 if (ifaddr.s_addr == INADDR_ANY) {
820 zlog_warn(
821 "%s: unnumbered interfaces are not supported on this platform",
822 __PRETTY_FUNCTION__);
823 return -1;
824 }
825 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
826 #endif
827 vc.vifc_flags = flags;
828 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
829 vc.vifc_rate_limit = 0;
830
831 #ifdef PIM_DVMRP_TUNNEL
832 if (vc.vifc_flags & VIFF_TUNNEL) {
833 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
834 sizeof(vc.vifc_rmt_addr));
835 }
836 #endif
837
838 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
839 (void *)&vc, sizeof(vc));
840 if (err) {
841 char ifaddr_str[INET_ADDRSTRLEN];
842
843 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
844 sizeof(ifaddr_str));
845
846 zlog_warn(
847 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
848 __PRETTY_FUNCTION__, pim_ifp->pim->mroute_socket,
849 ifp->ifindex, ifaddr_str, flags, errno,
850 safe_strerror(errno));
851 return -2;
852 }
853
854 return 0;
855 }
856
857 int pim_mroute_del_vif(struct interface *ifp)
858 {
859 struct pim_interface *pim_ifp = ifp->info;
860 struct vifctl vc;
861 int err;
862
863 if (PIM_DEBUG_MROUTE)
864 zlog_debug("%s: Del Vif %d (%s[%s])", __PRETTY_FUNCTION__,
865 pim_ifp->mroute_vif_index, ifp->name,
866 pim_ifp->pim->vrf->name);
867
868 memset(&vc, 0, sizeof(vc));
869 vc.vifc_vifi = pim_ifp->mroute_vif_index;
870
871 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
872 (void *)&vc, sizeof(vc));
873 if (err) {
874 zlog_warn(
875 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
876 __FILE__, __PRETTY_FUNCTION__,
877 pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index,
878 errno, safe_strerror(errno));
879 return -2;
880 }
881
882 return 0;
883 }
884
885 int pim_mroute_add(struct channel_oil *c_oil, const char *name)
886 {
887 struct pim_instance *pim = c_oil->pim;
888 int err;
889 int orig = 0;
890 int orig_iif_vif = 0;
891 struct pim_interface *pim_reg_ifp = NULL;
892 int orig_pimreg_ttl = 0;
893 bool pimreg_ttl_reset = false;
894 struct pim_interface *vxlan_ifp = NULL;
895 int orig_term_ttl = 0;
896 bool orig_term_ttl_reset = false;
897
898 pim->mroute_add_last = pim_time_monotonic_sec();
899 ++pim->mroute_add_events;
900
901 /* Do not install route if incoming interface is undefined. */
902 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
903 if (PIM_DEBUG_MROUTE) {
904 char buf[1000];
905 zlog_debug(
906 "%s(%s) %s Attempting to add vifi that is invalid to mroute table",
907 __PRETTY_FUNCTION__, name,
908 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
909 }
910 return -2;
911 }
912
913 /* The linux kernel *expects* the incoming
914 * vif to be part of the outgoing list
915 * in the case of a (*,G).
916 */
917 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
918 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
919 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
920 }
921
922 if (c_oil->up) {
923 /* suppress pimreg in the OIL if the mroute is not supposed to
924 * trigger register encapsulated data
925 */
926 if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags)) {
927 pim_reg_ifp = pim->regiface->info;
928 orig_pimreg_ttl =
929 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index];
930 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] = 0;
931 /* remember to flip it back after MFC programming */
932 pimreg_ttl_reset = true;
933 }
934
935 vxlan_ifp = pim_vxlan_get_term_ifp(pim);
936 /* 1. vxlan termination device must never be added to the
937 * origination mroute (and that can actually happen because
938 * of XG inheritance from the termination mroute) otherwise
939 * traffic will end up looping.
940 * 2. vxlan termination device should be removed from the non-DF
941 * to prevent duplicates to the overlay rxer
942 */
943 if (vxlan_ifp &&
944 (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
945 PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags))) {
946 orig_term_ttl_reset = true;
947 orig_term_ttl =
948 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index];
949 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] = 0;
950 }
951 }
952
953 /*
954 * If we have an unresolved cache entry for the S,G
955 * it is owned by the pimreg for the incoming IIF
956 * So set pimreg as the IIF temporarily to cause
957 * the packets to be forwarded. Then set it
958 * to the correct IIF afterwords.
959 */
960 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
961 && c_oil->oil.mfcc_parent != 0) {
962 orig_iif_vif = c_oil->oil.mfcc_parent;
963 c_oil->oil.mfcc_parent = 0;
964 }
965 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
966 &c_oil->oil, sizeof(c_oil->oil));
967
968 if (!err && !c_oil->installed
969 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
970 && orig_iif_vif != 0) {
971 c_oil->oil.mfcc_parent = orig_iif_vif;
972 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
973 &c_oil->oil, sizeof(c_oil->oil));
974 }
975
976 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
977 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
978
979 if (pimreg_ttl_reset) {
980 assert(pim_reg_ifp);
981 c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] =
982 orig_pimreg_ttl;
983 }
984
985 if (orig_term_ttl_reset)
986 c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] =
987 orig_term_ttl;
988
989 if (err) {
990 zlog_warn(
991 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
992 __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
993 errno, safe_strerror(errno));
994 return -2;
995 }
996
997 if (PIM_DEBUG_MROUTE) {
998 char buf[1000];
999 zlog_debug("%s(%s), vrf %s Added Route: %s",
1000 __PRETTY_FUNCTION__, name, pim->vrf->name,
1001 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1002 }
1003
1004 c_oil->installed = 1;
1005 c_oil->mroute_creation = pim_time_monotonic_sec();
1006
1007 return 0;
1008 }
1009
1010 int pim_mroute_del(struct channel_oil *c_oil, const char *name)
1011 {
1012 struct pim_instance *pim = c_oil->pim;
1013 int err;
1014
1015 pim->mroute_del_last = pim_time_monotonic_sec();
1016 ++pim->mroute_del_events;
1017
1018 if (!c_oil->installed) {
1019 if (PIM_DEBUG_MROUTE) {
1020 char buf[1000];
1021 zlog_debug(
1022 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1023 __FILE__, __PRETTY_FUNCTION__,
1024 c_oil->oil.mfcc_parent,
1025 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1026 }
1027 return -2;
1028 }
1029
1030 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
1031 &c_oil->oil, sizeof(c_oil->oil));
1032 if (err) {
1033 if (PIM_DEBUG_MROUTE)
1034 zlog_warn(
1035 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
1036 __FILE__, __PRETTY_FUNCTION__,
1037 pim->mroute_socket, errno,
1038 safe_strerror(errno));
1039 return -2;
1040 }
1041
1042 if (PIM_DEBUG_MROUTE) {
1043 char buf[1000];
1044 zlog_debug("%s(%s), vrf %s Deleted Route: %s",
1045 __PRETTY_FUNCTION__, name, pim->vrf->name,
1046 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1047 }
1048
1049 // Reset kernel installed flag
1050 c_oil->installed = 0;
1051
1052 return 0;
1053 }
1054
1055 void pim_mroute_update_counters(struct channel_oil *c_oil)
1056 {
1057 struct pim_instance *pim = c_oil->pim;
1058 struct sioc_sg_req sgreq;
1059
1060 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1061 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1062 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1063
1064 if (!c_oil->installed) {
1065 c_oil->cc.lastused = 100 * pim->keep_alive_time;
1066 if (PIM_DEBUG_MROUTE) {
1067 struct prefix_sg sg;
1068
1069 sg.src = c_oil->oil.mfcc_origin;
1070 sg.grp = c_oil->oil.mfcc_mcastgrp;
1071 if (PIM_DEBUG_MROUTE)
1072 zlog_debug(
1073 "Channel%s is not installed no need to collect data from kernel",
1074 pim_str_sg_dump(&sg));
1075 }
1076 return;
1077 }
1078
1079 memset(&sgreq, 0, sizeof(sgreq));
1080 sgreq.src = c_oil->oil.mfcc_origin;
1081 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1082
1083 pim_zlookup_sg_statistics(c_oil);
1084 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
1085 struct prefix_sg sg;
1086
1087 sg.src = c_oil->oil.mfcc_origin;
1088 sg.grp = c_oil->oil.mfcc_mcastgrp;
1089
1090 zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s",
1091 (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg),
1092 errno, safe_strerror(errno));
1093 return;
1094 }
1095
1096 c_oil->cc.pktcnt = sgreq.pktcnt;
1097 c_oil->cc.bytecnt = sgreq.bytecnt;
1098 c_oil->cc.wrong_if = sgreq.wrong_if;
1099
1100 return;
1101 }