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