blob: e18b7ac92a130c27c25c3c8b1cb5837d1c78644c [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
356static void scan_oil()
357{
358 struct listnode *node;
359 struct listnode *nextnode;
360 struct channel_oil *c_oil;
361
362 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
363 int old_vif_index;
364 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
365 if (input_iface_vif_index < 1) {
366 char source_str[100];
367 char group_str[100];
368 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
369 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
370 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
371 __FILE__, __PRETTY_FUNCTION__,
372 source_str, group_str);
373 continue;
374 }
375
376 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
377 /* RPF unchanged */
378 continue;
379 }
380
381 if (PIM_DEBUG_ZEBRA) {
382 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
383 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
384 char source_str[100];
385 char group_str[100];
386 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
387 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
388 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
389 __FILE__, __PRETTY_FUNCTION__,
390 source_str, group_str,
391 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
392 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
393 }
394
395 /* new iif loops to existing oif ? */
396 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
397 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
398
399 if (PIM_DEBUG_ZEBRA) {
400 char source_str[100];
401 char group_str[100];
402 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
403 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
404 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
405 __FILE__, __PRETTY_FUNCTION__,
406 source_str, group_str,
407 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
408 }
409
410 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
411 }
412
413 /* update iif vif_index */
414 old_vif_index = c_oil->oil.mfcc_parent;
415 c_oil->oil.mfcc_parent = input_iface_vif_index;
416
417 /* update kernel multicast forwarding cache (MFC) */
418 if (pim_mroute_add(&c_oil->oil)) {
419 /* just log warning */
420 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
421 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
422 char source_str[100];
423 char group_str[100];
424 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
425 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
426 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
427 __FILE__, __PRETTY_FUNCTION__,
428 source_str, group_str,
429 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
430 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
431 continue;
432 }
433
434 } /* for (qpim_channel_oil_list) */
435}
436
437static int on_rpf_cache_refresh(struct thread *t)
438{
439 zassert(t);
440 zassert(qpim_rpf_cache_refresher);
441
442 qpim_rpf_cache_refresher = 0;
443
444 /* update PIM protocol state */
445 scan_upstream_rpf_cache();
446
447 /* update kernel multicast forwarding cache (MFC) */
448 scan_oil();
449
Everton Marquesbcc4abe2009-08-17 18:18:59 -0300450 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
Everton Marques613938d2009-08-13 15:39:31 -0300451 ++qpim_rpf_cache_refresh_events;
452
Everton Marques871dbcf2009-08-11 15:43:05 -0300453 return 0;
454}
455
456static void sched_rpf_cache_refresh()
457{
Everton Marques613938d2009-08-13 15:39:31 -0300458 ++qpim_rpf_cache_refresh_requests;
459
460 if (qpim_rpf_cache_refresher) {
461 /* Refresh timer is already running */
Everton Marques871dbcf2009-08-11 15:43:05 -0300462 return;
Everton Marques613938d2009-08-13 15:39:31 -0300463 }
464
465 /* Start refresh timer */
Everton Marques871dbcf2009-08-11 15:43:05 -0300466
467 if (PIM_DEBUG_ZEBRA) {
468 zlog_debug("%s: triggering %ld msec timer",
469 __PRETTY_FUNCTION__,
470 qpim_rpf_cache_refresh_delay_msec);
471 }
472
473 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
474 on_rpf_cache_refresh,
475 0, qpim_rpf_cache_refresh_delay_msec);
476}
477
478static int redist_read_ipv4_route(int command, struct zclient *zclient,
479 zebra_size_t length)
480{
481 struct stream *s;
482 struct zapi_ipv4 api;
483 unsigned long ifindex;
484 struct in_addr nexthop;
485 struct prefix_ipv4 p;
486 int min_len = 4;
487
488 if (length < min_len) {
489 zlog_warn("%s %s: short buffer: length=%d min=%d",
490 __FILE__, __PRETTY_FUNCTION__,
491 length, min_len);
492 return -1;
493 }
494
495 s = zclient->ibuf;
496 ifindex = 0;
497 nexthop.s_addr = 0;
498
499 /* Type, flags, message. */
500 api.type = stream_getc(s);
501 api.flags = stream_getc(s);
502 api.message = stream_getc(s);
503
504 /* IPv4 prefix length. */
505 memset(&p, 0, sizeof(struct prefix_ipv4));
506 p.family = AF_INET;
507 p.prefixlen = stream_getc(s);
508
509 min_len +=
510 PSIZE(p.prefixlen) +
511 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
512 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
513 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
514 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
515
516 if (PIM_DEBUG_ZEBRA) {
517 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
518 __FILE__, __PRETTY_FUNCTION__,
519 length, min_len,
520 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
521 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
522 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
523 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
524 }
525
526 if (length < min_len) {
527 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
528 __FILE__, __PRETTY_FUNCTION__,
529 length, min_len,
530 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
531 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
532 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
533 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
534 return -1;
535 }
536
537 /* IPv4 prefix. */
538 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
539
540 /* Nexthop, ifindex, distance, metric. */
541 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
542 api.nexthop_num = stream_getc(s);
543 nexthop.s_addr = stream_get_ipv4(s);
544 }
545 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
546 api.ifindex_num = stream_getc(s);
547 ifindex = stream_getl(s);
548 }
549
550 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
551 api.distance = stream_getc(s) :
552 0;
553
554 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
555 stream_getl(s) :
556 0;
557
558 switch (command) {
559 case ZEBRA_IPV4_ROUTE_ADD:
560 if (PIM_DEBUG_ZEBRA) {
561 char buf[2][INET_ADDRSTRLEN];
562 zlog_debug("%s: add %s %s/%d "
563 "nexthop %s ifindex %ld metric%s %u distance%s %u",
564 __PRETTY_FUNCTION__,
565 zebra_route_string(api.type),
566 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
567 p.prefixlen,
568 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
569 ifindex,
570 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
571 api.metric,
572 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
573 api.distance);
574 }
575 break;
576 case ZEBRA_IPV4_ROUTE_DELETE:
577 if (PIM_DEBUG_ZEBRA) {
578 char buf[2][INET_ADDRSTRLEN];
579 zlog_debug("%s: delete %s %s/%d "
580 "nexthop %s ifindex %ld metric%s %u distance%s %u",
581 __PRETTY_FUNCTION__,
582 zebra_route_string(api.type),
583 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
584 p.prefixlen,
585 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
586 ifindex,
587 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
588 api.metric,
589 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
590 api.distance);
591 }
592 break;
593 default:
594 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
595 return -1;
596 }
597
598 sched_rpf_cache_refresh();
599
600 return 0;
601}
602
603void pim_zebra_init()
604{
605 struct zclient *zclient;
606 int i;
607
608#ifdef HAVE_TCP_ZEBRA
609 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
610#else
611 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", ZEBRA_SERV_PATH);
612#endif
613
614 /* Socket for receiving updates from Zebra daemon */
615 zclient = zclient_new();
616
617 zclient->router_id_update = pim_router_id_update_zebra;
618 zclient->interface_add = pim_zebra_if_add;
619 zclient->interface_delete = pim_zebra_if_del;
620 zclient->interface_up = pim_zebra_if_state_up;
621 zclient->interface_down = pim_zebra_if_state_down;
622 zclient->interface_address_add = pim_zebra_if_address_add;
623 zclient->interface_address_delete = pim_zebra_if_address_del;
624 zclient->ipv4_route_add = redist_read_ipv4_route;
625 zclient->ipv4_route_delete = redist_read_ipv4_route;
626
627 zclient_init(zclient, ZEBRA_ROUTE_PIM);
628 zlog_info("zclient_init cleared redistribution request");
629
630 zassert(zclient->redist_default == ZEBRA_ROUTE_PIM);
631
632 /* Request all redistribution */
633 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
634 if (i == zclient->redist_default)
635 continue;
636 zclient->redist[i] = 1;
637 zlog_info("%s: requesting redistribution for %s (%i)",
638 __PRETTY_FUNCTION__, zebra_route_string(i), i);
639 }
640
641 /* Request default information */
642 zclient->default_information = 1;
643 zlog_info("%s: requesting default information redistribution",
644 __PRETTY_FUNCTION__);
645
646 zlog_notice("%s: zclient update socket initialized",
647 __PRETTY_FUNCTION__);
648
649 zassert(!qpim_zclient_lookup);
650 qpim_zclient_lookup = zclient_lookup_new();
651 zassert(qpim_zclient_lookup);
652}
653
654void igmp_anysource_forward_start(struct igmp_group *group)
655{
656 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
657 zassert(group->group_filtermode_isexcl);
658 zassert(listcount(group->group_source_list) < 1);
659
660 if (PIM_DEBUG_IGMP_TRACE) {
661 zlog_debug("%s %s: UNIMPLEMENTED",
662 __FILE__, __PRETTY_FUNCTION__);
663 }
664}
665
666void igmp_anysource_forward_stop(struct igmp_group *group)
667{
668 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
669 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
670
671 if (PIM_DEBUG_IGMP_TRACE) {
672 zlog_debug("%s %s: UNIMPLEMENTED",
673 __FILE__, __PRETTY_FUNCTION__);
674 }
675}
676
677static int fib_lookup_if_vif_index(struct in_addr addr)
678{
679 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
680 int num_ifindex;
681 int vif_index;
682 int first_ifindex;
683
684 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
685 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
686 PIM_NEXTHOP_LOOKUP_MAX);
687 if (num_ifindex < 1) {
688 char addr_str[100];
689 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
690 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
691 __FILE__, __PRETTY_FUNCTION__,
692 addr_str);
693 return -1;
694 }
695
696 first_ifindex = nexthop_tab[0].ifindex;
697
698 if (num_ifindex > 1) {
699 char addr_str[100];
700 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
701 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
702 __FILE__, __PRETTY_FUNCTION__,
703 num_ifindex, addr_str, first_ifindex);
704 /* debug warning only, do not return */
705 }
706
707 if (PIM_DEBUG_ZEBRA) {
708 char addr_str[100];
709 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
710 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
711 __FILE__, __PRETTY_FUNCTION__,
712 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
713 }
714
715 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
716
717 if (vif_index < 1) {
718 char addr_str[100];
719 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
720 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
721 __FILE__, __PRETTY_FUNCTION__,
722 vif_index, addr_str);
723 return -2;
724 }
725
726 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
727
728 if (vif_index > qpim_mroute_oif_highest_vif_index) {
729 char addr_str[100];
730 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
731 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
732 __FILE__, __PRETTY_FUNCTION__,
733 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
734
735 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
736 __FILE__, __PRETTY_FUNCTION__,
737 ifindex2ifname(vif_index),
738 vif_index);
739
740 return -3;
741 }
742
743 return vif_index;
744}
745
746static int add_oif(struct channel_oil *channel_oil,
747 struct interface *oif,
748 uint32_t proto_mask)
749{
750 struct pim_interface *pim_ifp;
751 int old_ttl;
752
753 zassert(channel_oil);
754
755 pim_ifp = oif->info;
756
Everton Marques67faabc2010-02-23 12:11:11 -0300757 if (PIM_DEBUG_MROUTE) {
758 char group_str[100];
759 char source_str[100];
760 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
761 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
762 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
763 __FILE__, __PRETTY_FUNCTION__,
764 source_str, group_str,
765 proto_mask, oif->name, pim_ifp->mroute_vif_index);
766 }
767
Everton Marques871dbcf2009-08-11 15:43:05 -0300768 if (pim_ifp->mroute_vif_index < 1) {
769 zlog_warn("%s %s: interface %s vif_index=%d < 1",
770 __FILE__, __PRETTY_FUNCTION__,
771 oif->name, pim_ifp->mroute_vif_index);
772 return -1;
773 }
774
775#ifdef PIM_ENFORCE_LOOPFREE_MFC
776 /*
777 Prevent creating MFC entry with OIF=IIF.
778
779 This is a protection against implementation mistakes.
780
781 PIM protocol implicitely ensures loopfree multicast topology.
782
783 IGMP must be protected against adding looped MFC entries created
784 by both source and receiver attached to the same interface. See
785 TODO T22.
786 */
787 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
788 char group_str[100];
789 char source_str[100];
790 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
791 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
792 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
793 __FILE__, __PRETTY_FUNCTION__,
794 proto_mask, oif->name, pim_ifp->mroute_vif_index,
795 source_str, group_str);
796 return -2;
797 }
798#endif
799
800 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
801 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
802
803 /* Prevent single protocol from subscribing same interface to
804 channel (S,G) multiple times */
805 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
806 char group_str[100];
807 char source_str[100];
808 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
809 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
810 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
811 __FILE__, __PRETTY_FUNCTION__,
812 proto_mask, oif->name, pim_ifp->mroute_vif_index,
813 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
814 source_str, group_str);
815 return -3;
816 }
817
818 /* Allow other protocol to request subscription of same interface to
819 channel (S,G) multiple times, by silently ignoring further
820 requests */
821 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
822
823 /* Check the OIF really exists before returning, and only log
824 warning otherwise */
825 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
826 char group_str[100];
827 char source_str[100];
828 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
829 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
830 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
831 __FILE__, __PRETTY_FUNCTION__,
832 proto_mask, oif->name, pim_ifp->mroute_vif_index,
833 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
834 source_str, group_str);
835 }
836
837 return 0;
838 }
839
840 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
841
842 if (old_ttl > 0) {
843 char group_str[100];
844 char source_str[100];
845 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
846 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
847 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
848 __FILE__, __PRETTY_FUNCTION__,
849 oif->name, pim_ifp->mroute_vif_index,
850 source_str, group_str);
851 return -4;
852 }
853
854 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
855
856 if (pim_mroute_add(&channel_oil->oil)) {
857 char group_str[100];
858 char source_str[100];
859 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
860 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
861 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
862 __FILE__, __PRETTY_FUNCTION__,
863 oif->name, pim_ifp->mroute_vif_index,
864 source_str, group_str);
865
866 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
867 return -5;
868 }
869
870 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
871 ++channel_oil->oil_size;
872 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
873
Everton Marques67faabc2010-02-23 12:11:11 -0300874 if (PIM_DEBUG_MROUTE) {
875 char group_str[100];
876 char source_str[100];
877 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
878 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
879 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
880 __FILE__, __PRETTY_FUNCTION__,
881 source_str, group_str,
882 proto_mask, oif->name, pim_ifp->mroute_vif_index);
883 }
884
Everton Marques871dbcf2009-08-11 15:43:05 -0300885 return 0;
886}
887
888static int del_oif(struct channel_oil *channel_oil,
889 struct interface *oif,
890 uint32_t proto_mask)
891{
892 struct pim_interface *pim_ifp;
893 int old_ttl;
894
895 zassert(channel_oil);
896
897 pim_ifp = oif->info;
898
899 zassert(pim_ifp->mroute_vif_index >= 1);
900 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
901 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
902
Everton Marques67faabc2010-02-23 12:11:11 -0300903 if (PIM_DEBUG_MROUTE) {
904 char group_str[100];
905 char source_str[100];
906 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
907 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
908 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
909 __FILE__, __PRETTY_FUNCTION__,
910 source_str, group_str,
911 proto_mask, oif->name, pim_ifp->mroute_vif_index);
912 }
913
Everton Marques871dbcf2009-08-11 15:43:05 -0300914 /* Prevent single protocol from unsubscribing same interface from
915 channel (S,G) multiple times */
916 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
917 char group_str[100];
918 char source_str[100];
919 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
920 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
921 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
922 __FILE__, __PRETTY_FUNCTION__,
923 proto_mask, oif->name, pim_ifp->mroute_vif_index,
924 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
925 source_str, group_str);
926 return -2;
927 }
928
929 /* Mark that protocol is no longer interested in this OIF */
930 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
931
932 /* Allow multiple protocols to unsubscribe same interface from
933 channel (S,G) multiple times, by silently ignoring requests while
934 there is at least one protocol interested in the channel */
935 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
936
937 /* Check the OIF keeps existing before returning, and only log
938 warning otherwise */
939 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
940 char group_str[100];
941 char source_str[100];
942 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
943 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
944 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
945 __FILE__, __PRETTY_FUNCTION__,
946 proto_mask, oif->name, pim_ifp->mroute_vif_index,
947 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
948 source_str, group_str);
949 }
950
951 return 0;
952 }
953
954 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
955
956 if (old_ttl < 1) {
957 char group_str[100];
958 char source_str[100];
959 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
960 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
961 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
962 __FILE__, __PRETTY_FUNCTION__,
963 oif->name, pim_ifp->mroute_vif_index,
964 source_str, group_str);
965 return -3;
966 }
967
968 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
969
970 if (pim_mroute_add(&channel_oil->oil)) {
971 char group_str[100];
972 char source_str[100];
973 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
974 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
975 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
976 __FILE__, __PRETTY_FUNCTION__,
977 oif->name, pim_ifp->mroute_vif_index,
978 source_str, group_str);
979
980 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
981 return -4;
982 }
983
984 --channel_oil->oil_size;
985
986 if (channel_oil->oil_size < 1) {
987 if (pim_mroute_del(&channel_oil->oil)) {
988 /* just log a warning in case of failure */
989 char group_str[100];
990 char source_str[100];
991 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
992 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
993 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
994 __FILE__, __PRETTY_FUNCTION__,
995 source_str, group_str);
996 }
997 }
998
Everton Marques67faabc2010-02-23 12:11:11 -0300999 if (PIM_DEBUG_MROUTE) {
1000 char group_str[100];
1001 char source_str[100];
1002 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1003 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1004 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1005 __FILE__, __PRETTY_FUNCTION__,
1006 source_str, group_str,
1007 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1008 }
1009
Everton Marques871dbcf2009-08-11 15:43:05 -03001010 return 0;
1011}
1012
1013void igmp_source_forward_start(struct igmp_source *source)
1014{
1015 struct igmp_group *group;
1016
1017 if (PIM_DEBUG_IGMP_TRACE) {
1018 char source_str[100];
1019 char group_str[100];
1020 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1021 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1022 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1023 __PRETTY_FUNCTION__,
1024 source_str, group_str,
1025 source->source_group->group_igmp_sock->fd,
1026 source->source_group->group_igmp_sock->interface->name,
1027 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1028 }
1029
1030 /* Prevent IGMP interface from installing multicast route multiple
1031 times */
1032 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1033 return;
1034 }
1035
1036 group = source->source_group;
1037
1038 if (!source->source_channel_oil) {
1039 struct pim_interface *pim_oif;
1040 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1041 if (input_iface_vif_index < 1) {
1042 char source_str[100];
1043 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1044 zlog_warn("%s %s: could not find input interface for source %s",
1045 __FILE__, __PRETTY_FUNCTION__,
1046 source_str);
1047 return;
1048 }
1049
1050 /*
1051 Protect IGMP against adding looped MFC entries created by both
1052 source and receiver attached to the same interface. See TODO
1053 T22.
1054 */
1055 pim_oif = source->source_group->group_igmp_sock->interface->info;
1056 if (!pim_oif) {
1057 zlog_warn("%s: multicast not enabled on oif=%s ?",
1058 __PRETTY_FUNCTION__,
1059 source->source_group->group_igmp_sock->interface->name);
1060 return;
1061 }
1062 if (pim_oif->mroute_vif_index < 1) {
1063 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1064 __FILE__, __PRETTY_FUNCTION__,
1065 source->source_group->group_igmp_sock->interface->name,
1066 pim_oif->mroute_vif_index);
1067 return;
1068 }
1069 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1070 /* ignore request for looped MFC entry */
1071 if (PIM_DEBUG_IGMP_TRACE) {
1072 char source_str[100];
1073 char group_str[100];
1074 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1075 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1076 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1077 __PRETTY_FUNCTION__,
1078 source_str, group_str,
1079 source->source_group->group_igmp_sock->fd,
1080 source->source_group->group_igmp_sock->interface->name,
1081 input_iface_vif_index);
1082 }
1083 return;
1084 }
1085
1086 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1087 source->source_addr,
1088 input_iface_vif_index);
1089 if (!source->source_channel_oil) {
1090 char group_str[100];
1091 char source_str[100];
1092 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1093 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1094 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1095 __FILE__, __PRETTY_FUNCTION__,
1096 source_str, group_str);
1097 return;
1098 }
1099 }
1100
1101 if (add_oif(source->source_channel_oil,
1102 group->group_igmp_sock->interface,
1103 PIM_OIF_FLAG_PROTO_IGMP)) {
1104 return;
1105 }
1106
1107 /*
1108 Feed IGMPv3-gathered local membership information into PIM
1109 per-interface (S,G) state.
1110 */
1111 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1112 source->source_addr, group->group_addr);
1113
1114 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1115}
1116
1117void igmp_source_forward_stop(struct igmp_source *source)
1118{
1119 struct igmp_group *group;
1120
1121 if (PIM_DEBUG_IGMP_TRACE) {
1122 char source_str[100];
1123 char group_str[100];
1124 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1125 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1126 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1127 __PRETTY_FUNCTION__,
1128 source_str, group_str,
1129 source->source_group->group_igmp_sock->fd,
1130 source->source_group->group_igmp_sock->interface->name,
1131 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1132 }
1133
1134 /* Prevent IGMP interface from removing multicast route multiple
1135 times */
1136 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1137 return;
1138 }
1139
1140 group = source->source_group;
1141
1142 if (del_oif(source->source_channel_oil,
1143 group->group_igmp_sock->interface,
1144 PIM_OIF_FLAG_PROTO_IGMP)) {
1145 return;
1146 }
1147
1148 /*
1149 Feed IGMPv3-gathered local membership information into PIM
1150 per-interface (S,G) state.
1151 */
1152 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1153 source->source_addr, group->group_addr);
1154
1155 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1156}
1157
1158void pim_forward_start(struct pim_ifchannel *ch)
1159{
1160 struct pim_upstream *up = ch->upstream;
1161
1162 if (PIM_DEBUG_PIM_TRACE) {
1163 char source_str[100];
1164 char group_str[100];
1165 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1166 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1167 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1168 __PRETTY_FUNCTION__,
1169 source_str, group_str, ch->interface->name);
1170 }
1171
1172 if (!up->channel_oil) {
1173 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1174 if (input_iface_vif_index < 1) {
1175 char source_str[100];
1176 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1177 zlog_warn("%s %s: could not find input interface for source %s",
1178 __FILE__, __PRETTY_FUNCTION__,
1179 source_str);
1180 return;
1181 }
1182
1183 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1184 input_iface_vif_index);
1185 if (!up->channel_oil) {
1186 char group_str[100];
1187 char source_str[100];
1188 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1189 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1190 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1191 __FILE__, __PRETTY_FUNCTION__,
1192 source_str, group_str);
1193 return;
1194 }
1195 }
1196
1197 add_oif(up->channel_oil,
1198 ch->interface,
1199 PIM_OIF_FLAG_PROTO_PIM);
1200}
1201
1202void pim_forward_stop(struct pim_ifchannel *ch)
1203{
1204 struct pim_upstream *up = ch->upstream;
1205
1206 if (PIM_DEBUG_PIM_TRACE) {
1207 char source_str[100];
1208 char group_str[100];
1209 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1210 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1211 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1212 __PRETTY_FUNCTION__,
1213 source_str, group_str, ch->interface->name);
1214 }
1215
1216 if (!up->channel_oil) {
1217 char source_str[100];
1218 char group_str[100];
1219 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1220 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1221 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1222 __PRETTY_FUNCTION__,
1223 source_str, group_str, ch->interface->name);
1224
1225 return;
1226 }
1227
1228 del_oif(up->channel_oil,
1229 ch->interface,
1230 PIM_OIF_FLAG_PROTO_PIM);
1231}