blob: e080c04f34002bee28765b47cdde577abf7dc273 [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{
647 struct zclient *zclient;
648 int i;
649
650#ifdef HAVE_TCP_ZEBRA
651 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
652#else
653 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", ZEBRA_SERV_PATH);
654#endif
655
656 /* Socket for receiving updates from Zebra daemon */
657 zclient = zclient_new();
658
Everton Marques2a0ecf22014-09-22 18:18:26 -0300659 zclient->router_id_update = pim_router_id_update;
Everton Marques871dbcf2009-08-11 15:43:05 -0300660 zclient->router_id_update = pim_router_id_update_zebra;
661 zclient->interface_add = pim_zebra_if_add;
662 zclient->interface_delete = pim_zebra_if_del;
663 zclient->interface_up = pim_zebra_if_state_up;
664 zclient->interface_down = pim_zebra_if_state_down;
665 zclient->interface_address_add = pim_zebra_if_address_add;
666 zclient->interface_address_delete = pim_zebra_if_address_del;
667 zclient->ipv4_route_add = redist_read_ipv4_route;
668 zclient->ipv4_route_delete = redist_read_ipv4_route;
669
670 zclient_init(zclient, ZEBRA_ROUTE_PIM);
671 zlog_info("zclient_init cleared redistribution request");
672
673 zassert(zclient->redist_default == ZEBRA_ROUTE_PIM);
674
675 /* Request all redistribution */
676 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
677 if (i == zclient->redist_default)
678 continue;
679 zclient->redist[i] = 1;
680 zlog_info("%s: requesting redistribution for %s (%i)",
681 __PRETTY_FUNCTION__, zebra_route_string(i), i);
682 }
683
684 /* Request default information */
685 zclient->default_information = 1;
686 zlog_info("%s: requesting default information redistribution",
687 __PRETTY_FUNCTION__);
688
689 zlog_notice("%s: zclient update socket initialized",
690 __PRETTY_FUNCTION__);
691
692 zassert(!qpim_zclient_lookup);
693 qpim_zclient_lookup = zclient_lookup_new();
694 zassert(qpim_zclient_lookup);
695}
696
697void igmp_anysource_forward_start(struct igmp_group *group)
698{
699 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
700 zassert(group->group_filtermode_isexcl);
701 zassert(listcount(group->group_source_list) < 1);
702
703 if (PIM_DEBUG_IGMP_TRACE) {
704 zlog_debug("%s %s: UNIMPLEMENTED",
705 __FILE__, __PRETTY_FUNCTION__);
706 }
707}
708
709void igmp_anysource_forward_stop(struct igmp_group *group)
710{
711 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
712 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
713
714 if (PIM_DEBUG_IGMP_TRACE) {
715 zlog_debug("%s %s: UNIMPLEMENTED",
716 __FILE__, __PRETTY_FUNCTION__);
717 }
718}
719
720static int fib_lookup_if_vif_index(struct in_addr addr)
721{
722 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
723 int num_ifindex;
724 int vif_index;
725 int first_ifindex;
726
727 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
728 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
729 PIM_NEXTHOP_LOOKUP_MAX);
730 if (num_ifindex < 1) {
731 char addr_str[100];
732 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
733 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
734 __FILE__, __PRETTY_FUNCTION__,
735 addr_str);
736 return -1;
737 }
738
739 first_ifindex = nexthop_tab[0].ifindex;
740
741 if (num_ifindex > 1) {
742 char addr_str[100];
743 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
744 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
745 __FILE__, __PRETTY_FUNCTION__,
746 num_ifindex, addr_str, first_ifindex);
747 /* debug warning only, do not return */
748 }
749
750 if (PIM_DEBUG_ZEBRA) {
751 char addr_str[100];
752 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
753 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
754 __FILE__, __PRETTY_FUNCTION__,
755 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
756 }
757
758 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
759
760 if (vif_index < 1) {
761 char addr_str[100];
762 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
763 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
764 __FILE__, __PRETTY_FUNCTION__,
765 vif_index, addr_str);
766 return -2;
767 }
768
769 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
770
771 if (vif_index > qpim_mroute_oif_highest_vif_index) {
772 char addr_str[100];
773 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
774 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
775 __FILE__, __PRETTY_FUNCTION__,
776 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
777
778 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
779 __FILE__, __PRETTY_FUNCTION__,
780 ifindex2ifname(vif_index),
781 vif_index);
782
783 return -3;
784 }
785
786 return vif_index;
787}
788
789static int add_oif(struct channel_oil *channel_oil,
790 struct interface *oif,
791 uint32_t proto_mask)
792{
793 struct pim_interface *pim_ifp;
794 int old_ttl;
795
796 zassert(channel_oil);
797
798 pim_ifp = oif->info;
799
Everton Marques67faabc2010-02-23 12:11:11 -0300800 if (PIM_DEBUG_MROUTE) {
801 char group_str[100];
802 char source_str[100];
803 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
804 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
805 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
806 __FILE__, __PRETTY_FUNCTION__,
807 source_str, group_str,
808 proto_mask, oif->name, pim_ifp->mroute_vif_index);
809 }
810
Everton Marques871dbcf2009-08-11 15:43:05 -0300811 if (pim_ifp->mroute_vif_index < 1) {
812 zlog_warn("%s %s: interface %s vif_index=%d < 1",
813 __FILE__, __PRETTY_FUNCTION__,
814 oif->name, pim_ifp->mroute_vif_index);
815 return -1;
816 }
817
818#ifdef PIM_ENFORCE_LOOPFREE_MFC
819 /*
820 Prevent creating MFC entry with OIF=IIF.
821
822 This is a protection against implementation mistakes.
823
824 PIM protocol implicitely ensures loopfree multicast topology.
825
826 IGMP must be protected against adding looped MFC entries created
827 by both source and receiver attached to the same interface. See
828 TODO T22.
829 */
830 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
831 char group_str[100];
832 char source_str[100];
833 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
834 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
835 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
836 __FILE__, __PRETTY_FUNCTION__,
837 proto_mask, oif->name, pim_ifp->mroute_vif_index,
838 source_str, group_str);
839 return -2;
840 }
841#endif
842
843 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
844 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
845
846 /* Prevent single protocol from subscribing same interface to
847 channel (S,G) multiple times */
848 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
849 char group_str[100];
850 char source_str[100];
851 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
852 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
853 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
854 __FILE__, __PRETTY_FUNCTION__,
855 proto_mask, oif->name, pim_ifp->mroute_vif_index,
856 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
857 source_str, group_str);
858 return -3;
859 }
860
861 /* Allow other protocol to request subscription of same interface to
862 channel (S,G) multiple times, by silently ignoring further
863 requests */
864 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
865
866 /* Check the OIF really exists before returning, and only log
867 warning otherwise */
868 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
869 char group_str[100];
870 char source_str[100];
871 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
872 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
873 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
874 __FILE__, __PRETTY_FUNCTION__,
875 proto_mask, oif->name, pim_ifp->mroute_vif_index,
876 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
877 source_str, group_str);
878 }
879
880 return 0;
881 }
882
883 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
884
885 if (old_ttl > 0) {
886 char group_str[100];
887 char source_str[100];
888 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
889 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
890 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
891 __FILE__, __PRETTY_FUNCTION__,
892 oif->name, pim_ifp->mroute_vif_index,
893 source_str, group_str);
894 return -4;
895 }
896
897 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
898
899 if (pim_mroute_add(&channel_oil->oil)) {
900 char group_str[100];
901 char source_str[100];
902 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
903 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
904 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
905 __FILE__, __PRETTY_FUNCTION__,
906 oif->name, pim_ifp->mroute_vif_index,
907 source_str, group_str);
908
909 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
910 return -5;
911 }
912
913 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
914 ++channel_oil->oil_size;
915 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
916
Everton Marques67faabc2010-02-23 12:11:11 -0300917 if (PIM_DEBUG_MROUTE) {
918 char group_str[100];
919 char source_str[100];
920 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
921 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
922 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
923 __FILE__, __PRETTY_FUNCTION__,
924 source_str, group_str,
925 proto_mask, oif->name, pim_ifp->mroute_vif_index);
926 }
927
Everton Marques871dbcf2009-08-11 15:43:05 -0300928 return 0;
929}
930
931static int del_oif(struct channel_oil *channel_oil,
932 struct interface *oif,
933 uint32_t proto_mask)
934{
935 struct pim_interface *pim_ifp;
936 int old_ttl;
937
938 zassert(channel_oil);
939
940 pim_ifp = oif->info;
941
942 zassert(pim_ifp->mroute_vif_index >= 1);
943 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
944 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
945
Everton Marques67faabc2010-02-23 12:11:11 -0300946 if (PIM_DEBUG_MROUTE) {
947 char group_str[100];
948 char source_str[100];
949 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
950 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
951 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
952 __FILE__, __PRETTY_FUNCTION__,
953 source_str, group_str,
954 proto_mask, oif->name, pim_ifp->mroute_vif_index);
955 }
956
Everton Marques871dbcf2009-08-11 15:43:05 -0300957 /* Prevent single protocol from unsubscribing same interface from
958 channel (S,G) multiple times */
959 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
960 char group_str[100];
961 char source_str[100];
962 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
963 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
964 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
965 __FILE__, __PRETTY_FUNCTION__,
966 proto_mask, oif->name, pim_ifp->mroute_vif_index,
967 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
968 source_str, group_str);
969 return -2;
970 }
971
972 /* Mark that protocol is no longer interested in this OIF */
973 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
974
975 /* Allow multiple protocols to unsubscribe same interface from
976 channel (S,G) multiple times, by silently ignoring requests while
977 there is at least one protocol interested in the channel */
978 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
979
980 /* Check the OIF keeps existing before returning, and only log
981 warning otherwise */
982 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
983 char group_str[100];
984 char source_str[100];
985 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
986 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
987 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
988 __FILE__, __PRETTY_FUNCTION__,
989 proto_mask, oif->name, pim_ifp->mroute_vif_index,
990 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
991 source_str, group_str);
992 }
993
994 return 0;
995 }
996
997 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
998
999 if (old_ttl < 1) {
1000 char group_str[100];
1001 char source_str[100];
1002 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1003 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1004 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1005 __FILE__, __PRETTY_FUNCTION__,
1006 oif->name, pim_ifp->mroute_vif_index,
1007 source_str, group_str);
1008 return -3;
1009 }
1010
1011 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1012
1013 if (pim_mroute_add(&channel_oil->oil)) {
1014 char group_str[100];
1015 char source_str[100];
1016 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1017 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1018 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1019 __FILE__, __PRETTY_FUNCTION__,
1020 oif->name, pim_ifp->mroute_vif_index,
1021 source_str, group_str);
1022
1023 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1024 return -4;
1025 }
1026
1027 --channel_oil->oil_size;
1028
1029 if (channel_oil->oil_size < 1) {
1030 if (pim_mroute_del(&channel_oil->oil)) {
1031 /* just log a warning in case of failure */
1032 char group_str[100];
1033 char source_str[100];
1034 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1035 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1036 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1037 __FILE__, __PRETTY_FUNCTION__,
1038 source_str, group_str);
1039 }
1040 }
1041
Everton Marques67faabc2010-02-23 12:11:11 -03001042 if (PIM_DEBUG_MROUTE) {
1043 char group_str[100];
1044 char source_str[100];
1045 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1046 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1047 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1048 __FILE__, __PRETTY_FUNCTION__,
1049 source_str, group_str,
1050 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1051 }
1052
Everton Marques871dbcf2009-08-11 15:43:05 -03001053 return 0;
1054}
1055
1056void igmp_source_forward_start(struct igmp_source *source)
1057{
1058 struct igmp_group *group;
1059
1060 if (PIM_DEBUG_IGMP_TRACE) {
1061 char source_str[100];
1062 char group_str[100];
1063 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1064 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1065 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1066 __PRETTY_FUNCTION__,
1067 source_str, group_str,
1068 source->source_group->group_igmp_sock->fd,
1069 source->source_group->group_igmp_sock->interface->name,
1070 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1071 }
1072
1073 /* Prevent IGMP interface from installing multicast route multiple
1074 times */
1075 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1076 return;
1077 }
1078
1079 group = source->source_group;
1080
1081 if (!source->source_channel_oil) {
1082 struct pim_interface *pim_oif;
1083 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1084 if (input_iface_vif_index < 1) {
1085 char source_str[100];
1086 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1087 zlog_warn("%s %s: could not find input interface for source %s",
1088 __FILE__, __PRETTY_FUNCTION__,
1089 source_str);
1090 return;
1091 }
1092
1093 /*
1094 Protect IGMP against adding looped MFC entries created by both
1095 source and receiver attached to the same interface. See TODO
1096 T22.
1097 */
1098 pim_oif = source->source_group->group_igmp_sock->interface->info;
1099 if (!pim_oif) {
1100 zlog_warn("%s: multicast not enabled on oif=%s ?",
1101 __PRETTY_FUNCTION__,
1102 source->source_group->group_igmp_sock->interface->name);
1103 return;
1104 }
1105 if (pim_oif->mroute_vif_index < 1) {
1106 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1107 __FILE__, __PRETTY_FUNCTION__,
1108 source->source_group->group_igmp_sock->interface->name,
1109 pim_oif->mroute_vif_index);
1110 return;
1111 }
1112 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1113 /* ignore request for looped MFC entry */
1114 if (PIM_DEBUG_IGMP_TRACE) {
1115 char source_str[100];
1116 char group_str[100];
1117 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1118 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1119 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1120 __PRETTY_FUNCTION__,
1121 source_str, group_str,
1122 source->source_group->group_igmp_sock->fd,
1123 source->source_group->group_igmp_sock->interface->name,
1124 input_iface_vif_index);
1125 }
1126 return;
1127 }
1128
1129 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1130 source->source_addr,
1131 input_iface_vif_index);
1132 if (!source->source_channel_oil) {
1133 char group_str[100];
1134 char source_str[100];
1135 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1136 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1137 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1138 __FILE__, __PRETTY_FUNCTION__,
1139 source_str, group_str);
1140 return;
1141 }
1142 }
1143
1144 if (add_oif(source->source_channel_oil,
1145 group->group_igmp_sock->interface,
1146 PIM_OIF_FLAG_PROTO_IGMP)) {
1147 return;
1148 }
1149
1150 /*
1151 Feed IGMPv3-gathered local membership information into PIM
1152 per-interface (S,G) state.
1153 */
1154 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1155 source->source_addr, group->group_addr);
1156
1157 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1158}
1159
1160void igmp_source_forward_stop(struct igmp_source *source)
1161{
1162 struct igmp_group *group;
1163
1164 if (PIM_DEBUG_IGMP_TRACE) {
1165 char source_str[100];
1166 char group_str[100];
1167 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1168 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1169 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1170 __PRETTY_FUNCTION__,
1171 source_str, group_str,
1172 source->source_group->group_igmp_sock->fd,
1173 source->source_group->group_igmp_sock->interface->name,
1174 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1175 }
1176
1177 /* Prevent IGMP interface from removing multicast route multiple
1178 times */
1179 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1180 return;
1181 }
1182
1183 group = source->source_group;
1184
1185 if (del_oif(source->source_channel_oil,
1186 group->group_igmp_sock->interface,
1187 PIM_OIF_FLAG_PROTO_IGMP)) {
1188 return;
1189 }
1190
1191 /*
1192 Feed IGMPv3-gathered local membership information into PIM
1193 per-interface (S,G) state.
1194 */
1195 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1196 source->source_addr, group->group_addr);
1197
1198 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1199}
1200
1201void pim_forward_start(struct pim_ifchannel *ch)
1202{
1203 struct pim_upstream *up = ch->upstream;
1204
1205 if (PIM_DEBUG_PIM_TRACE) {
1206 char source_str[100];
1207 char group_str[100];
1208 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1209 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1210 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1211 __PRETTY_FUNCTION__,
1212 source_str, group_str, ch->interface->name);
1213 }
1214
1215 if (!up->channel_oil) {
1216 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1217 if (input_iface_vif_index < 1) {
1218 char source_str[100];
1219 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1220 zlog_warn("%s %s: could not find input interface for source %s",
1221 __FILE__, __PRETTY_FUNCTION__,
1222 source_str);
1223 return;
1224 }
1225
1226 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1227 input_iface_vif_index);
1228 if (!up->channel_oil) {
1229 char group_str[100];
1230 char source_str[100];
1231 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1232 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1233 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1234 __FILE__, __PRETTY_FUNCTION__,
1235 source_str, group_str);
1236 return;
1237 }
1238 }
1239
1240 add_oif(up->channel_oil,
1241 ch->interface,
1242 PIM_OIF_FLAG_PROTO_PIM);
1243}
1244
1245void pim_forward_stop(struct pim_ifchannel *ch)
1246{
1247 struct pim_upstream *up = ch->upstream;
1248
1249 if (PIM_DEBUG_PIM_TRACE) {
1250 char source_str[100];
1251 char group_str[100];
1252 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1253 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1254 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1255 __PRETTY_FUNCTION__,
1256 source_str, group_str, ch->interface->name);
1257 }
1258
1259 if (!up->channel_oil) {
1260 char source_str[100];
1261 char group_str[100];
1262 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1263 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1264 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1265 __PRETTY_FUNCTION__,
1266 source_str, group_str, ch->interface->name);
1267
1268 return;
1269 }
1270
1271 del_oif(up->channel_oil,
1272 ch->interface,
1273 PIM_OIF_FLAG_PROTO_PIM);
1274}