]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_mroute.c
lib, pimd: Fix borked up prefix code
[mirror_frr.git] / pimd / pim_mroute.c
CommitLineData
12e41d03
DL
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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
12e41d03
DL
20*/
21
22#include <zebra.h>
23#include "log.h"
24#include "privs.h"
744d91b3 25#include "if.h"
065bee4b 26#include "prefix.h"
12e41d03
DL
27
28#include "pimd.h"
29#include "pim_mroute.h"
37653d4f 30#include "pim_oil.h"
12e41d03
DL
31#include "pim_str.h"
32#include "pim_time.h"
33#include "pim_iface.h"
34#include "pim_macro.h"
c8ae3ce8 35#include "pim_rp.h"
59471fb8 36#include "pim_oil.h"
998af219 37#include "pim_register.h"
56638739 38#include "pim_ifchannel.h"
12e41d03
DL
39
40/* GLOBAL VARS */
41extern struct zebra_privs_t pimd_privs;
42
43static void mroute_read_on(void);
44
45static int pim_mroute_set(int fd, int enable)
46{
47 int err;
48 int opt = enable ? MRT_INIT : MRT_DONE;
49 socklen_t opt_len = sizeof(opt);
50
51 err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
52 if (err) {
12e41d03
DL
53 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
54 __FILE__, __PRETTY_FUNCTION__,
3d7765d7 55 fd, enable ? "MRT_INIT" : "MRT_DONE", opt, errno, safe_strerror(errno));
12e41d03
DL
56 return -1;
57 }
58
12e41d03
DL
59 return 0;
60}
61
065bee4b
DS
62static int
63pim_mroute_connected_to_source (struct interface *ifp, struct in_addr src)
64{
65 struct listnode *cnode;
66 struct connected *c;
67 struct prefix p;
68
69 p.family = AF_INET;
70 p.u.prefix4 = src;
71 p.prefixlen = IPV4_MAX_BITLEN;
72
73 for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
74 {
75 if ((c->address->family == AF_INET) &&
76 prefix_match (CONNECTED_PREFIX (c), &p))
77 {
78 return 1;
79 }
80 }
81
82 return 0;
83}
84
e355e30f
DS
85static const char *igmpmsgtype2str[IGMPMSG_WHOLEPKT + 1] = {
86 "<unknown_upcall?>",
87 "NOCACHE",
88 "WRONGVIF",
89 "WHOLEPKT", };
90
91static int
92pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg,
93 const char *src_str, const char *grp_str)
12e41d03 94{
04b40f02 95 struct pim_interface *pim_ifp = ifp->info;
59471fb8 96 struct pim_upstream *up;
065bee4b 97 struct pim_rpf *rpg;
4ed0af70 98 struct prefix_sg sg;
04b40f02 99
c8ae3ce8 100 rpg = RP(msg->im_dst);
04b40f02
DS
101 /*
102 * If the incoming interface is unknown OR
103 * the Interface type is SSM we don't need to
104 * do anything here
105 */
ed66602c 106 if ((rpg->rpf_addr.s_addr == INADDR_NONE) ||
04b40f02 107 (!pim_ifp) ||
b45fd505 108 (!(PIM_I_am_DR(pim_ifp))) ||
04b40f02
DS
109 (pim_ifp->itype == PIM_INTERFACE_SSM))
110 return 0;
111
065bee4b
DS
112 /*
113 * If we've received a multicast packet that isn't connected to
114 * us
115 */
116 if (!pim_mroute_connected_to_source (ifp, msg->im_src))
117 {
630f76b6 118 if (PIM_DEBUG_MROUTE)
065bee4b
DS
119 zlog_debug ("%s: Received incoming packet that does originate on our seg",
120 __PRETTY_FUNCTION__);
121 return 0;
122 }
123
630f76b6 124 if (PIM_DEBUG_MROUTE) {
04b40f02
DS
125 zlog_debug("%s: Adding a Route for %s from %s for WHOLEPKT consumption",
126 __PRETTY_FUNCTION__, grp_str, src_str);
127 }
8813406f 128
4ed0af70
DS
129 memset (&sg, 0, sizeof (struct prefix_sg));
130 sg.src = msg->im_src;
131 sg.grp = msg->im_dst;
5074a423 132 up = pim_upstream_add (&sg, ifp);
59471fb8 133 if (!up) {
630f76b6 134 if (PIM_DEBUG_MROUTE) {
5074a423 135 zlog_debug("%s: Failure to add upstream information for %s",
59471fb8 136 __PRETTY_FUNCTION__,
5074a423 137 pim_str_sg_dump (&sg));
59471fb8
DS
138 }
139 return 0;
140 }
141
3667e8a0
DS
142 pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD);
143
05e451f8 144 up->channel_oil = pim_channel_oil_add(&sg,
59471fb8
DS
145 pim_ifp->mroute_vif_index);
146 if (!up->channel_oil) {
630f76b6 147 if (PIM_DEBUG_MROUTE) {
59471fb8
DS
148 zlog_debug("%s: Failure to add channel oil for (%s,%s)",
149 __PRETTY_FUNCTION__,
150 src_str, grp_str);
151 }
152 return 0;
153 }
25a335e0 154 up->channel_oil->cc.pktcnt++;
56638739 155 up->fhr = 1;
8a294fa2 156 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
56638739 157 up->join_state = PIM_UPSTREAM_JOINED;
59471fb8 158
e355e30f
DS
159 return 0;
160}
12e41d03 161
e355e30f 162static int
c8ae3ce8 163pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf,
e355e30f
DS
164 const char *src_str, const char *grp_str)
165{
59471fb8 166 struct pim_interface *pim_ifp;
4ed0af70 167 struct prefix_sg sg;
ed66602c 168 struct pim_rpf *rpg;
c8ae3ce8 169 const struct ip *ip_hdr;
59471fb8 170 struct pim_upstream *up;
04b40f02 171
c8ae3ce8
DS
172 ip_hdr = (const struct ip *)buf;
173
4ed0af70
DS
174 memset (&sg, 0, sizeof (struct prefix_sg));
175 sg.src = ip_hdr->ip_src;
176 sg.grp = ip_hdr->ip_dst;
c8ae3ce8 177
5074a423 178 up = pim_upstream_find(&sg);
59471fb8 179 if (!up) {
630f76b6 180 if (PIM_DEBUG_MROUTE) {
5074a423
DS
181 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
182 __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
59471fb8
DS
183 }
184 return 0;
185 }
186
998af219
DS
187 pim_ifp = up->rpf.source_nexthop.interface->info;
188
4ed0af70 189 rpg = RP(sg.grp);
c8ae3ce8 190
ed66602c 191 if ((rpg->rpf_addr.s_addr == INADDR_NONE) ||
c8ae3ce8 192 (!pim_ifp) ||
b45fd505 193 (!(PIM_I_am_DR(pim_ifp))) ||
c8ae3ce8 194 (pim_ifp->itype == PIM_INTERFACE_SSM)) {
630f76b6 195 if (PIM_DEBUG_MROUTE) {
998af219
DS
196 zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
197 }
c8ae3ce8 198 return 0;
04b40f02 199 }
84366c7e 200
2ddab288
DS
201 /*
202 * If we've received a register suppress
203 */
204 if (!up->t_rs_timer)
b100a4f5 205 pim_register_send((uint8_t *)buf + sizeof(struct ip), ntohs (ip_hdr->ip_len), rpg, 0);
2ddab288 206
e355e30f
DS
207 return 0;
208}
12e41d03 209
e355e30f
DS
210static int
211pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg,
212 const char *src_str, const char *grp_str)
213{
214 struct pim_ifchannel *ch;
215 struct pim_interface *pim_ifp;
4ed0af70 216 struct prefix_sg sg;
12e41d03 217
e355e30f
DS
218 /*
219 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
12e41d03 220
e355e30f
DS
221 RFC 4601 4.8.2. PIM-SSM-Only Routers
222
223 iif is the incoming interface of the packet.
224 if (iif is in inherited_olist(S,G)) {
225 send Assert(S,G) on iif
226 }
227 */
12e41d03 228
e355e30f 229 if (!ifp) {
630f76b6 230 if (PIM_DEBUG_MROUTE) {
e355e30f 231 zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
12e41d03 232 __PRETTY_FUNCTION__,
e355e30f 233 src_str, grp_str, msg->im_vif);
12e41d03 234 }
e355e30f
DS
235 return -1;
236 }
12e41d03 237
e355e30f
DS
238 pim_ifp = ifp->info;
239 if (!pim_ifp) {
630f76b6 240 if (PIM_DEBUG_MROUTE) {
e355e30f
DS
241 zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s",
242 __PRETTY_FUNCTION__,
243 src_str, grp_str, ifp->name);
12e41d03 244 }
e355e30f
DS
245 return -2;
246 }
12e41d03 247
4ed0af70
DS
248 memset (&sg, 0, sizeof (struct prefix_sg));
249 sg.src = msg->im_src;
250 sg.grp = msg->im_dst;
5074a423 251 ch = pim_ifchannel_find(ifp, &sg);
e355e30f 252 if (!ch) {
630f76b6 253 if (PIM_DEBUG_MROUTE) {
e355e30f
DS
254 zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s",
255 __PRETTY_FUNCTION__,
256 src_str, grp_str, ifp->name);
12e41d03 257 }
e355e30f
DS
258 return -3;
259 }
12e41d03 260
e355e30f
DS
261 /*
262 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
263
264 Transitions from NoInfo State
265
266 An (S,G) data packet arrives on interface I, AND
267 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
268 downstream interface that is in our (S,G) outgoing interface
269 list. We optimistically assume that we will be the assert
270 winner for this (S,G), and so we transition to the "I am Assert
271 Winner" state and perform Actions A1 (below), which will
272 initiate the assert negotiation for (S,G).
273 */
12e41d03 274
e355e30f 275 if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
630f76b6 276 if (PIM_DEBUG_MROUTE) {
e355e30f
DS
277 zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s",
278 __PRETTY_FUNCTION__,
279 src_str, grp_str, ifp->name);
12e41d03 280 }
e355e30f
DS
281 return -4;
282 }
12e41d03 283
e355e30f 284 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
630f76b6 285 if (PIM_DEBUG_MROUTE) {
e355e30f
DS
286 zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel",
287 __PRETTY_FUNCTION__,
288 src_str, grp_str, ifp->name);
12e41d03 289 }
e355e30f
DS
290 return -5;
291 }
12e41d03 292
e355e30f 293 if (assert_action_a1(ch)) {
630f76b6 294 if (PIM_DEBUG_MROUTE) {
e355e30f
DS
295 zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
296 __PRETTY_FUNCTION__,
297 src_str, grp_str, ifp->name);
12e41d03 298 }
e355e30f
DS
299 return -6;
300 }
301
302 return 0;
303}
304
305int pim_mroute_msg(int fd, const char *buf, int buf_size)
306{
307 struct interface *ifp;
308 const struct ip *ip_hdr;
309 const struct igmpmsg *msg;
310 char src_str[100] = "<src?>";
311 char grp_str[100] = "<grp?>";
12e41d03 312
e355e30f
DS
313 ip_hdr = (const struct ip *) buf;
314
315 /* kernel upcall must have protocol=0 */
316 if (ip_hdr->ip_p) {
317 /* this is not a kernel upcall */
630f76b6 318 if (PIM_DEBUG_MROUTE) {
e5d33c83
DS
319 pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
320 pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str, sizeof(grp_str));
321 zlog_debug("%s: not a kernel upcall proto=%d src: %s dst: %s msg_size=%d",
322 __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size);
e355e30f 323 }
12e41d03 324 return 0;
e355e30f
DS
325 }
326
327 msg = (const struct igmpmsg *) buf;
328
329 ifp = pim_if_find_by_vif_index(msg->im_vif);
330
630f76b6 331 if (PIM_DEBUG_MROUTE) {
e355e30f
DS
332 pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
333 pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
334 zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
335 __PRETTY_FUNCTION__,
336 igmpmsgtype2str[msg->im_msgtype],
337 msg->im_msgtype,
338 ip_hdr->ip_p,
339 fd,
340 src_str,
341 grp_str,
342 ifp ? ifp->name : "<ifname?>",
343 msg->im_vif);
344 }
345
346 switch (msg->im_msgtype) {
347 case IGMPMSG_WRONGVIF:
348 return pim_mroute_msg_wrongvif(fd, ifp, msg, src_str, grp_str);
349 break;
350 case IGMPMSG_NOCACHE:
351 return pim_mroute_msg_nocache(fd, ifp, msg, src_str, grp_str);
352 break;
353 case IGMPMSG_WHOLEPKT:
9f6d6b12 354 return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg, src_str, grp_str);
e355e30f
DS
355 break;
356 default:
357 break;
358 }
12e41d03
DL
359
360 return 0;
361}
362
363static int mroute_read_msg(int fd)
364{
365 const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg));
366 char buf[1000];
367 int rd;
368
369 if (((int) sizeof(buf)) < msg_min_size) {
370 zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d",
371 __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size);
372 return -1;
373 }
374
375 rd = read(fd, buf, sizeof(buf));
376 if (rd < 0) {
377 zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
378 __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
379 return -2;
380 }
381
382 if (rd < msg_min_size) {
383 zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d",
384 __PRETTY_FUNCTION__, fd, rd, msg_min_size);
385 return -3;
386 }
387
388 return pim_mroute_msg(fd, buf, rd);
389}
390
391static int mroute_read(struct thread *t)
392{
393 int fd;
394 int result;
395
396 zassert(t);
397 zassert(!THREAD_ARG(t));
398
399 fd = THREAD_FD(t);
400 zassert(fd == qpim_mroute_socket_fd);
401
402 result = mroute_read_msg(fd);
403
404 /* Keep reading */
405 qpim_mroute_socket_reader = 0;
406 mroute_read_on();
407
408 return result;
409}
410
411static void mroute_read_on()
412{
413 zassert(!qpim_mroute_socket_reader);
414 zassert(PIM_MROUTE_IS_ENABLED);
415
416 THREAD_READ_ON(master, qpim_mroute_socket_reader,
417 mroute_read, 0, qpim_mroute_socket_fd);
418}
419
420static void mroute_read_off()
421{
422 THREAD_OFF(qpim_mroute_socket_reader);
423}
424
425int pim_mroute_socket_enable()
426{
427 int fd;
428
429 if (PIM_MROUTE_IS_ENABLED)
430 return -1;
431
432 if ( pimd_privs.change (ZPRIVS_RAISE) )
433 zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
434 safe_strerror (errno) );
435
436 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
437
438 if ( pimd_privs.change (ZPRIVS_LOWER) )
439 zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
440 safe_strerror (errno) );
441
442 if (fd < 0) {
443 zlog_warn("Could not create mroute socket: errno=%d: %s",
444 errno, safe_strerror(errno));
445 return -2;
446 }
447
448 if (pim_mroute_set(fd, 1)) {
449 zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
450 fd, errno, safe_strerror(errno));
451 close(fd);
452 return -3;
453 }
454
455 qpim_mroute_socket_fd = fd;
b45cefcb 456
12e41d03
DL
457 qpim_mroute_socket_creation = pim_time_monotonic_sec();
458 mroute_read_on();
459
12e41d03
DL
460 return 0;
461}
462
463int pim_mroute_socket_disable()
464{
465 if (PIM_MROUTE_IS_DISABLED)
466 return -1;
467
468 if (pim_mroute_set(qpim_mroute_socket_fd, 0)) {
469 zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
470 qpim_mroute_socket_fd, errno, safe_strerror(errno));
471 return -2;
472 }
473
474 if (close(qpim_mroute_socket_fd)) {
475 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
476 qpim_mroute_socket_fd, errno, safe_strerror(errno));
477 return -3;
478 }
479
480 mroute_read_off();
481 qpim_mroute_socket_fd = -1;
482
12e41d03
DL
483 return 0;
484}
485
486/*
487 For each network interface (e.g., physical or a virtual tunnel) that
488 would be used for multicast forwarding, a corresponding multicast
489 interface must be added to the kernel.
490 */
744d91b3 491int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned char flags)
12e41d03 492{
744d91b3 493 struct pim_interface *pim_ifp = ifp->info;
12e41d03
DL
494 struct vifctl vc;
495 int err;
496
497 if (PIM_MROUTE_IS_DISABLED) {
498 zlog_warn("%s: global multicast is disabled",
499 __PRETTY_FUNCTION__);
500 return -1;
501 }
502
503 memset(&vc, 0, sizeof(vc));
744d91b3 504 vc.vifc_vifi = pim_ifp->mroute_vif_index;
b3f2bf7c 505#ifdef VIFF_USE_IFINDEX
744d91b3 506 vc.vifc_lcl_ifindex = ifp->ifindex;
b3f2bf7c
RW
507#else
508 if (ifaddr.s_addr == INADDR_ANY) {
509 zlog_warn("%s: unnumbered interfaces are not supported on this platform",
510 __PRETTY_FUNCTION__);
511 return -1;
512 }
513 memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
514#endif
b45cefcb 515 vc.vifc_flags = flags;
12e41d03
DL
516 vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
517 vc.vifc_rate_limit = 0;
12e41d03
DL
518
519#ifdef PIM_DVMRP_TUNNEL
520 if (vc.vifc_flags & VIFF_TUNNEL) {
521 memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr));
522 }
523#endif
524
b45cefcb 525 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc));
12e41d03
DL
526 if (err) {
527 char ifaddr_str[100];
12e41d03
DL
528
529 pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, sizeof(ifaddr_str));
530
59471fb8 531 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
12e41d03 532 __FILE__, __PRETTY_FUNCTION__,
744d91b3 533 qpim_mroute_socket_fd, ifp->ifindex, ifaddr_str, flags,
3d7765d7 534 errno, safe_strerror(errno));
12e41d03
DL
535 return -2;
536 }
537
538 return 0;
539}
540
541int pim_mroute_del_vif(int vif_index)
542{
543 struct vifctl vc;
544 int err;
545
546 if (PIM_MROUTE_IS_DISABLED) {
547 zlog_warn("%s: global multicast is disabled",
548 __PRETTY_FUNCTION__);
549 return -1;
550 }
551
552 memset(&vc, 0, sizeof(vc));
553 vc.vifc_vifi = vif_index;
554
555 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc));
556 if (err) {
12e41d03
DL
557 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
558 __FILE__, __PRETTY_FUNCTION__,
559 qpim_mroute_socket_fd, vif_index,
3d7765d7 560 errno, safe_strerror(errno));
12e41d03
DL
561 return -2;
562 }
563
564 return 0;
565}
566
c171d6d8 567int pim_mroute_add(struct channel_oil *c_oil)
12e41d03
DL
568{
569 int err;
2ca35b3d 570 int orig = 0;
0365f56b 571 int orig_iif_vif = 0;
12e41d03
DL
572
573 qpim_mroute_add_last = pim_time_monotonic_sec();
574 ++qpim_mroute_add_events;
575
576 if (PIM_MROUTE_IS_DISABLED) {
577 zlog_warn("%s: global multicast is disabled",
578 __PRETTY_FUNCTION__);
579 return -1;
580 }
581
d3aded99
DS
582 /* The linux kernel *expects* the incoming
583 * vif to be part of the outgoing list
584 * in the case of a (*,G).
585 */
c171d6d8 586 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
d3aded99 587 {
c171d6d8
DS
588 orig = c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent];
589 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
d3aded99
DS
590 }
591
0365f56b
DS
592 /*
593 * If we have an unresolved cache entry for the S,G
594 * it is owned by the pimreg for the incoming IIF
595 * So set pimreg as the IIF temporarily to cause
596 * the packets to be forwarded. Then set it
597 * to the correct IIF afterwords.
598 */
599 if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY &&
600 c_oil->oil.mfcc_parent != 0)
601 {
602 orig_iif_vif = c_oil->oil.mfcc_parent;
603 c_oil->oil.mfcc_parent = 0;
604 }
12e41d03 605 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
c171d6d8 606 &c_oil->oil, sizeof(c_oil->oil));
d3aded99 607
0365f56b
DS
608 if (!err && !c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY &&
609 orig_iif_vif != 0)
610 {
611 c_oil->oil.mfcc_parent = orig_iif_vif;
612 err = setsockopt (qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
613 &c_oil->oil, sizeof (c_oil->oil));
614 }
615
c171d6d8
DS
616 if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
617 c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
d3aded99 618
12e41d03 619 if (err) {
12e41d03
DL
620 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
621 __FILE__, __PRETTY_FUNCTION__,
622 qpim_mroute_socket_fd,
3d7765d7 623 errno, safe_strerror(errno));
12e41d03
DL
624 return -2;
625 }
626
58302dc7 627 c_oil->installed = 1;
12e41d03
DL
628 return 0;
629}
630
c171d6d8 631int pim_mroute_del (struct channel_oil *c_oil)
12e41d03
DL
632{
633 int err;
634
635 qpim_mroute_del_last = pim_time_monotonic_sec();
636 ++qpim_mroute_del_events;
637
638 if (PIM_MROUTE_IS_DISABLED) {
639 zlog_warn("%s: global multicast is disabled",
640 __PRETTY_FUNCTION__);
641 return -1;
642 }
643
c171d6d8 644 err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil));
12e41d03 645 if (err) {
12e41d03
DL
646 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
647 __FILE__, __PRETTY_FUNCTION__,
648 qpim_mroute_socket_fd,
3d7765d7 649 errno, safe_strerror(errno));
12e41d03
DL
650 return -2;
651 }
652
58302dc7
DS
653 c_oil->installed = 0;
654
12e41d03
DL
655 return 0;
656}
3667e8a0
DS
657
658void
659pim_mroute_update_counters (struct channel_oil *c_oil)
660{
661 struct sioc_sg_req sgreq;
662
663 memset (&sgreq, 0, sizeof(sgreq));
664 sgreq.src = c_oil->oil.mfcc_origin;
665 sgreq.grp = c_oil->oil.mfcc_mcastgrp;
666
667 c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
668 c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
669 c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
670
671 if (ioctl (qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq))
672 {
673 char group_str[100];
674 char source_str[100];
675
676 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
677 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
678
679 zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s",
680 (unsigned long)SIOCGETSGCNT,
681 source_str,
682 group_str,
683 errno,
684 safe_strerror(errno));
685 return;
686 }
687
688 c_oil->cc.pktcnt = sgreq.pktcnt;
689 c_oil->cc.bytecnt = sgreq.bytecnt;
690 c_oil->cc.wrong_if = sgreq.wrong_if;
691
692 return;
693}