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