]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_mroute.c
zebra: Allow ns delete to happen after under/over flow checks
[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
46 static void mroute_read_on(struct pim_instance *pim);
47
48 static int pim_mroute_set(struct pim_instance *pim, int enable)
49 {
50 int err;
51 int opt, data;
52 socklen_t data_len = sizeof(data);
53 long flags;
54
55 /*
56 * We need to create the VRF table for the pim mroute_socket
57 */
58 if (pim->vrf_id != VRF_DEFAULT) {
59 frr_elevate_privs(&pimd_privs) {
60
61 data = pim->vrf->data.l.table_id;
62 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
63 MRT_TABLE,
64 &data, data_len);
65 if (err) {
66 zlog_warn(
67 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
68 __FILE__, __PRETTY_FUNCTION__,
69 pim->mroute_socket, data, errno,
70 safe_strerror(errno));
71 return -1;
72 }
73
74 }
75 }
76
77 frr_elevate_privs(&pimd_privs) {
78 opt = enable ? MRT_INIT : MRT_DONE;
79 /*
80 * *BSD *cares* about what value we pass down
81 * here
82 */
83 data = 1;
84 err = setsockopt(pim->mroute_socket, IPPROTO_IP,
85 opt, &data, data_len);
86 if (err) {
87 zlog_warn(
88 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
89 __FILE__, __PRETTY_FUNCTION__,
90 pim->mroute_socket,
91 enable ? "MRT_INIT" : "MRT_DONE", data, errno,
92 safe_strerror(errno));
93 return -1;
94 }
95 }
96
97 #if defined(HAVE_IP_PKTINFO)
98 if (enable) {
99 /* Linux and Solaris IP_PKTINFO */
100 data = 1;
101 if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
102 &data, data_len)) {
103 zlog_warn(
104 "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
105 pim->mroute_socket, errno,
106 safe_strerror(errno));
107 }
108 }
109 #endif
110
111 setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
112
113 flags = fcntl(pim->mroute_socket, F_GETFL, 0);
114 if (flags < 0) {
115 zlog_warn("Could not get flags on socket fd:%d %d %s",
116 pim->mroute_socket, errno, safe_strerror(errno));
117 close(pim->mroute_socket);
118 return -1;
119 }
120 if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
121 zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
122 pim->mroute_socket, errno, safe_strerror(errno));
123 close(pim->mroute_socket);
124 return -1;
125 }
126
127 if (enable) {
128 #if defined linux
129 int upcalls = IGMPMSG_WRVIFWHOLE;
130 opt = MRT_PIM;
131
132 err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
133 sizeof(upcalls));
134 if (err) {
135 zlog_warn(
136 "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
137 errno, safe_strerror(errno));
138 return -1;
139 }
140 #else
141 zlog_warn(
142 "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
143 #endif
144 }
145
146 return 0;
147 }
148
149 static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
150 "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
151
152 static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
153 const struct igmpmsg *msg)
154 {
155 struct pim_interface *pim_ifp = ifp->info;
156 struct pim_upstream *up;
157 struct pim_rpf *rpg;
158 struct prefix_sg sg;
159
160 rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
161 /*
162 * If the incoming interface is unknown OR
163 * the Interface type is SSM we don't need to
164 * do anything here
165 */
166 if (!rpg || pim_rpf_addr_is_inaddr_none(rpg)) {
167 if (PIM_DEBUG_MROUTE_DETAIL)
168 zlog_debug(
169 "%s: Interface is not configured correctly to handle incoming packet: Could be !pim_ifp, !SM, !RP",
170 __PRETTY_FUNCTION__);
171
172 return 0;
173 }
174
175 /*
176 * If we've received a multicast packet that isn't connected to
177 * us
178 */
179 if (!pim_if_connected_to_source(ifp, msg->im_src)) {
180 if (PIM_DEBUG_MROUTE_DETAIL)
181 zlog_debug(
182 "%s: Received incoming packet that doesn't originate on our seg",
183 __PRETTY_FUNCTION__);
184 return 0;
185 }
186
187 memset(&sg, 0, sizeof(struct prefix_sg));
188 sg.src = msg->im_src;
189 sg.grp = msg->im_dst;
190
191 if (!(PIM_I_am_DR(pim_ifp))) {
192 struct channel_oil *c_oil;
193
194 if (PIM_DEBUG_MROUTE_DETAIL)
195 zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %s",
196 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
197
198 /*
199 * We are not the DR, but we are still receiving packets
200 * Let's blackhole those packets for the moment
201 * As that they will be coming up to the cpu
202 * and causing us to consider them.
203 */
204 c_oil = pim_channel_oil_add(pim_ifp->pim, &sg,
205 pim_ifp->mroute_vif_index);
206 pim_mroute_add(c_oil, __PRETTY_FUNCTION__);
207
208 return 0;
209 }
210
211 up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
212 __PRETTY_FUNCTION__);
213 if (!up) {
214 if (PIM_DEBUG_MROUTE) {
215 zlog_debug(
216 "%s: Failure to add upstream information for %s",
217 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
218 }
219 return 0;
220 }
221
222 /*
223 * I moved this debug till after the actual add because
224 * I want to take advantage of the up->sg_str being filled in.
225 */
226 if (PIM_DEBUG_MROUTE) {
227 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
228 __PRETTY_FUNCTION__, up->sg_str);
229 }
230
231 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
232 pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
233
234 up->channel_oil->cc.pktcnt++;
235 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
236 // resolve mfcc_parent prior to mroute_add in channel_add_oif
237 if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
238 int vif_index = 0;
239 vif_index = pim_if_find_vifindex_by_ifindex(
240 pim_ifp->pim,
241 up->rpf.source_nexthop.interface->ifindex);
242 up->channel_oil->oil.mfcc_parent = vif_index;
243 }
244 pim_register_join(up);
245
246 return 0;
247 }
248
249 static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
250 const char *buf)
251 {
252 struct pim_interface *pim_ifp;
253 struct prefix_sg sg;
254 struct pim_rpf *rpg;
255 const struct ip *ip_hdr;
256 struct pim_upstream *up;
257
258 pim_ifp = ifp->info;
259
260 ip_hdr = (const struct ip *)buf;
261
262 memset(&sg, 0, sizeof(struct prefix_sg));
263 sg.src = ip_hdr->ip_src;
264 sg.grp = ip_hdr->ip_dst;
265
266 up = pim_upstream_find(pim_ifp->pim, &sg);
267 if (!up) {
268 struct prefix_sg star = sg;
269 star.src.s_addr = INADDR_ANY;
270
271 up = pim_upstream_find(pim_ifp->pim, &star);
272
273 if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) {
274 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
275 PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
276 __PRETTY_FUNCTION__, NULL);
277 if (!up) {
278 if (PIM_DEBUG_MROUTE)
279 zlog_debug(
280 "%s: Unable to create upstream information for %s",
281 __PRETTY_FUNCTION__,
282 pim_str_sg_dump(&sg));
283 return 0;
284 }
285 pim_upstream_keep_alive_timer_start(
286 up, pim_ifp->pim->keep_alive_time);
287 pim_upstream_inherited_olist(pim_ifp->pim, up);
288 pim_upstream_switch(pim_ifp->pim, up,
289 PIM_UPSTREAM_JOINED);
290
291 if (PIM_DEBUG_MROUTE)
292 zlog_debug("%s: Creating %s upstream on LHR",
293 __PRETTY_FUNCTION__, up->sg_str);
294 return 0;
295 }
296 if (PIM_DEBUG_MROUTE_DETAIL) {
297 zlog_debug(
298 "%s: Unable to find upstream channel WHOLEPKT%s",
299 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
300 }
301 return 0;
302 }
303
304 pim_ifp = up->rpf.source_nexthop.interface->info;
305
306 rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
307
308 if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
309 || (!(PIM_I_am_DR(pim_ifp)))) {
310 if (PIM_DEBUG_MROUTE) {
311 zlog_debug("%s: Failed Check send packet",
312 __PRETTY_FUNCTION__);
313 }
314 return 0;
315 }
316
317 /*
318 * If we've received a register suppress
319 */
320 if (!up->t_rs_timer) {
321 if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
322 if (PIM_DEBUG_PIM_REG)
323 zlog_debug(
324 "%s register forward skipped as group is SSM",
325 pim_str_sg_dump(&sg));
326 return 0;
327 }
328 pim_register_send((uint8_t *)buf + sizeof(struct ip),
329 ntohs(ip_hdr->ip_len) - sizeof(struct ip),
330 pim_ifp->primary_address, rpg, 0, up);
331 }
332 return 0;
333 }
334
335 static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
336 const struct igmpmsg *msg)
337 {
338 struct pim_ifchannel *ch;
339 struct pim_interface *pim_ifp;
340 struct prefix_sg sg;
341
342 memset(&sg, 0, sizeof(struct prefix_sg));
343 sg.src = msg->im_src;
344 sg.grp = msg->im_dst;
345
346 /*
347 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
348
349 RFC 4601 4.8.2. PIM-SSM-Only Routers
350
351 iif is the incoming interface of the packet.
352 if (iif is in inherited_olist(S,G)) {
353 send Assert(S,G) on iif
354 }
355 */
356
357 if (!ifp) {
358 if (PIM_DEBUG_MROUTE)
359 zlog_debug(
360 "%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
361 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
362 msg->im_vif);
363 return -1;
364 }
365
366 pim_ifp = ifp->info;
367 if (!pim_ifp) {
368 if (PIM_DEBUG_MROUTE)
369 zlog_debug(
370 "%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
371 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
372 ifp->name);
373 return -2;
374 }
375
376 ch = pim_ifchannel_find(ifp, &sg);
377 if (!ch) {
378 struct prefix_sg star_g = sg;
379 if (PIM_DEBUG_MROUTE)
380 zlog_debug(
381 "%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
382 __PRETTY_FUNCTION__, pim_str_sg_dump(&sg),
383 ifp->name);
384
385 star_g.src.s_addr = INADDR_ANY;
386 ch = pim_ifchannel_find(ifp, &star_g);
387 if (!ch) {
388 if (PIM_DEBUG_MROUTE)
389 zlog_debug(
390 "%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
391 __PRETTY_FUNCTION__,
392 pim_str_sg_dump(&star_g), ifp->name);
393 return -3;
394 }
395 }
396
397 /*
398 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
399
400 Transitions from NoInfo State
401
402 An (S,G) data packet arrives on interface I, AND
403 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
404 downstream interface that is in our (S,G) outgoing interface
405 list. We optimistically assume that we will be the assert
406 winner for this (S,G), and so we transition to the "I am Assert
407 Winner" state and perform Actions A1 (below), which will
408 initiate the assert negotiation for (S,G).
409 */
410
411 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
412 if (PIM_DEBUG_MROUTE) {
413 zlog_debug(
414 "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
415 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
416 }
417 return -4;
418 }
419
420 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
421 if (PIM_DEBUG_MROUTE) {
422 zlog_debug(
423 "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
424 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
425 }
426 return -5;
427 }
428
429 if (assert_action_a1(ch)) {
430 if (PIM_DEBUG_MROUTE) {
431 zlog_debug(
432 "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
433 __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
434 }
435 return -6;
436 }
437
438 return 0;
439 }
440
441 static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
442 const char *buf)
443 {
444 const struct ip *ip_hdr = (const struct ip *)buf;
445 struct pim_interface *pim_ifp;
446 struct pim_ifchannel *ch;
447 struct pim_upstream *up;
448 struct prefix_sg star_g;
449 struct prefix_sg sg;
450 struct channel_oil *oil;
451
452 pim_ifp = ifp->info;
453
454 memset(&sg, 0, sizeof(struct prefix_sg));
455 sg.src = ip_hdr->ip_src;
456 sg.grp = ip_hdr->ip_dst;
457
458 ch = pim_ifchannel_find(ifp, &sg);
459 if (ch) {
460 if (PIM_DEBUG_MROUTE)
461 zlog_debug(
462 "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
463 ch->sg_str, ifp->name);
464 return -1;
465 }
466
467 star_g = sg;
468 star_g.src.s_addr = INADDR_ANY;
469 #if 0
470 ch = pim_ifchannel_find(ifp, &star_g);
471 if (ch)
472 {
473 if (PIM_DEBUG_MROUTE)
474 zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
475 pim_str_sg_dump (&star_g), ifp->name);
476 return -1;
477 }
478 #endif
479
480 up = pim_upstream_find(pim_ifp->pim, &sg);
481 if (up) {
482 struct pim_upstream *parent;
483 struct pim_nexthop source;
484 struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
485 if (!rpf || !rpf->source_nexthop.interface)
486 return 0;
487
488 /*
489 * If we have received a WRVIFWHOLE and are at this
490 * point, we could be receiving the packet on the *,G
491 * tree, let's check and if so we can safely drop
492 * it.
493 */
494 parent = pim_upstream_find(pim_ifp->pim, &star_g);
495 if (parent && parent->rpf.source_nexthop.interface == ifp)
496 return 0;
497
498 pim_ifp = rpf->source_nexthop.interface->info;
499
500 memset(&source, 0, sizeof(source));
501 /*
502 * If we are the fhr that means we are getting a callback during
503 * the pimreg period, so I believe we can ignore this packet
504 */
505 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
506 // No if channel, but upstream we are at the RP.
507 if (pim_nexthop_lookup(pim_ifp->pim, &source,
508 up->upstream_register, 0)
509 == 0) {
510 pim_register_stop_send(source.interface, &sg,
511 pim_ifp->primary_address,
512 up->upstream_register);
513 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
514 }
515 if (!up->channel_oil)
516 up->channel_oil = pim_channel_oil_add(
517 pim_ifp->pim, &sg,
518 pim_ifp->mroute_vif_index);
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, 0)
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 oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index);
544 if (!oil->installed)
545 pim_mroute_add(oil, __PRETTY_FUNCTION__);
546 if (pim_if_connected_to_source(ifp, sg.src)) {
547 up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
548 PIM_UPSTREAM_FLAG_MASK_FHR,
549 __PRETTY_FUNCTION__, NULL);
550 if (!up) {
551 if (PIM_DEBUG_MROUTE)
552 zlog_debug(
553 "%s: WRONGVIF%s unable to create upstream on interface",
554 pim_str_sg_dump(&sg), ifp->name);
555 return -2;
556 }
557 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
558 pim_upstream_keep_alive_timer_start(
559 up, pim_ifp->pim->keep_alive_time);
560 up->channel_oil = oil;
561 up->channel_oil->cc.pktcnt++;
562 pim_register_join(up);
563 pim_upstream_inherited_olist(pim_ifp->pim, up);
564
565 // Send the packet to the RP
566 pim_mroute_msg_wholepkt(fd, ifp, buf);
567 }
568
569 return 0;
570 }
571
572 static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
573 int buf_size, ifindex_t ifindex)
574 {
575 struct interface *ifp;
576 struct pim_interface *pim_ifp;
577 const struct ip *ip_hdr;
578 const struct igmpmsg *msg;
579 char ip_src_str[INET_ADDRSTRLEN] = "";
580 char ip_dst_str[INET_ADDRSTRLEN] = "";
581 char src_str[INET_ADDRSTRLEN] = "<src?>";
582 char grp_str[INET_ADDRSTRLEN] = "<grp?>";
583 struct in_addr ifaddr;
584 struct igmp_sock *igmp;
585
586 ip_hdr = (const struct ip *)buf;
587
588 if (ip_hdr->ip_p == IPPROTO_IGMP) {
589
590 /* We have the IP packet but we do not know which interface this
591 * packet was
592 * received on. Find the interface that is on the same subnet as
593 * the source
594 * of the IP packet.
595 */
596 ifp = if_lookup_by_index(ifindex, pim->vrf_id);
597
598 if (!ifp || !ifp->info)
599 return 0;
600
601 pim_ifp = ifp->info;
602 ifaddr = pim_find_primary_addr(ifp);
603 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
604 ifaddr);
605
606 if (PIM_DEBUG_MROUTE) {
607 pim_inet4_dump("<src?>", ip_hdr->ip_src, ip_src_str,
608 sizeof(ip_src_str));
609 pim_inet4_dump("<dst?>", ip_hdr->ip_dst, ip_dst_str,
610 sizeof(ip_dst_str));
611
612 zlog_warn(
613 "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
614 __PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
615 igmp, ip_src_str, ip_dst_str);
616 }
617 if (igmp)
618 pim_igmp_packet(igmp, (char *)buf, buf_size);
619
620 } else if (ip_hdr->ip_p) {
621 if (PIM_DEBUG_MROUTE_DETAIL) {
622 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str,
623 sizeof(src_str));
624 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str,
625 sizeof(grp_str));
626 zlog_debug(
627 "%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
628 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str,
629 grp_str, buf_size);
630 }
631
632 } else {
633 msg = (const struct igmpmsg *)buf;
634
635 ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
636
637 if (!ifp)
638 return 0;
639 if (PIM_DEBUG_MROUTE) {
640 pim_inet4_dump("<src?>", msg->im_src, src_str,
641 sizeof(src_str));
642 pim_inet4_dump("<grp?>", msg->im_dst, grp_str,
643 sizeof(grp_str));
644 zlog_warn(
645 "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d",
646 __PRETTY_FUNCTION__,
647 igmpmsgtype2str[msg->im_msgtype],
648 msg->im_msgtype, ip_hdr->ip_p,
649 pim->mroute_socket, src_str, grp_str, ifp->name,
650 msg->im_vif, buf_size);
651 }
652
653 switch (msg->im_msgtype) {
654 case IGMPMSG_WRONGVIF:
655 return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
656 msg);
657 break;
658 case IGMPMSG_NOCACHE:
659 return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
660 msg);
661 break;
662 case IGMPMSG_WHOLEPKT:
663 return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
664 (const char *)msg);
665 break;
666 case IGMPMSG_WRVIFWHOLE:
667 return pim_mroute_msg_wrvifwhole(
668 pim->mroute_socket, ifp, (const char *)msg);
669 break;
670 default:
671 break;
672 }
673 }
674
675 return 0;
676 }
677
678 static int mroute_read(struct thread *t)
679 {
680 struct pim_instance *pim;
681 static long long count;
682 char buf[10000];
683 int result = 0;
684 int cont = 1;
685 int rd;
686 ifindex_t ifindex;
687 pim = THREAD_ARG(t);
688
689 while (cont) {
690 rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
691 sizeof(buf), NULL, NULL, NULL, NULL,
692 &ifindex);
693 if (rd <= 0) {
694 if (errno == EINTR)
695 continue;
696 if (errno == EWOULDBLOCK || errno == EAGAIN)
697 break;
698
699 if (PIM_DEBUG_MROUTE)
700 zlog_warn(
701 "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
702 __PRETTY_FUNCTION__, rd,
703 pim->mroute_socket, errno,
704 safe_strerror(errno));
705 goto done;
706 }
707
708 result = pim_mroute_msg(pim, buf, rd, ifindex);
709
710 count++;
711 if (count % qpim_packet_process == 0)
712 cont = 0;
713 }
714 /* Keep reading */
715 done:
716 mroute_read_on(pim);
717
718 return result;
719 }
720
721 static void mroute_read_on(struct pim_instance *pim)
722 {
723 thread_add_read(master, mroute_read, pim, pim->mroute_socket,
724 &pim->thread);
725 }
726
727 static void mroute_read_off(struct pim_instance *pim)
728 {
729 THREAD_OFF(pim->thread);
730 }
731
732 int pim_mroute_socket_enable(struct pim_instance *pim)
733 {
734 int fd;
735
736 frr_elevate_privs(&pimd_privs) {
737
738 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
739
740 if (fd < 0) {
741 zlog_warn("Could not create mroute socket: errno=%d: %s",
742 errno,
743 safe_strerror(errno));
744 return -2;
745 }
746
747 #ifdef SO_BINDTODEVICE
748 if (pim->vrf->vrf_id != VRF_DEFAULT
749 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
750 pim->vrf->name, strlen(pim->vrf->name))) {
751 zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
752 safe_strerror(errno));
753 close(fd);
754 return -3;
755 }
756 #endif
757
758 }
759
760 pim->mroute_socket = fd;
761 if (pim_mroute_set(pim, 1)) {
762 zlog_warn(
763 "Could not enable mroute on socket fd=%d: errno=%d: %s",
764 fd, errno, safe_strerror(errno));
765 close(fd);
766 pim->mroute_socket = -1;
767 return -3;
768 }
769
770 pim->mroute_socket_creation = pim_time_monotonic_sec();
771
772 mroute_read_on(pim);
773
774 return 0;
775 }
776
777 int pim_mroute_socket_disable(struct pim_instance *pim)
778 {
779 if (pim_mroute_set(pim, 0)) {
780 zlog_warn(
781 "Could not disable mroute on socket fd=%d: errno=%d: %s",
782 pim->mroute_socket, errno, safe_strerror(errno));
783 return -2;
784 }
785
786 if (close(pim->mroute_socket)) {
787 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
788 pim->mroute_socket, errno, safe_strerror(errno));
789 return -3;
790 }
791
792 mroute_read_off(pim);
793 pim->mroute_socket = -1;
794
795 return 0;
796 }
797
798 /*
799 For each network interface (e.g., physical or a virtual tunnel) that
800 would be used for multicast forwarding, a corresponding multicast
801 interface must be added to the kernel.
802 */
803 int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
804 unsigned char flags)
805 {
806 struct pim_interface *pim_ifp = ifp->info;
807 struct vifctl vc;
808 int err;
809
810 if (PIM_DEBUG_MROUTE)
811 zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__,
812 pim_ifp->mroute_vif_index, ifp->name,
813 pim_ifp->pim->vrf->name);
814
815 memset(&vc, 0, sizeof(vc));
816 vc.vifc_vifi = pim_ifp->mroute_vif_index;
817 #ifdef VIFF_USE_IFINDEX
818 vc.vifc_lcl_ifindex = ifp->ifindex;
819 #else
820 if (ifaddr.s_addr == INADDR_ANY) {
821 zlog_warn(
822 "%s: unnumbered interfaces are not supported on this platform",
823 __PRETTY_FUNCTION__);
824 return -1;
825 }
826 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
827 #endif
828 vc.vifc_flags = flags;
829 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
830 vc.vifc_rate_limit = 0;
831
832 #ifdef PIM_DVMRP_TUNNEL
833 if (vc.vifc_flags & VIFF_TUNNEL) {
834 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
835 sizeof(vc.vifc_rmt_addr));
836 }
837 #endif
838
839 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
840 (void *)&vc, sizeof(vc));
841 if (err) {
842 char ifaddr_str[INET_ADDRSTRLEN];
843
844 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str,
845 sizeof(ifaddr_str));
846
847 zlog_warn(
848 "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
849 __PRETTY_FUNCTION__, pim_ifp->pim->mroute_socket,
850 ifp->ifindex, ifaddr_str, flags, errno,
851 safe_strerror(errno));
852 return -2;
853 }
854
855 return 0;
856 }
857
858 int pim_mroute_del_vif(struct interface *ifp)
859 {
860 struct pim_interface *pim_ifp = ifp->info;
861 struct vifctl vc;
862 int err;
863
864 if (PIM_DEBUG_MROUTE)
865 zlog_debug("%s: Del Vif %d (%s[%s])", __PRETTY_FUNCTION__,
866 pim_ifp->mroute_vif_index, ifp->name,
867 pim_ifp->pim->vrf->name);
868
869 memset(&vc, 0, sizeof(vc));
870 vc.vifc_vifi = pim_ifp->mroute_vif_index;
871
872 err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
873 (void *)&vc, sizeof(vc));
874 if (err) {
875 zlog_warn(
876 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
877 __FILE__, __PRETTY_FUNCTION__,
878 pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index,
879 errno, safe_strerror(errno));
880 return -2;
881 }
882
883 return 0;
884 }
885
886 int pim_mroute_add(struct channel_oil *c_oil, const char *name)
887 {
888 struct pim_instance *pim = c_oil->pim;
889 int err;
890 int orig = 0;
891 int orig_iif_vif = 0;
892
893 pim->mroute_add_last = pim_time_monotonic_sec();
894 ++pim->mroute_add_events;
895
896 /* Do not install route if incoming interface is undefined. */
897 if (c_oil->oil.mfcc_parent >= MAXVIFS) {
898 if (PIM_DEBUG_MROUTE) {
899 char buf[1000];
900 zlog_debug(
901 "%s(%s) %s Attempting to add vifi that is invalid to mroute table",
902 __PRETTY_FUNCTION__, name,
903 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
904 }
905 return -2;
906 }
907
908 /* The linux kernel *expects* the incoming
909 * vif to be part of the outgoing list
910 * in the case of a (*,G).
911 */
912 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) {
913 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
914 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
915 }
916
917 /*
918 * If we have an unresolved cache entry for the S,G
919 * it is owned by the pimreg for the incoming IIF
920 * So set pimreg as the IIF temporarily to cause
921 * the packets to be forwarded. Then set it
922 * to the correct IIF afterwords.
923 */
924 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
925 && c_oil->oil.mfcc_parent != 0) {
926 orig_iif_vif = c_oil->oil.mfcc_parent;
927 c_oil->oil.mfcc_parent = 0;
928 }
929 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
930 &c_oil->oil, sizeof(c_oil->oil));
931
932 if (!err && !c_oil->installed
933 && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
934 && orig_iif_vif != 0) {
935 c_oil->oil.mfcc_parent = orig_iif_vif;
936 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
937 &c_oil->oil, sizeof(c_oil->oil));
938 }
939
940 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
941 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
942
943 if (err) {
944 zlog_warn(
945 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
946 __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
947 errno, safe_strerror(errno));
948 return -2;
949 }
950
951 if (PIM_DEBUG_MROUTE) {
952 char buf[1000];
953 zlog_debug("%s(%s), vrf %s Added Route: %s",
954 __PRETTY_FUNCTION__, name, pim->vrf->name,
955 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
956 }
957
958 c_oil->installed = 1;
959 return 0;
960 }
961
962 int pim_mroute_del(struct channel_oil *c_oil, const char *name)
963 {
964 struct pim_instance *pim = c_oil->pim;
965 int err;
966
967 pim->mroute_del_last = pim_time_monotonic_sec();
968 ++pim->mroute_del_events;
969
970 if (!c_oil->installed) {
971 if (PIM_DEBUG_MROUTE) {
972 char buf[1000];
973 zlog_debug(
974 "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
975 __FILE__, __PRETTY_FUNCTION__,
976 c_oil->oil.mfcc_parent,
977 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
978 }
979 return -2;
980 }
981
982 err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
983 &c_oil->oil, sizeof(c_oil->oil));
984 if (err) {
985 if (PIM_DEBUG_MROUTE)
986 zlog_warn(
987 "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
988 __FILE__, __PRETTY_FUNCTION__,
989 pim->mroute_socket, errno,
990 safe_strerror(errno));
991 return -2;
992 }
993
994 if (PIM_DEBUG_MROUTE) {
995 char buf[1000];
996 zlog_debug("%s(%s), vrf %s Deleted Route: %s",
997 __PRETTY_FUNCTION__, name, pim->vrf->name,
998 pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
999 }
1000
1001 // Reset kernel installed flag
1002 c_oil->installed = 0;
1003
1004 return 0;
1005 }
1006
1007 void pim_mroute_update_counters(struct channel_oil *c_oil)
1008 {
1009 struct pim_instance *pim = c_oil->pim;
1010 struct sioc_sg_req sgreq;
1011
1012 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1013 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1014 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1015
1016 if (!c_oil->installed) {
1017 c_oil->cc.lastused = 100 * pim->keep_alive_time;
1018 if (PIM_DEBUG_MROUTE) {
1019 struct prefix_sg sg;
1020
1021 sg.src = c_oil->oil.mfcc_origin;
1022 sg.grp = c_oil->oil.mfcc_mcastgrp;
1023 if (PIM_DEBUG_MROUTE)
1024 zlog_debug(
1025 "Channel(%s) is not installed no need to collect data from kernel",
1026 pim_str_sg_dump(&sg));
1027 }
1028 return;
1029 }
1030
1031 memset(&sgreq, 0, sizeof(sgreq));
1032 sgreq.src = c_oil->oil.mfcc_origin;
1033 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
1034
1035 pim_zlookup_sg_statistics(c_oil);
1036 if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
1037 if (PIM_DEBUG_MROUTE) {
1038 struct prefix_sg sg;
1039
1040 sg.src = c_oil->oil.mfcc_origin;
1041 sg.grp = c_oil->oil.mfcc_mcastgrp;
1042
1043 zlog_warn(
1044 "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
1045 (unsigned long)SIOCGETSGCNT,
1046 pim_str_sg_dump(&sg), errno,
1047 safe_strerror(errno));
1048 }
1049 return;
1050 }
1051
1052 c_oil->cc.pktcnt = sgreq.pktcnt;
1053 c_oil->cc.bytecnt = sgreq.bytecnt;
1054 c_oil->cc.wrong_if = sgreq.wrong_if;
1055
1056 return;
1057 }