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