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