blob: f0aa84f0c09ee39045451078ccbeb0ef80632f60 [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
Everton Marques306c99e2014-07-16 15:51:37 -0300206 zlog_debug("%s %s: interface %s address %s %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300207 __FILE__, __PRETTY_FUNCTION__,
208 ifp->name,
Everton Marques306c99e2014-07-16 15:51:37 -0300209 inet_ntoa(p->u.prefix4),
210 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
211 "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300212 }
213}
214#endif
215
216static int pim_zebra_if_address_add(int command, struct zclient *zclient,
217 zebra_size_t length)
218{
219 struct connected *c;
220 struct prefix *p;
221
222 zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD);
223
224 /*
225 zebra api notifies address adds/dels events by using the same call
226 interface_add_read below, see comments in lib/zclient.c
227
228 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
229 will add address to interface list by calling
230 connected_add_by_prefix()
231 */
232 c = zebra_interface_address_read(command, zclient->ibuf);
233 if (!c)
234 return 0;
235
236 p = c->address;
237 if (p->family != AF_INET)
238 return 0;
239
240 if (PIM_DEBUG_ZEBRA) {
241 char buf[BUFSIZ];
242 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300243 zlog_debug("%s: %s connected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300244 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300245 c->ifp->name, buf, c->flags,
246 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300247
248#ifdef PIM_DEBUG_IFADDR_DUMP
249 dump_if_address(c->ifp);
250#endif
251 }
252
Everton Marques306c99e2014-07-16 15:51:37 -0300253 if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
254 /* trying to add primary address */
255
256 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
257 if (primary_addr.s_addr != p->u.prefix4.s_addr) {
258 /* but we had a primary address already */
259
260 char buf[BUFSIZ];
261 char old[100];
262
263 prefix2str(p, buf, BUFSIZ);
264 pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
265
266 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
267 __PRETTY_FUNCTION__,
268 c->ifp->name, old, buf);
269 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
270 }
271 }
272
Everton Marques871dbcf2009-08-11 15:43:05 -0300273 pim_if_addr_add(c);
274
275 return 0;
276}
277
278static int pim_zebra_if_address_del(int command, struct zclient *client,
279 zebra_size_t length)
280{
281 struct connected *c;
282 struct prefix *p;
283
284 zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE);
285
286 /*
287 zebra api notifies address adds/dels events by using the same call
288 interface_add_read below, see comments in lib/zclient.c
289
290 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
291 will remove address from interface list by calling
292 connected_delete_by_prefix()
293 */
294 c = zebra_interface_address_read(command, client->ibuf);
295 if (!c)
296 return 0;
297
298 p = c->address;
299 if (p->family != AF_INET)
300 return 0;
301
302 if (PIM_DEBUG_ZEBRA) {
303 char buf[BUFSIZ];
304 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300305 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300306 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300307 c->ifp->name, buf, c->flags,
308 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300309
310#ifdef PIM_DEBUG_IFADDR_DUMP
311 dump_if_address(c->ifp);
312#endif
313 }
Everton Marques306c99e2014-07-16 15:51:37 -0300314
Everton Marques871dbcf2009-08-11 15:43:05 -0300315 pim_if_addr_del(c);
316
317 return 0;
318}
319
320static void scan_upstream_rpf_cache()
321{
322 struct listnode *up_node;
323 struct listnode *up_nextnode;
324 struct pim_upstream *up;
325
326 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
327 struct in_addr old_rpf_addr;
328 enum pim_rpf_result rpf_result;
329
330 rpf_result = pim_rpf_update(up, &old_rpf_addr);
331 if (rpf_result == PIM_RPF_FAILURE)
332 continue;
333
334 if (rpf_result == PIM_RPF_CHANGED) {
335
336 if (up->join_state == PIM_UPSTREAM_JOINED) {
337
338 /*
339 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
340
341 Transitions from Joined State
342
343 RPF'(S,G) changes not due to an Assert
344
345 The upstream (S,G) state machine remains in Joined
346 state. Send Join(S,G) to the new upstream neighbor, which is
347 the new value of RPF'(S,G). Send Prune(S,G) to the old
348 upstream neighbor, which is the old value of RPF'(S,G). Set
349 the Join Timer (JT) to expire after t_periodic seconds.
350 */
351
352
353 /* send Prune(S,G) to the old upstream neighbor */
354 pim_joinprune_send(up->rpf.source_nexthop.interface,
355 old_rpf_addr,
356 up->source_addr,
357 up->group_addr,
358 0 /* prune */);
359
360 /* send Join(S,G) to the current upstream neighbor */
361 pim_joinprune_send(up->rpf.source_nexthop.interface,
362 up->rpf.rpf_addr,
363 up->source_addr,
364 up->group_addr,
365 1 /* join */);
366
367 pim_upstream_join_timer_restart(up);
368 } /* up->join_state == PIM_UPSTREAM_JOINED */
369
370 /* FIXME can join_desired actually be changed by pim_rpf_update()
371 returning PIM_RPF_CHANGED ? */
372 pim_upstream_update_join_desired(up);
373
374 } /* PIM_RPF_CHANGED */
375
376 } /* for (qpim_upstream_list) */
377
378}
379
Everton Marquesf24200d2014-02-14 16:40:34 -0200380void pim_scan_oil()
Everton Marques871dbcf2009-08-11 15:43:05 -0300381{
382 struct listnode *node;
383 struct listnode *nextnode;
384 struct channel_oil *c_oil;
385
Everton Marquesf24200d2014-02-14 16:40:34 -0200386 qpim_scan_oil_last = pim_time_monotonic_sec();
387 ++qpim_scan_oil_events;
388
Everton Marques871dbcf2009-08-11 15:43:05 -0300389 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
390 int old_vif_index;
391 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
392 if (input_iface_vif_index < 1) {
393 char source_str[100];
394 char group_str[100];
395 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
396 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
397 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
398 __FILE__, __PRETTY_FUNCTION__,
399 source_str, group_str);
400 continue;
401 }
402
403 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
404 /* RPF unchanged */
405 continue;
406 }
407
408 if (PIM_DEBUG_ZEBRA) {
409 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
410 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
411 char source_str[100];
412 char group_str[100];
413 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
414 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
415 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
416 __FILE__, __PRETTY_FUNCTION__,
417 source_str, group_str,
418 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
419 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
420 }
421
422 /* new iif loops to existing oif ? */
423 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
424 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
425
426 if (PIM_DEBUG_ZEBRA) {
427 char source_str[100];
428 char group_str[100];
429 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
430 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
431 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
432 __FILE__, __PRETTY_FUNCTION__,
433 source_str, group_str,
434 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
435 }
436
437 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
438 }
439
440 /* update iif vif_index */
441 old_vif_index = c_oil->oil.mfcc_parent;
442 c_oil->oil.mfcc_parent = input_iface_vif_index;
443
444 /* update kernel multicast forwarding cache (MFC) */
445 if (pim_mroute_add(&c_oil->oil)) {
446 /* just log warning */
447 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
448 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
449 char source_str[100];
450 char group_str[100];
451 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
452 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
453 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
454 __FILE__, __PRETTY_FUNCTION__,
455 source_str, group_str,
456 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
457 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
458 continue;
459 }
460
461 } /* for (qpim_channel_oil_list) */
462}
463
464static int on_rpf_cache_refresh(struct thread *t)
465{
466 zassert(t);
467 zassert(qpim_rpf_cache_refresher);
468
469 qpim_rpf_cache_refresher = 0;
470
471 /* update PIM protocol state */
472 scan_upstream_rpf_cache();
473
474 /* update kernel multicast forwarding cache (MFC) */
Everton Marquesf24200d2014-02-14 16:40:34 -0200475 pim_scan_oil();
Everton Marques871dbcf2009-08-11 15:43:05 -0300476
Everton Marquesbcc4abe2009-08-17 18:18:59 -0300477 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
Everton Marques613938d2009-08-13 15:39:31 -0300478 ++qpim_rpf_cache_refresh_events;
479
Everton Marques871dbcf2009-08-11 15:43:05 -0300480 return 0;
481}
482
483static void sched_rpf_cache_refresh()
484{
Everton Marques613938d2009-08-13 15:39:31 -0300485 ++qpim_rpf_cache_refresh_requests;
486
487 if (qpim_rpf_cache_refresher) {
488 /* Refresh timer is already running */
Everton Marques871dbcf2009-08-11 15:43:05 -0300489 return;
Everton Marques613938d2009-08-13 15:39:31 -0300490 }
491
492 /* Start refresh timer */
Everton Marques871dbcf2009-08-11 15:43:05 -0300493
494 if (PIM_DEBUG_ZEBRA) {
495 zlog_debug("%s: triggering %ld msec timer",
496 __PRETTY_FUNCTION__,
497 qpim_rpf_cache_refresh_delay_msec);
498 }
499
500 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
501 on_rpf_cache_refresh,
502 0, qpim_rpf_cache_refresh_delay_msec);
503}
504
505static int redist_read_ipv4_route(int command, struct zclient *zclient,
506 zebra_size_t length)
507{
508 struct stream *s;
509 struct zapi_ipv4 api;
510 unsigned long ifindex;
511 struct in_addr nexthop;
512 struct prefix_ipv4 p;
513 int min_len = 4;
514
515 if (length < min_len) {
516 zlog_warn("%s %s: short buffer: length=%d min=%d",
517 __FILE__, __PRETTY_FUNCTION__,
518 length, min_len);
519 return -1;
520 }
521
522 s = zclient->ibuf;
523 ifindex = 0;
524 nexthop.s_addr = 0;
525
526 /* Type, flags, message. */
527 api.type = stream_getc(s);
528 api.flags = stream_getc(s);
529 api.message = stream_getc(s);
530
531 /* IPv4 prefix length. */
532 memset(&p, 0, sizeof(struct prefix_ipv4));
533 p.family = AF_INET;
534 p.prefixlen = stream_getc(s);
535
536 min_len +=
537 PSIZE(p.prefixlen) +
538 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
539 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
540 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
541 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
542
543 if (PIM_DEBUG_ZEBRA) {
544 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
545 __FILE__, __PRETTY_FUNCTION__,
546 length, min_len,
547 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
548 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
549 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
550 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
551 }
552
553 if (length < min_len) {
554 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
555 __FILE__, __PRETTY_FUNCTION__,
556 length, min_len,
557 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
558 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
559 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
560 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
561 return -1;
562 }
563
564 /* IPv4 prefix. */
565 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
566
567 /* Nexthop, ifindex, distance, metric. */
568 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
569 api.nexthop_num = stream_getc(s);
570 nexthop.s_addr = stream_get_ipv4(s);
571 }
572 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
573 api.ifindex_num = stream_getc(s);
574 ifindex = stream_getl(s);
575 }
576
577 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
David Lamparter105ad862012-02-16 04:50:35 +0000578 stream_getc(s) :
Everton Marques871dbcf2009-08-11 15:43:05 -0300579 0;
580
581 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
582 stream_getl(s) :
583 0;
584
585 switch (command) {
586 case ZEBRA_IPV4_ROUTE_ADD:
587 if (PIM_DEBUG_ZEBRA) {
588 char buf[2][INET_ADDRSTRLEN];
589 zlog_debug("%s: add %s %s/%d "
590 "nexthop %s ifindex %ld metric%s %u distance%s %u",
591 __PRETTY_FUNCTION__,
592 zebra_route_string(api.type),
593 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
594 p.prefixlen,
595 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
596 ifindex,
597 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
598 api.metric,
599 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
600 api.distance);
601 }
602 break;
603 case ZEBRA_IPV4_ROUTE_DELETE:
604 if (PIM_DEBUG_ZEBRA) {
605 char buf[2][INET_ADDRSTRLEN];
606 zlog_debug("%s: delete %s %s/%d "
607 "nexthop %s ifindex %ld metric%s %u distance%s %u",
608 __PRETTY_FUNCTION__,
609 zebra_route_string(api.type),
610 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
611 p.prefixlen,
612 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
613 ifindex,
614 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
615 api.metric,
616 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
617 api.distance);
618 }
619 break;
620 default:
621 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
622 return -1;
623 }
624
625 sched_rpf_cache_refresh();
626
627 return 0;
628}
629
630void pim_zebra_init()
631{
632 struct zclient *zclient;
633 int i;
634
635#ifdef HAVE_TCP_ZEBRA
636 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
637#else
638 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", ZEBRA_SERV_PATH);
639#endif
640
641 /* Socket for receiving updates from Zebra daemon */
642 zclient = zclient_new();
643
644 zclient->router_id_update = pim_router_id_update_zebra;
645 zclient->interface_add = pim_zebra_if_add;
646 zclient->interface_delete = pim_zebra_if_del;
647 zclient->interface_up = pim_zebra_if_state_up;
648 zclient->interface_down = pim_zebra_if_state_down;
649 zclient->interface_address_add = pim_zebra_if_address_add;
650 zclient->interface_address_delete = pim_zebra_if_address_del;
651 zclient->ipv4_route_add = redist_read_ipv4_route;
652 zclient->ipv4_route_delete = redist_read_ipv4_route;
653
654 zclient_init(zclient, ZEBRA_ROUTE_PIM);
655 zlog_info("zclient_init cleared redistribution request");
656
657 zassert(zclient->redist_default == ZEBRA_ROUTE_PIM);
658
659 /* Request all redistribution */
660 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
661 if (i == zclient->redist_default)
662 continue;
663 zclient->redist[i] = 1;
664 zlog_info("%s: requesting redistribution for %s (%i)",
665 __PRETTY_FUNCTION__, zebra_route_string(i), i);
666 }
667
668 /* Request default information */
669 zclient->default_information = 1;
670 zlog_info("%s: requesting default information redistribution",
671 __PRETTY_FUNCTION__);
672
673 zlog_notice("%s: zclient update socket initialized",
674 __PRETTY_FUNCTION__);
675
676 zassert(!qpim_zclient_lookup);
677 qpim_zclient_lookup = zclient_lookup_new();
678 zassert(qpim_zclient_lookup);
679}
680
681void igmp_anysource_forward_start(struct igmp_group *group)
682{
683 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
684 zassert(group->group_filtermode_isexcl);
685 zassert(listcount(group->group_source_list) < 1);
686
687 if (PIM_DEBUG_IGMP_TRACE) {
688 zlog_debug("%s %s: UNIMPLEMENTED",
689 __FILE__, __PRETTY_FUNCTION__);
690 }
691}
692
693void igmp_anysource_forward_stop(struct igmp_group *group)
694{
695 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
696 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
697
698 if (PIM_DEBUG_IGMP_TRACE) {
699 zlog_debug("%s %s: UNIMPLEMENTED",
700 __FILE__, __PRETTY_FUNCTION__);
701 }
702}
703
704static int fib_lookup_if_vif_index(struct in_addr addr)
705{
706 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
707 int num_ifindex;
708 int vif_index;
709 int first_ifindex;
710
711 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
712 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
713 PIM_NEXTHOP_LOOKUP_MAX);
714 if (num_ifindex < 1) {
715 char addr_str[100];
716 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
717 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
718 __FILE__, __PRETTY_FUNCTION__,
719 addr_str);
720 return -1;
721 }
722
723 first_ifindex = nexthop_tab[0].ifindex;
724
725 if (num_ifindex > 1) {
726 char addr_str[100];
727 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
728 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
729 __FILE__, __PRETTY_FUNCTION__,
730 num_ifindex, addr_str, first_ifindex);
731 /* debug warning only, do not return */
732 }
733
734 if (PIM_DEBUG_ZEBRA) {
735 char addr_str[100];
736 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
737 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
738 __FILE__, __PRETTY_FUNCTION__,
739 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
740 }
741
742 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
743
744 if (vif_index < 1) {
745 char addr_str[100];
746 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
747 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
748 __FILE__, __PRETTY_FUNCTION__,
749 vif_index, addr_str);
750 return -2;
751 }
752
753 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
754
755 if (vif_index > qpim_mroute_oif_highest_vif_index) {
756 char addr_str[100];
757 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
758 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
759 __FILE__, __PRETTY_FUNCTION__,
760 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
761
762 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
763 __FILE__, __PRETTY_FUNCTION__,
764 ifindex2ifname(vif_index),
765 vif_index);
766
767 return -3;
768 }
769
770 return vif_index;
771}
772
773static int add_oif(struct channel_oil *channel_oil,
774 struct interface *oif,
775 uint32_t proto_mask)
776{
777 struct pim_interface *pim_ifp;
778 int old_ttl;
779
780 zassert(channel_oil);
781
782 pim_ifp = oif->info;
783
Everton Marques67faabc2010-02-23 12:11:11 -0300784 if (PIM_DEBUG_MROUTE) {
785 char group_str[100];
786 char source_str[100];
787 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
788 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
789 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
790 __FILE__, __PRETTY_FUNCTION__,
791 source_str, group_str,
792 proto_mask, oif->name, pim_ifp->mroute_vif_index);
793 }
794
Everton Marques871dbcf2009-08-11 15:43:05 -0300795 if (pim_ifp->mroute_vif_index < 1) {
796 zlog_warn("%s %s: interface %s vif_index=%d < 1",
797 __FILE__, __PRETTY_FUNCTION__,
798 oif->name, pim_ifp->mroute_vif_index);
799 return -1;
800 }
801
802#ifdef PIM_ENFORCE_LOOPFREE_MFC
803 /*
804 Prevent creating MFC entry with OIF=IIF.
805
806 This is a protection against implementation mistakes.
807
808 PIM protocol implicitely ensures loopfree multicast topology.
809
810 IGMP must be protected against adding looped MFC entries created
811 by both source and receiver attached to the same interface. See
812 TODO T22.
813 */
814 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
815 char group_str[100];
816 char source_str[100];
817 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
818 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
819 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
820 __FILE__, __PRETTY_FUNCTION__,
821 proto_mask, oif->name, pim_ifp->mroute_vif_index,
822 source_str, group_str);
823 return -2;
824 }
825#endif
826
827 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
828 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
829
830 /* Prevent single protocol from subscribing same interface to
831 channel (S,G) multiple times */
832 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
833 char group_str[100];
834 char source_str[100];
835 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
836 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
837 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
838 __FILE__, __PRETTY_FUNCTION__,
839 proto_mask, oif->name, pim_ifp->mroute_vif_index,
840 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
841 source_str, group_str);
842 return -3;
843 }
844
845 /* Allow other protocol to request subscription of same interface to
846 channel (S,G) multiple times, by silently ignoring further
847 requests */
848 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
849
850 /* Check the OIF really exists before returning, and only log
851 warning otherwise */
852 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
853 char group_str[100];
854 char source_str[100];
855 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
856 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
857 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
858 __FILE__, __PRETTY_FUNCTION__,
859 proto_mask, oif->name, pim_ifp->mroute_vif_index,
860 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
861 source_str, group_str);
862 }
863
864 return 0;
865 }
866
867 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
868
869 if (old_ttl > 0) {
870 char group_str[100];
871 char source_str[100];
872 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
873 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
874 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
875 __FILE__, __PRETTY_FUNCTION__,
876 oif->name, pim_ifp->mroute_vif_index,
877 source_str, group_str);
878 return -4;
879 }
880
881 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
882
883 if (pim_mroute_add(&channel_oil->oil)) {
884 char group_str[100];
885 char source_str[100];
886 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
887 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
888 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
889 __FILE__, __PRETTY_FUNCTION__,
890 oif->name, pim_ifp->mroute_vif_index,
891 source_str, group_str);
892
893 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
894 return -5;
895 }
896
897 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
898 ++channel_oil->oil_size;
899 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
900
Everton Marques67faabc2010-02-23 12:11:11 -0300901 if (PIM_DEBUG_MROUTE) {
902 char group_str[100];
903 char source_str[100];
904 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
905 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
906 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
907 __FILE__, __PRETTY_FUNCTION__,
908 source_str, group_str,
909 proto_mask, oif->name, pim_ifp->mroute_vif_index);
910 }
911
Everton Marques871dbcf2009-08-11 15:43:05 -0300912 return 0;
913}
914
915static int del_oif(struct channel_oil *channel_oil,
916 struct interface *oif,
917 uint32_t proto_mask)
918{
919 struct pim_interface *pim_ifp;
920 int old_ttl;
921
922 zassert(channel_oil);
923
924 pim_ifp = oif->info;
925
926 zassert(pim_ifp->mroute_vif_index >= 1);
927 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
928 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
929
Everton Marques67faabc2010-02-23 12:11:11 -0300930 if (PIM_DEBUG_MROUTE) {
931 char group_str[100];
932 char source_str[100];
933 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
934 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
935 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
936 __FILE__, __PRETTY_FUNCTION__,
937 source_str, group_str,
938 proto_mask, oif->name, pim_ifp->mroute_vif_index);
939 }
940
Everton Marques871dbcf2009-08-11 15:43:05 -0300941 /* Prevent single protocol from unsubscribing same interface from
942 channel (S,G) multiple times */
943 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
944 char group_str[100];
945 char source_str[100];
946 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
947 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
948 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
949 __FILE__, __PRETTY_FUNCTION__,
950 proto_mask, oif->name, pim_ifp->mroute_vif_index,
951 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
952 source_str, group_str);
953 return -2;
954 }
955
956 /* Mark that protocol is no longer interested in this OIF */
957 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
958
959 /* Allow multiple protocols to unsubscribe same interface from
960 channel (S,G) multiple times, by silently ignoring requests while
961 there is at least one protocol interested in the channel */
962 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
963
964 /* Check the OIF keeps existing before returning, and only log
965 warning otherwise */
966 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
967 char group_str[100];
968 char source_str[100];
969 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
970 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
971 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
972 __FILE__, __PRETTY_FUNCTION__,
973 proto_mask, oif->name, pim_ifp->mroute_vif_index,
974 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
975 source_str, group_str);
976 }
977
978 return 0;
979 }
980
981 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
982
983 if (old_ttl < 1) {
984 char group_str[100];
985 char source_str[100];
986 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
987 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
988 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
989 __FILE__, __PRETTY_FUNCTION__,
990 oif->name, pim_ifp->mroute_vif_index,
991 source_str, group_str);
992 return -3;
993 }
994
995 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
996
997 if (pim_mroute_add(&channel_oil->oil)) {
998 char group_str[100];
999 char source_str[100];
1000 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1001 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1002 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1003 __FILE__, __PRETTY_FUNCTION__,
1004 oif->name, pim_ifp->mroute_vif_index,
1005 source_str, group_str);
1006
1007 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1008 return -4;
1009 }
1010
1011 --channel_oil->oil_size;
1012
1013 if (channel_oil->oil_size < 1) {
1014 if (pim_mroute_del(&channel_oil->oil)) {
1015 /* just log a warning in case of failure */
1016 char group_str[100];
1017 char source_str[100];
1018 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1019 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1020 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1021 __FILE__, __PRETTY_FUNCTION__,
1022 source_str, group_str);
1023 }
1024 }
1025
Everton Marques67faabc2010-02-23 12:11:11 -03001026 if (PIM_DEBUG_MROUTE) {
1027 char group_str[100];
1028 char source_str[100];
1029 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1030 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1031 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1032 __FILE__, __PRETTY_FUNCTION__,
1033 source_str, group_str,
1034 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1035 }
1036
Everton Marques871dbcf2009-08-11 15:43:05 -03001037 return 0;
1038}
1039
1040void igmp_source_forward_start(struct igmp_source *source)
1041{
1042 struct igmp_group *group;
1043
1044 if (PIM_DEBUG_IGMP_TRACE) {
1045 char source_str[100];
1046 char group_str[100];
1047 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1048 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1049 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1050 __PRETTY_FUNCTION__,
1051 source_str, group_str,
1052 source->source_group->group_igmp_sock->fd,
1053 source->source_group->group_igmp_sock->interface->name,
1054 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1055 }
1056
1057 /* Prevent IGMP interface from installing multicast route multiple
1058 times */
1059 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1060 return;
1061 }
1062
1063 group = source->source_group;
1064
1065 if (!source->source_channel_oil) {
1066 struct pim_interface *pim_oif;
1067 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1068 if (input_iface_vif_index < 1) {
1069 char source_str[100];
1070 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1071 zlog_warn("%s %s: could not find input interface for source %s",
1072 __FILE__, __PRETTY_FUNCTION__,
1073 source_str);
1074 return;
1075 }
1076
1077 /*
1078 Protect IGMP against adding looped MFC entries created by both
1079 source and receiver attached to the same interface. See TODO
1080 T22.
1081 */
1082 pim_oif = source->source_group->group_igmp_sock->interface->info;
1083 if (!pim_oif) {
1084 zlog_warn("%s: multicast not enabled on oif=%s ?",
1085 __PRETTY_FUNCTION__,
1086 source->source_group->group_igmp_sock->interface->name);
1087 return;
1088 }
1089 if (pim_oif->mroute_vif_index < 1) {
1090 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1091 __FILE__, __PRETTY_FUNCTION__,
1092 source->source_group->group_igmp_sock->interface->name,
1093 pim_oif->mroute_vif_index);
1094 return;
1095 }
1096 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1097 /* ignore request for looped MFC entry */
1098 if (PIM_DEBUG_IGMP_TRACE) {
1099 char source_str[100];
1100 char group_str[100];
1101 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1102 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1103 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1104 __PRETTY_FUNCTION__,
1105 source_str, group_str,
1106 source->source_group->group_igmp_sock->fd,
1107 source->source_group->group_igmp_sock->interface->name,
1108 input_iface_vif_index);
1109 }
1110 return;
1111 }
1112
1113 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1114 source->source_addr,
1115 input_iface_vif_index);
1116 if (!source->source_channel_oil) {
1117 char group_str[100];
1118 char source_str[100];
1119 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1120 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1121 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1122 __FILE__, __PRETTY_FUNCTION__,
1123 source_str, group_str);
1124 return;
1125 }
1126 }
1127
1128 if (add_oif(source->source_channel_oil,
1129 group->group_igmp_sock->interface,
1130 PIM_OIF_FLAG_PROTO_IGMP)) {
1131 return;
1132 }
1133
1134 /*
1135 Feed IGMPv3-gathered local membership information into PIM
1136 per-interface (S,G) state.
1137 */
1138 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1139 source->source_addr, group->group_addr);
1140
1141 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1142}
1143
1144void igmp_source_forward_stop(struct igmp_source *source)
1145{
1146 struct igmp_group *group;
1147
1148 if (PIM_DEBUG_IGMP_TRACE) {
1149 char source_str[100];
1150 char group_str[100];
1151 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1152 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1153 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1154 __PRETTY_FUNCTION__,
1155 source_str, group_str,
1156 source->source_group->group_igmp_sock->fd,
1157 source->source_group->group_igmp_sock->interface->name,
1158 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1159 }
1160
1161 /* Prevent IGMP interface from removing multicast route multiple
1162 times */
1163 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1164 return;
1165 }
1166
1167 group = source->source_group;
1168
1169 if (del_oif(source->source_channel_oil,
1170 group->group_igmp_sock->interface,
1171 PIM_OIF_FLAG_PROTO_IGMP)) {
1172 return;
1173 }
1174
1175 /*
1176 Feed IGMPv3-gathered local membership information into PIM
1177 per-interface (S,G) state.
1178 */
1179 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1180 source->source_addr, group->group_addr);
1181
1182 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1183}
1184
1185void pim_forward_start(struct pim_ifchannel *ch)
1186{
1187 struct pim_upstream *up = ch->upstream;
1188
1189 if (PIM_DEBUG_PIM_TRACE) {
1190 char source_str[100];
1191 char group_str[100];
1192 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1193 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1194 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1195 __PRETTY_FUNCTION__,
1196 source_str, group_str, ch->interface->name);
1197 }
1198
1199 if (!up->channel_oil) {
1200 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1201 if (input_iface_vif_index < 1) {
1202 char source_str[100];
1203 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1204 zlog_warn("%s %s: could not find input interface for source %s",
1205 __FILE__, __PRETTY_FUNCTION__,
1206 source_str);
1207 return;
1208 }
1209
1210 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1211 input_iface_vif_index);
1212 if (!up->channel_oil) {
1213 char group_str[100];
1214 char source_str[100];
1215 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1216 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1217 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1218 __FILE__, __PRETTY_FUNCTION__,
1219 source_str, group_str);
1220 return;
1221 }
1222 }
1223
1224 add_oif(up->channel_oil,
1225 ch->interface,
1226 PIM_OIF_FLAG_PROTO_PIM);
1227}
1228
1229void pim_forward_stop(struct pim_ifchannel *ch)
1230{
1231 struct pim_upstream *up = ch->upstream;
1232
1233 if (PIM_DEBUG_PIM_TRACE) {
1234 char source_str[100];
1235 char group_str[100];
1236 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1237 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1238 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1239 __PRETTY_FUNCTION__,
1240 source_str, group_str, ch->interface->name);
1241 }
1242
1243 if (!up->channel_oil) {
1244 char source_str[100];
1245 char group_str[100];
1246 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1247 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1248 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1249 __PRETTY_FUNCTION__,
1250 source_str, group_str, ch->interface->name);
1251
1252 return;
1253 }
1254
1255 del_oif(up->channel_oil,
1256 ch->interface,
1257 PIM_OIF_FLAG_PROTO_PIM);
1258}