blob: 820b0efc182c85919b1a508e20aec689c3b65368 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
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
20 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "zebra/rib.h"
26
27#include "log.h"
28#include "prefix.h"
29#include "zclient.h"
30#include "stream.h"
31#include "network.h"
32
33#include "pimd.h"
34#include "pim_pim.h"
35#include "pim_zebra.h"
36#include "pim_iface.h"
37#include "pim_str.h"
38#include "pim_oil.h"
39#include "pim_rpf.h"
40#include "pim_time.h"
41#include "pim_join.h"
42#include "pim_zlookup.h"
43#include "pim_ifchannel.h"
44
45#undef PIM_DEBUG_IFADDR_DUMP
46#define PIM_DEBUG_IFADDR_DUMP
47
48static int fib_lookup_if_vif_index(struct in_addr addr);
49static int del_oif(struct channel_oil *channel_oil,
50 struct interface *oif,
51 uint32_t proto_mask);
52
53/* Router-id update message from zebra. */
54static int pim_router_id_update_zebra(int command, struct zclient *zclient,
55 zebra_size_t length)
56{
57 struct prefix router_id;
58
59 /* FIXME: actually use router_id for anything ? */
60 zebra_router_id_update_read(zclient->ibuf, &router_id);
61
62 return 0;
63}
64
65static int pim_zebra_if_add(int command, struct zclient *zclient,
66 zebra_size_t length)
67{
68 struct interface *ifp;
69
70 /*
71 zebra api adds/dels interfaces using the same call
72 interface_add_read below, see comments in lib/zclient.c
73 */
74 ifp = zebra_interface_add_read(zclient->ibuf);
75 if (!ifp)
76 return 0;
77
78 if (PIM_DEBUG_ZEBRA) {
79 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
80 __PRETTY_FUNCTION__,
81 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
82 ifp->mtu, if_is_operative(ifp));
83 }
84
85 if (if_is_operative(ifp))
86 pim_if_addr_add_all(ifp);
87
88 return 0;
89}
90
91static int pim_zebra_if_del(int command, struct zclient *zclient,
92 zebra_size_t length)
93{
94 struct interface *ifp;
95
96 /*
97 zebra api adds/dels interfaces using the same call
98 interface_add_read below, see comments in lib/zclient.c
99 */
100 ifp = zebra_interface_add_read(zclient->ibuf);
101 if (!ifp)
102 return 0;
103
104 if (PIM_DEBUG_ZEBRA) {
105 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
106 __PRETTY_FUNCTION__,
107 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
108 ifp->mtu, if_is_operative(ifp));
109 }
110
111 if (!if_is_operative(ifp))
112 pim_if_addr_del_all(ifp);
113
114 return 0;
115}
116
117static int pim_zebra_if_state_up(int command, struct zclient *zclient,
118 zebra_size_t length)
119{
120 struct interface *ifp;
121
122 /*
123 zebra api notifies interface up/down events by using the same call
124 interface_add_read below, see comments in lib/zclient.c
125 */
126 ifp = zebra_interface_state_read(zclient->ibuf);
127 if (!ifp)
128 return 0;
129
Everton Marquese96f0af2009-08-11 15:48:02 -0300130 zlog_info("INTERFACE UP: %s", ifp->name);
131
Everton Marques871dbcf2009-08-11 15:43:05 -0300132 if (PIM_DEBUG_ZEBRA) {
133 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
134 __PRETTY_FUNCTION__,
135 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
136 ifp->mtu, if_is_operative(ifp));
137 }
138
139 if (if_is_operative(ifp)) {
140 /*
141 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
142 */
143 pim_if_addr_add_all(ifp);
144 }
145
146 return 0;
147}
148
149static int pim_zebra_if_state_down(int command, struct zclient *zclient,
150 zebra_size_t length)
151{
152 struct interface *ifp;
153
154 /*
155 zebra api notifies interface up/down events by using the same call
156 interface_add_read below, see comments in lib/zclient.c
157 */
158 ifp = zebra_interface_state_read(zclient->ibuf);
159 if (!ifp)
160 return 0;
161
Everton Marquese96f0af2009-08-11 15:48:02 -0300162 zlog_info("INTERFACE DOWN: %s", ifp->name);
163
Everton Marques871dbcf2009-08-11 15:43:05 -0300164 if (PIM_DEBUG_ZEBRA) {
165 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
166 __PRETTY_FUNCTION__,
167 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
168 ifp->mtu, if_is_operative(ifp));
169 }
170
171 if (!if_is_operative(ifp)) {
172 /*
173 pim_if_addr_del_all() suffices for shutting down IGMP,
174 but not for shutting down PIM
175 */
176 pim_if_addr_del_all(ifp);
177
178 /*
179 pim_sock_delete() closes the socket, stops read and timer threads,
180 and kills all neighbors.
181 */
Everton Marquese96f0af2009-08-11 15:48:02 -0300182 if (ifp->info) {
183 pim_sock_delete(ifp, "link down");
184 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300185 }
186
187 return 0;
188}
189
190#ifdef PIM_DEBUG_IFADDR_DUMP
191static void dump_if_address(struct interface *ifp)
192{
193 struct connected *ifc;
194 struct listnode *node;
195
196 zlog_debug("%s %s: interface %s addresses:",
197 __FILE__, __PRETTY_FUNCTION__,
198 ifp->name);
199
200 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
201 struct prefix *p = ifc->address;
202
203 if (p->family != AF_INET)
204 continue;
205
206 zlog_debug("%s %s: interface %s address %s",
207 __FILE__, __PRETTY_FUNCTION__,
208 ifp->name,
209 inet_ntoa(p->u.prefix4));
210 }
211}
212#endif
213
214static int pim_zebra_if_address_add(int command, struct zclient *zclient,
215 zebra_size_t length)
216{
217 struct connected *c;
218 struct prefix *p;
219
220 zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD);
221
222 /*
223 zebra api notifies address adds/dels events by using the same call
224 interface_add_read below, see comments in lib/zclient.c
225
226 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
227 will add address to interface list by calling
228 connected_add_by_prefix()
229 */
230 c = zebra_interface_address_read(command, zclient->ibuf);
231 if (!c)
232 return 0;
233
234 p = c->address;
235 if (p->family != AF_INET)
236 return 0;
237
238 if (PIM_DEBUG_ZEBRA) {
239 char buf[BUFSIZ];
240 prefix2str(p, buf, BUFSIZ);
241 zlog_debug("%s: %s connected IP address %s flags %u",
242 __PRETTY_FUNCTION__,
243 c->ifp->name, buf, c->flags);
244
245#ifdef PIM_DEBUG_IFADDR_DUMP
246 dump_if_address(c->ifp);
247#endif
248 }
249
250 pim_if_addr_add(c);
251
252 return 0;
253}
254
255static int pim_zebra_if_address_del(int command, struct zclient *client,
256 zebra_size_t length)
257{
258 struct connected *c;
259 struct prefix *p;
260
261 zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE);
262
263 /*
264 zebra api notifies address adds/dels events by using the same call
265 interface_add_read below, see comments in lib/zclient.c
266
267 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
268 will remove address from interface list by calling
269 connected_delete_by_prefix()
270 */
271 c = zebra_interface_address_read(command, client->ibuf);
272 if (!c)
273 return 0;
274
275 p = c->address;
276 if (p->family != AF_INET)
277 return 0;
278
279 if (PIM_DEBUG_ZEBRA) {
280 char buf[BUFSIZ];
281 prefix2str(p, buf, BUFSIZ);
282 zlog_debug("%s: %s disconnected IP address %s flags %u",
283 __PRETTY_FUNCTION__,
284 c->ifp->name, buf, c->flags);
285
286#ifdef PIM_DEBUG_IFADDR_DUMP
287 dump_if_address(c->ifp);
288#endif
289 }
290
291 pim_if_addr_del(c);
292
293 return 0;
294}
295
296static void scan_upstream_rpf_cache()
297{
298 struct listnode *up_node;
299 struct listnode *up_nextnode;
300 struct pim_upstream *up;
301
302 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
303 struct in_addr old_rpf_addr;
304 enum pim_rpf_result rpf_result;
305
306 rpf_result = pim_rpf_update(up, &old_rpf_addr);
307 if (rpf_result == PIM_RPF_FAILURE)
308 continue;
309
310 if (rpf_result == PIM_RPF_CHANGED) {
311
312 if (up->join_state == PIM_UPSTREAM_JOINED) {
313
314 /*
315 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
316
317 Transitions from Joined State
318
319 RPF'(S,G) changes not due to an Assert
320
321 The upstream (S,G) state machine remains in Joined
322 state. Send Join(S,G) to the new upstream neighbor, which is
323 the new value of RPF'(S,G). Send Prune(S,G) to the old
324 upstream neighbor, which is the old value of RPF'(S,G). Set
325 the Join Timer (JT) to expire after t_periodic seconds.
326 */
327
328
329 /* send Prune(S,G) to the old upstream neighbor */
330 pim_joinprune_send(up->rpf.source_nexthop.interface,
331 old_rpf_addr,
332 up->source_addr,
333 up->group_addr,
334 0 /* prune */);
335
336 /* send Join(S,G) to the current upstream neighbor */
337 pim_joinprune_send(up->rpf.source_nexthop.interface,
338 up->rpf.rpf_addr,
339 up->source_addr,
340 up->group_addr,
341 1 /* join */);
342
343 pim_upstream_join_timer_restart(up);
344 } /* up->join_state == PIM_UPSTREAM_JOINED */
345
346 /* FIXME can join_desired actually be changed by pim_rpf_update()
347 returning PIM_RPF_CHANGED ? */
348 pim_upstream_update_join_desired(up);
349
350 } /* PIM_RPF_CHANGED */
351
352 } /* for (qpim_upstream_list) */
353
354}
355
Everton Marquesf24200d2014-02-14 16:40:34 -0200356void pim_scan_oil()
Everton Marques871dbcf2009-08-11 15:43:05 -0300357{
358 struct listnode *node;
359 struct listnode *nextnode;
360 struct channel_oil *c_oil;
361
Everton Marquesf24200d2014-02-14 16:40:34 -0200362 qpim_scan_oil_last = pim_time_monotonic_sec();
363 ++qpim_scan_oil_events;
364
Everton Marques871dbcf2009-08-11 15:43:05 -0300365 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
366 int old_vif_index;
367 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
368 if (input_iface_vif_index < 1) {
369 char source_str[100];
370 char group_str[100];
371 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
372 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
373 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
374 __FILE__, __PRETTY_FUNCTION__,
375 source_str, group_str);
376 continue;
377 }
378
379 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
380 /* RPF unchanged */
381 continue;
382 }
383
384 if (PIM_DEBUG_ZEBRA) {
385 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
386 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
387 char source_str[100];
388 char group_str[100];
389 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
390 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
391 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
392 __FILE__, __PRETTY_FUNCTION__,
393 source_str, group_str,
394 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
395 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
396 }
397
398 /* new iif loops to existing oif ? */
399 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
400 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
401
402 if (PIM_DEBUG_ZEBRA) {
403 char source_str[100];
404 char group_str[100];
405 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
406 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
407 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
408 __FILE__, __PRETTY_FUNCTION__,
409 source_str, group_str,
410 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
411 }
412
413 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
414 }
415
416 /* update iif vif_index */
417 old_vif_index = c_oil->oil.mfcc_parent;
418 c_oil->oil.mfcc_parent = input_iface_vif_index;
419
420 /* update kernel multicast forwarding cache (MFC) */
421 if (pim_mroute_add(&c_oil->oil)) {
422 /* just log warning */
423 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
424 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
425 char source_str[100];
426 char group_str[100];
427 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
428 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
429 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
430 __FILE__, __PRETTY_FUNCTION__,
431 source_str, group_str,
432 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
433 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
434 continue;
435 }
436
437 } /* for (qpim_channel_oil_list) */
438}
439
440static int on_rpf_cache_refresh(struct thread *t)
441{
442 zassert(t);
443 zassert(qpim_rpf_cache_refresher);
444
445 qpim_rpf_cache_refresher = 0;
446
447 /* update PIM protocol state */
448 scan_upstream_rpf_cache();
449
450 /* update kernel multicast forwarding cache (MFC) */
Everton Marquesf24200d2014-02-14 16:40:34 -0200451 pim_scan_oil();
Everton Marques871dbcf2009-08-11 15:43:05 -0300452
Everton Marquesbcc4abe2009-08-17 18:18:59 -0300453 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
Everton Marques613938d2009-08-13 15:39:31 -0300454 ++qpim_rpf_cache_refresh_events;
455
Everton Marques871dbcf2009-08-11 15:43:05 -0300456 return 0;
457}
458
459static void sched_rpf_cache_refresh()
460{
Everton Marques613938d2009-08-13 15:39:31 -0300461 ++qpim_rpf_cache_refresh_requests;
462
463 if (qpim_rpf_cache_refresher) {
464 /* Refresh timer is already running */
Everton Marques871dbcf2009-08-11 15:43:05 -0300465 return;
Everton Marques613938d2009-08-13 15:39:31 -0300466 }
467
468 /* Start refresh timer */
Everton Marques871dbcf2009-08-11 15:43:05 -0300469
470 if (PIM_DEBUG_ZEBRA) {
471 zlog_debug("%s: triggering %ld msec timer",
472 __PRETTY_FUNCTION__,
473 qpim_rpf_cache_refresh_delay_msec);
474 }
475
476 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
477 on_rpf_cache_refresh,
478 0, qpim_rpf_cache_refresh_delay_msec);
479}
480
481static int redist_read_ipv4_route(int command, struct zclient *zclient,
482 zebra_size_t length)
483{
484 struct stream *s;
485 struct zapi_ipv4 api;
486 unsigned long ifindex;
487 struct in_addr nexthop;
488 struct prefix_ipv4 p;
489 int min_len = 4;
490
491 if (length < min_len) {
492 zlog_warn("%s %s: short buffer: length=%d min=%d",
493 __FILE__, __PRETTY_FUNCTION__,
494 length, min_len);
495 return -1;
496 }
497
498 s = zclient->ibuf;
499 ifindex = 0;
500 nexthop.s_addr = 0;
501
502 /* Type, flags, message. */
503 api.type = stream_getc(s);
504 api.flags = stream_getc(s);
505 api.message = stream_getc(s);
506
507 /* IPv4 prefix length. */
508 memset(&p, 0, sizeof(struct prefix_ipv4));
509 p.family = AF_INET;
510 p.prefixlen = stream_getc(s);
511
512 min_len +=
513 PSIZE(p.prefixlen) +
514 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
515 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
516 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
517 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
518
519 if (PIM_DEBUG_ZEBRA) {
520 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
521 __FILE__, __PRETTY_FUNCTION__,
522 length, min_len,
523 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
524 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
525 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
526 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
527 }
528
529 if (length < min_len) {
530 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
531 __FILE__, __PRETTY_FUNCTION__,
532 length, min_len,
533 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
534 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
535 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
536 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
537 return -1;
538 }
539
540 /* IPv4 prefix. */
541 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
542
543 /* Nexthop, ifindex, distance, metric. */
544 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
545 api.nexthop_num = stream_getc(s);
546 nexthop.s_addr = stream_get_ipv4(s);
547 }
548 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
549 api.ifindex_num = stream_getc(s);
550 ifindex = stream_getl(s);
551 }
552
553 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
David Lamparter105ad862012-02-16 04:50:35 +0000554 stream_getc(s) :
Everton Marques871dbcf2009-08-11 15:43:05 -0300555 0;
556
557 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
558 stream_getl(s) :
559 0;
560
561 switch (command) {
562 case ZEBRA_IPV4_ROUTE_ADD:
563 if (PIM_DEBUG_ZEBRA) {
564 char buf[2][INET_ADDRSTRLEN];
565 zlog_debug("%s: add %s %s/%d "
566 "nexthop %s ifindex %ld metric%s %u distance%s %u",
567 __PRETTY_FUNCTION__,
568 zebra_route_string(api.type),
569 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
570 p.prefixlen,
571 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
572 ifindex,
573 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
574 api.metric,
575 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
576 api.distance);
577 }
578 break;
579 case ZEBRA_IPV4_ROUTE_DELETE:
580 if (PIM_DEBUG_ZEBRA) {
581 char buf[2][INET_ADDRSTRLEN];
582 zlog_debug("%s: delete %s %s/%d "
583 "nexthop %s ifindex %ld metric%s %u distance%s %u",
584 __PRETTY_FUNCTION__,
585 zebra_route_string(api.type),
586 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
587 p.prefixlen,
588 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
589 ifindex,
590 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
591 api.metric,
592 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
593 api.distance);
594 }
595 break;
596 default:
597 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
598 return -1;
599 }
600
601 sched_rpf_cache_refresh();
602
603 return 0;
604}
605
606void pim_zebra_init()
607{
608 struct zclient *zclient;
609 int i;
610
611#ifdef HAVE_TCP_ZEBRA
612 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
613#else
614 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", ZEBRA_SERV_PATH);
615#endif
616
617 /* Socket for receiving updates from Zebra daemon */
618 zclient = zclient_new();
619
620 zclient->router_id_update = pim_router_id_update_zebra;
621 zclient->interface_add = pim_zebra_if_add;
622 zclient->interface_delete = pim_zebra_if_del;
623 zclient->interface_up = pim_zebra_if_state_up;
624 zclient->interface_down = pim_zebra_if_state_down;
625 zclient->interface_address_add = pim_zebra_if_address_add;
626 zclient->interface_address_delete = pim_zebra_if_address_del;
627 zclient->ipv4_route_add = redist_read_ipv4_route;
628 zclient->ipv4_route_delete = redist_read_ipv4_route;
629
630 zclient_init(zclient, ZEBRA_ROUTE_PIM);
631 zlog_info("zclient_init cleared redistribution request");
632
633 zassert(zclient->redist_default == ZEBRA_ROUTE_PIM);
634
635 /* Request all redistribution */
636 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
637 if (i == zclient->redist_default)
638 continue;
639 zclient->redist[i] = 1;
640 zlog_info("%s: requesting redistribution for %s (%i)",
641 __PRETTY_FUNCTION__, zebra_route_string(i), i);
642 }
643
644 /* Request default information */
645 zclient->default_information = 1;
646 zlog_info("%s: requesting default information redistribution",
647 __PRETTY_FUNCTION__);
648
649 zlog_notice("%s: zclient update socket initialized",
650 __PRETTY_FUNCTION__);
651
652 zassert(!qpim_zclient_lookup);
653 qpim_zclient_lookup = zclient_lookup_new();
654 zassert(qpim_zclient_lookup);
655}
656
657void igmp_anysource_forward_start(struct igmp_group *group)
658{
659 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
660 zassert(group->group_filtermode_isexcl);
661 zassert(listcount(group->group_source_list) < 1);
662
663 if (PIM_DEBUG_IGMP_TRACE) {
664 zlog_debug("%s %s: UNIMPLEMENTED",
665 __FILE__, __PRETTY_FUNCTION__);
666 }
667}
668
669void igmp_anysource_forward_stop(struct igmp_group *group)
670{
671 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
672 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
673
674 if (PIM_DEBUG_IGMP_TRACE) {
675 zlog_debug("%s %s: UNIMPLEMENTED",
676 __FILE__, __PRETTY_FUNCTION__);
677 }
678}
679
680static int fib_lookup_if_vif_index(struct in_addr addr)
681{
682 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
683 int num_ifindex;
684 int vif_index;
685 int first_ifindex;
686
687 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
688 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
689 PIM_NEXTHOP_LOOKUP_MAX);
690 if (num_ifindex < 1) {
691 char addr_str[100];
692 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
693 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
694 __FILE__, __PRETTY_FUNCTION__,
695 addr_str);
696 return -1;
697 }
698
699 first_ifindex = nexthop_tab[0].ifindex;
700
701 if (num_ifindex > 1) {
702 char addr_str[100];
703 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
704 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
705 __FILE__, __PRETTY_FUNCTION__,
706 num_ifindex, addr_str, first_ifindex);
707 /* debug warning only, do not return */
708 }
709
710 if (PIM_DEBUG_ZEBRA) {
711 char addr_str[100];
712 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
713 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
714 __FILE__, __PRETTY_FUNCTION__,
715 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
716 }
717
718 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
719
720 if (vif_index < 1) {
721 char addr_str[100];
722 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
723 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
724 __FILE__, __PRETTY_FUNCTION__,
725 vif_index, addr_str);
726 return -2;
727 }
728
729 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
730
731 if (vif_index > qpim_mroute_oif_highest_vif_index) {
732 char addr_str[100];
733 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
734 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
735 __FILE__, __PRETTY_FUNCTION__,
736 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
737
738 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
739 __FILE__, __PRETTY_FUNCTION__,
740 ifindex2ifname(vif_index),
741 vif_index);
742
743 return -3;
744 }
745
746 return vif_index;
747}
748
749static int add_oif(struct channel_oil *channel_oil,
750 struct interface *oif,
751 uint32_t proto_mask)
752{
753 struct pim_interface *pim_ifp;
754 int old_ttl;
755
756 zassert(channel_oil);
757
758 pim_ifp = oif->info;
759
Everton Marques67faabc2010-02-23 12:11:11 -0300760 if (PIM_DEBUG_MROUTE) {
761 char group_str[100];
762 char source_str[100];
763 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
764 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
765 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
766 __FILE__, __PRETTY_FUNCTION__,
767 source_str, group_str,
768 proto_mask, oif->name, pim_ifp->mroute_vif_index);
769 }
770
Everton Marques871dbcf2009-08-11 15:43:05 -0300771 if (pim_ifp->mroute_vif_index < 1) {
772 zlog_warn("%s %s: interface %s vif_index=%d < 1",
773 __FILE__, __PRETTY_FUNCTION__,
774 oif->name, pim_ifp->mroute_vif_index);
775 return -1;
776 }
777
778#ifdef PIM_ENFORCE_LOOPFREE_MFC
779 /*
780 Prevent creating MFC entry with OIF=IIF.
781
782 This is a protection against implementation mistakes.
783
784 PIM protocol implicitely ensures loopfree multicast topology.
785
786 IGMP must be protected against adding looped MFC entries created
787 by both source and receiver attached to the same interface. See
788 TODO T22.
789 */
790 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
791 char group_str[100];
792 char source_str[100];
793 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
794 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
795 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
796 __FILE__, __PRETTY_FUNCTION__,
797 proto_mask, oif->name, pim_ifp->mroute_vif_index,
798 source_str, group_str);
799 return -2;
800 }
801#endif
802
803 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
804 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
805
806 /* Prevent single protocol from subscribing same interface to
807 channel (S,G) multiple times */
808 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
809 char group_str[100];
810 char source_str[100];
811 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
812 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
813 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
814 __FILE__, __PRETTY_FUNCTION__,
815 proto_mask, oif->name, pim_ifp->mroute_vif_index,
816 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
817 source_str, group_str);
818 return -3;
819 }
820
821 /* Allow other protocol to request subscription of same interface to
822 channel (S,G) multiple times, by silently ignoring further
823 requests */
824 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
825
826 /* Check the OIF really exists before returning, and only log
827 warning otherwise */
828 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
829 char group_str[100];
830 char source_str[100];
831 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
832 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
833 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
834 __FILE__, __PRETTY_FUNCTION__,
835 proto_mask, oif->name, pim_ifp->mroute_vif_index,
836 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
837 source_str, group_str);
838 }
839
840 return 0;
841 }
842
843 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
844
845 if (old_ttl > 0) {
846 char group_str[100];
847 char source_str[100];
848 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
849 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
850 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
851 __FILE__, __PRETTY_FUNCTION__,
852 oif->name, pim_ifp->mroute_vif_index,
853 source_str, group_str);
854 return -4;
855 }
856
857 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
858
859 if (pim_mroute_add(&channel_oil->oil)) {
860 char group_str[100];
861 char source_str[100];
862 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
863 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
864 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
865 __FILE__, __PRETTY_FUNCTION__,
866 oif->name, pim_ifp->mroute_vif_index,
867 source_str, group_str);
868
869 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
870 return -5;
871 }
872
873 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
874 ++channel_oil->oil_size;
875 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
876
Everton Marques67faabc2010-02-23 12:11:11 -0300877 if (PIM_DEBUG_MROUTE) {
878 char group_str[100];
879 char source_str[100];
880 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
881 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
882 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
883 __FILE__, __PRETTY_FUNCTION__,
884 source_str, group_str,
885 proto_mask, oif->name, pim_ifp->mroute_vif_index);
886 }
887
Everton Marques871dbcf2009-08-11 15:43:05 -0300888 return 0;
889}
890
891static int del_oif(struct channel_oil *channel_oil,
892 struct interface *oif,
893 uint32_t proto_mask)
894{
895 struct pim_interface *pim_ifp;
896 int old_ttl;
897
898 zassert(channel_oil);
899
900 pim_ifp = oif->info;
901
902 zassert(pim_ifp->mroute_vif_index >= 1);
903 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
904 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
905
Everton Marques67faabc2010-02-23 12:11:11 -0300906 if (PIM_DEBUG_MROUTE) {
907 char group_str[100];
908 char source_str[100];
909 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
910 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
911 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
912 __FILE__, __PRETTY_FUNCTION__,
913 source_str, group_str,
914 proto_mask, oif->name, pim_ifp->mroute_vif_index);
915 }
916
Everton Marques871dbcf2009-08-11 15:43:05 -0300917 /* Prevent single protocol from unsubscribing same interface from
918 channel (S,G) multiple times */
919 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
920 char group_str[100];
921 char source_str[100];
922 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
923 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
924 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
925 __FILE__, __PRETTY_FUNCTION__,
926 proto_mask, oif->name, pim_ifp->mroute_vif_index,
927 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
928 source_str, group_str);
929 return -2;
930 }
931
932 /* Mark that protocol is no longer interested in this OIF */
933 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
934
935 /* Allow multiple protocols to unsubscribe same interface from
936 channel (S,G) multiple times, by silently ignoring requests while
937 there is at least one protocol interested in the channel */
938 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
939
940 /* Check the OIF keeps existing before returning, and only log
941 warning otherwise */
942 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
943 char group_str[100];
944 char source_str[100];
945 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
946 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
947 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
948 __FILE__, __PRETTY_FUNCTION__,
949 proto_mask, oif->name, pim_ifp->mroute_vif_index,
950 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
951 source_str, group_str);
952 }
953
954 return 0;
955 }
956
957 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
958
959 if (old_ttl < 1) {
960 char group_str[100];
961 char source_str[100];
962 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
963 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
964 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
965 __FILE__, __PRETTY_FUNCTION__,
966 oif->name, pim_ifp->mroute_vif_index,
967 source_str, group_str);
968 return -3;
969 }
970
971 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
972
973 if (pim_mroute_add(&channel_oil->oil)) {
974 char group_str[100];
975 char source_str[100];
976 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
977 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
978 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
979 __FILE__, __PRETTY_FUNCTION__,
980 oif->name, pim_ifp->mroute_vif_index,
981 source_str, group_str);
982
983 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
984 return -4;
985 }
986
987 --channel_oil->oil_size;
988
989 if (channel_oil->oil_size < 1) {
990 if (pim_mroute_del(&channel_oil->oil)) {
991 /* just log a warning in case of failure */
992 char group_str[100];
993 char source_str[100];
994 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
995 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
996 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
997 __FILE__, __PRETTY_FUNCTION__,
998 source_str, group_str);
999 }
1000 }
1001
Everton Marques67faabc2010-02-23 12:11:11 -03001002 if (PIM_DEBUG_MROUTE) {
1003 char group_str[100];
1004 char source_str[100];
1005 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1006 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1007 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1008 __FILE__, __PRETTY_FUNCTION__,
1009 source_str, group_str,
1010 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1011 }
1012
Everton Marques871dbcf2009-08-11 15:43:05 -03001013 return 0;
1014}
1015
1016void igmp_source_forward_start(struct igmp_source *source)
1017{
1018 struct igmp_group *group;
1019
1020 if (PIM_DEBUG_IGMP_TRACE) {
1021 char source_str[100];
1022 char group_str[100];
1023 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1024 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1025 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1026 __PRETTY_FUNCTION__,
1027 source_str, group_str,
1028 source->source_group->group_igmp_sock->fd,
1029 source->source_group->group_igmp_sock->interface->name,
1030 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1031 }
1032
1033 /* Prevent IGMP interface from installing multicast route multiple
1034 times */
1035 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1036 return;
1037 }
1038
1039 group = source->source_group;
1040
1041 if (!source->source_channel_oil) {
1042 struct pim_interface *pim_oif;
1043 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1044 if (input_iface_vif_index < 1) {
1045 char source_str[100];
1046 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1047 zlog_warn("%s %s: could not find input interface for source %s",
1048 __FILE__, __PRETTY_FUNCTION__,
1049 source_str);
1050 return;
1051 }
1052
1053 /*
1054 Protect IGMP against adding looped MFC entries created by both
1055 source and receiver attached to the same interface. See TODO
1056 T22.
1057 */
1058 pim_oif = source->source_group->group_igmp_sock->interface->info;
1059 if (!pim_oif) {
1060 zlog_warn("%s: multicast not enabled on oif=%s ?",
1061 __PRETTY_FUNCTION__,
1062 source->source_group->group_igmp_sock->interface->name);
1063 return;
1064 }
1065 if (pim_oif->mroute_vif_index < 1) {
1066 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1067 __FILE__, __PRETTY_FUNCTION__,
1068 source->source_group->group_igmp_sock->interface->name,
1069 pim_oif->mroute_vif_index);
1070 return;
1071 }
1072 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1073 /* ignore request for looped MFC entry */
1074 if (PIM_DEBUG_IGMP_TRACE) {
1075 char source_str[100];
1076 char group_str[100];
1077 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1078 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1079 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1080 __PRETTY_FUNCTION__,
1081 source_str, group_str,
1082 source->source_group->group_igmp_sock->fd,
1083 source->source_group->group_igmp_sock->interface->name,
1084 input_iface_vif_index);
1085 }
1086 return;
1087 }
1088
1089 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1090 source->source_addr,
1091 input_iface_vif_index);
1092 if (!source->source_channel_oil) {
1093 char group_str[100];
1094 char source_str[100];
1095 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1096 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1097 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1098 __FILE__, __PRETTY_FUNCTION__,
1099 source_str, group_str);
1100 return;
1101 }
1102 }
1103
1104 if (add_oif(source->source_channel_oil,
1105 group->group_igmp_sock->interface,
1106 PIM_OIF_FLAG_PROTO_IGMP)) {
1107 return;
1108 }
1109
1110 /*
1111 Feed IGMPv3-gathered local membership information into PIM
1112 per-interface (S,G) state.
1113 */
1114 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1115 source->source_addr, group->group_addr);
1116
1117 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1118}
1119
1120void igmp_source_forward_stop(struct igmp_source *source)
1121{
1122 struct igmp_group *group;
1123
1124 if (PIM_DEBUG_IGMP_TRACE) {
1125 char source_str[100];
1126 char group_str[100];
1127 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1128 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1129 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1130 __PRETTY_FUNCTION__,
1131 source_str, group_str,
1132 source->source_group->group_igmp_sock->fd,
1133 source->source_group->group_igmp_sock->interface->name,
1134 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1135 }
1136
1137 /* Prevent IGMP interface from removing multicast route multiple
1138 times */
1139 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1140 return;
1141 }
1142
1143 group = source->source_group;
1144
1145 if (del_oif(source->source_channel_oil,
1146 group->group_igmp_sock->interface,
1147 PIM_OIF_FLAG_PROTO_IGMP)) {
1148 return;
1149 }
1150
1151 /*
1152 Feed IGMPv3-gathered local membership information into PIM
1153 per-interface (S,G) state.
1154 */
1155 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1156 source->source_addr, group->group_addr);
1157
1158 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1159}
1160
1161void pim_forward_start(struct pim_ifchannel *ch)
1162{
1163 struct pim_upstream *up = ch->upstream;
1164
1165 if (PIM_DEBUG_PIM_TRACE) {
1166 char source_str[100];
1167 char group_str[100];
1168 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1169 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1170 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1171 __PRETTY_FUNCTION__,
1172 source_str, group_str, ch->interface->name);
1173 }
1174
1175 if (!up->channel_oil) {
1176 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1177 if (input_iface_vif_index < 1) {
1178 char source_str[100];
1179 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1180 zlog_warn("%s %s: could not find input interface for source %s",
1181 __FILE__, __PRETTY_FUNCTION__,
1182 source_str);
1183 return;
1184 }
1185
1186 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1187 input_iface_vif_index);
1188 if (!up->channel_oil) {
1189 char group_str[100];
1190 char source_str[100];
1191 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1192 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1193 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1194 __FILE__, __PRETTY_FUNCTION__,
1195 source_str, group_str);
1196 return;
1197 }
1198 }
1199
1200 add_oif(up->channel_oil,
1201 ch->interface,
1202 PIM_OIF_FLAG_PROTO_PIM);
1203}
1204
1205void pim_forward_stop(struct pim_ifchannel *ch)
1206{
1207 struct pim_upstream *up = ch->upstream;
1208
1209 if (PIM_DEBUG_PIM_TRACE) {
1210 char source_str[100];
1211 char group_str[100];
1212 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1213 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1214 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1215 __PRETTY_FUNCTION__,
1216 source_str, group_str, ch->interface->name);
1217 }
1218
1219 if (!up->channel_oil) {
1220 char source_str[100];
1221 char group_str[100];
1222 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1223 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1224 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1225 __PRETTY_FUNCTION__,
1226 source_str, group_str, ch->interface->name);
1227
1228 return;
1229 }
1230
1231 del_oif(up->channel_oil,
1232 ch->interface,
1233 PIM_OIF_FLAG_PROTO_PIM);
1234}