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