blob: 6f241d596ba1d26af3b458a1f423cf61760d2403 [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
David Lamparter5d5af782015-02-04 06:33:59 +010066 /* 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
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -0300114
115 comments in lib/zclient.c seem to indicate that calling
116 zebra_interface_add_read is the correct call, but that
117 results in an attemted out of bounds read which causes
118 pimd to assert. Other clients use zebra_interface_state_read
119 and it appears to work just fine.
Everton Marques871dbcf2009-08-11 15:43:05 -0300120 */
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -0300121 ifp = zebra_interface_state_read(zclient->ibuf);
Everton Marques871dbcf2009-08-11 15:43:05 -0300122 if (!ifp)
123 return 0;
124
125 if (PIM_DEBUG_ZEBRA) {
126 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
127 __PRETTY_FUNCTION__,
128 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
129 ifp->mtu, if_is_operative(ifp));
130 }
131
132 if (!if_is_operative(ifp))
133 pim_if_addr_del_all(ifp);
134
135 return 0;
136}
137
138static int pim_zebra_if_state_up(int command, struct zclient *zclient,
139 zebra_size_t length)
140{
141 struct interface *ifp;
142
143 /*
144 zebra api notifies interface up/down events by using the same call
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -0300145 zebra_interface_state_read below, see comments in lib/zclient.c
Everton Marques871dbcf2009-08-11 15:43:05 -0300146 */
147 ifp = zebra_interface_state_read(zclient->ibuf);
148 if (!ifp)
149 return 0;
150
Everton Marques85385f72015-01-19 18:25:45 -0200151 zlog_info("INTERFACE UP: %s ifindex=%d", ifp->name, ifp->ifindex);
Everton Marquese96f0af2009-08-11 15:48:02 -0300152
Everton Marques871dbcf2009-08-11 15:43:05 -0300153 if (PIM_DEBUG_ZEBRA) {
154 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
155 __PRETTY_FUNCTION__,
156 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
157 ifp->mtu, if_is_operative(ifp));
158 }
159
160 if (if_is_operative(ifp)) {
161 /*
162 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
163 */
164 pim_if_addr_add_all(ifp);
165 }
166
167 return 0;
168}
169
170static int pim_zebra_if_state_down(int command, struct zclient *zclient,
171 zebra_size_t length)
172{
173 struct interface *ifp;
174
175 /*
176 zebra api notifies interface up/down events by using the same call
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -0300177 zebra_interface_state_read below, see comments in lib/zclient.c
Everton Marques871dbcf2009-08-11 15:43:05 -0300178 */
179 ifp = zebra_interface_state_read(zclient->ibuf);
180 if (!ifp)
181 return 0;
182
Everton Marques85385f72015-01-19 18:25:45 -0200183 zlog_info("INTERFACE DOWN: %s ifindex=%d", ifp->name, ifp->ifindex);
Everton Marquese96f0af2009-08-11 15:48:02 -0300184
Everton Marques871dbcf2009-08-11 15:43:05 -0300185 if (PIM_DEBUG_ZEBRA) {
186 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
187 __PRETTY_FUNCTION__,
188 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
189 ifp->mtu, if_is_operative(ifp));
190 }
191
192 if (!if_is_operative(ifp)) {
193 /*
194 pim_if_addr_del_all() suffices for shutting down IGMP,
195 but not for shutting down PIM
196 */
197 pim_if_addr_del_all(ifp);
198
199 /*
200 pim_sock_delete() closes the socket, stops read and timer threads,
201 and kills all neighbors.
202 */
Everton Marquese96f0af2009-08-11 15:48:02 -0300203 if (ifp->info) {
204 pim_sock_delete(ifp, "link down");
205 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300206 }
207
208 return 0;
209}
210
211#ifdef PIM_DEBUG_IFADDR_DUMP
212static void dump_if_address(struct interface *ifp)
213{
214 struct connected *ifc;
215 struct listnode *node;
216
217 zlog_debug("%s %s: interface %s addresses:",
218 __FILE__, __PRETTY_FUNCTION__,
219 ifp->name);
220
221 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
222 struct prefix *p = ifc->address;
223
224 if (p->family != AF_INET)
225 continue;
226
Everton Marques306c99e2014-07-16 15:51:37 -0300227 zlog_debug("%s %s: interface %s address %s %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300228 __FILE__, __PRETTY_FUNCTION__,
229 ifp->name,
Everton Marques306c99e2014-07-16 15:51:37 -0300230 inet_ntoa(p->u.prefix4),
231 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
232 "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300233 }
234}
235#endif
236
237static int pim_zebra_if_address_add(int command, struct zclient *zclient,
238 zebra_size_t length)
239{
240 struct connected *c;
241 struct prefix *p;
242
243 zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD);
244
245 /*
246 zebra api notifies address adds/dels events by using the same call
247 interface_add_read below, see comments in lib/zclient.c
248
249 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
250 will add address to interface list by calling
251 connected_add_by_prefix()
252 */
253 c = zebra_interface_address_read(command, zclient->ibuf);
254 if (!c)
255 return 0;
256
257 p = c->address;
258 if (p->family != AF_INET)
259 return 0;
260
261 if (PIM_DEBUG_ZEBRA) {
262 char buf[BUFSIZ];
263 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300264 zlog_debug("%s: %s connected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300265 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300266 c->ifp->name, buf, c->flags,
267 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300268
269#ifdef PIM_DEBUG_IFADDR_DUMP
270 dump_if_address(c->ifp);
271#endif
272 }
273
Everton Marques306c99e2014-07-16 15:51:37 -0300274 if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
275 /* trying to add primary address */
276
277 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
278 if (primary_addr.s_addr != p->u.prefix4.s_addr) {
279 /* but we had a primary address already */
280
281 char buf[BUFSIZ];
282 char old[100];
283
284 prefix2str(p, buf, BUFSIZ);
285 pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
286
287 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
288 __PRETTY_FUNCTION__,
289 c->ifp->name, old, buf);
290 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
291 }
292 }
293
Everton Marques871dbcf2009-08-11 15:43:05 -0300294 pim_if_addr_add(c);
295
296 return 0;
297}
298
299static int pim_zebra_if_address_del(int command, struct zclient *client,
300 zebra_size_t length)
301{
302 struct connected *c;
303 struct prefix *p;
304
305 zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE);
306
307 /*
308 zebra api notifies address adds/dels events by using the same call
309 interface_add_read below, see comments in lib/zclient.c
310
311 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
312 will remove address from interface list by calling
313 connected_delete_by_prefix()
314 */
315 c = zebra_interface_address_read(command, client->ibuf);
316 if (!c)
317 return 0;
318
319 p = c->address;
320 if (p->family != AF_INET)
321 return 0;
322
323 if (PIM_DEBUG_ZEBRA) {
324 char buf[BUFSIZ];
325 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300326 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300327 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300328 c->ifp->name, buf, c->flags,
329 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300330
331#ifdef PIM_DEBUG_IFADDR_DUMP
332 dump_if_address(c->ifp);
333#endif
334 }
Everton Marques306c99e2014-07-16 15:51:37 -0300335
Everton Marques2a0ecf22014-09-22 18:18:26 -0300336 pim_if_addr_del(c, 0);
Everton Marques871dbcf2009-08-11 15:43:05 -0300337
338 return 0;
339}
340
341static void scan_upstream_rpf_cache()
342{
343 struct listnode *up_node;
344 struct listnode *up_nextnode;
345 struct pim_upstream *up;
346
347 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
348 struct in_addr old_rpf_addr;
349 enum pim_rpf_result rpf_result;
350
351 rpf_result = pim_rpf_update(up, &old_rpf_addr);
352 if (rpf_result == PIM_RPF_FAILURE)
353 continue;
354
355 if (rpf_result == PIM_RPF_CHANGED) {
356
357 if (up->join_state == PIM_UPSTREAM_JOINED) {
358
359 /*
360 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
361
362 Transitions from Joined State
363
364 RPF'(S,G) changes not due to an Assert
365
366 The upstream (S,G) state machine remains in Joined
367 state. Send Join(S,G) to the new upstream neighbor, which is
368 the new value of RPF'(S,G). Send Prune(S,G) to the old
369 upstream neighbor, which is the old value of RPF'(S,G). Set
370 the Join Timer (JT) to expire after t_periodic seconds.
371 */
372
373
374 /* send Prune(S,G) to the old upstream neighbor */
375 pim_joinprune_send(up->rpf.source_nexthop.interface,
376 old_rpf_addr,
377 up->source_addr,
378 up->group_addr,
379 0 /* prune */);
380
381 /* send Join(S,G) to the current upstream neighbor */
382 pim_joinprune_send(up->rpf.source_nexthop.interface,
383 up->rpf.rpf_addr,
384 up->source_addr,
385 up->group_addr,
386 1 /* join */);
387
388 pim_upstream_join_timer_restart(up);
389 } /* up->join_state == PIM_UPSTREAM_JOINED */
390
391 /* FIXME can join_desired actually be changed by pim_rpf_update()
392 returning PIM_RPF_CHANGED ? */
393 pim_upstream_update_join_desired(up);
394
395 } /* PIM_RPF_CHANGED */
396
397 } /* for (qpim_upstream_list) */
398
399}
400
Everton Marquesf24200d2014-02-14 16:40:34 -0200401void pim_scan_oil()
Everton Marques871dbcf2009-08-11 15:43:05 -0300402{
403 struct listnode *node;
404 struct listnode *nextnode;
405 struct channel_oil *c_oil;
406
Everton Marquesf24200d2014-02-14 16:40:34 -0200407 qpim_scan_oil_last = pim_time_monotonic_sec();
408 ++qpim_scan_oil_events;
409
Everton Marques871dbcf2009-08-11 15:43:05 -0300410 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
411 int old_vif_index;
412 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
413 if (input_iface_vif_index < 1) {
414 char source_str[100];
415 char group_str[100];
416 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
417 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
418 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
419 __FILE__, __PRETTY_FUNCTION__,
420 source_str, group_str);
421 continue;
422 }
423
424 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
425 /* RPF unchanged */
426 continue;
427 }
428
429 if (PIM_DEBUG_ZEBRA) {
430 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
431 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
432 char source_str[100];
433 char group_str[100];
434 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
435 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
436 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
437 __FILE__, __PRETTY_FUNCTION__,
438 source_str, group_str,
439 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
440 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
441 }
442
443 /* new iif loops to existing oif ? */
444 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
445 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
446
447 if (PIM_DEBUG_ZEBRA) {
448 char source_str[100];
449 char group_str[100];
450 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
451 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
452 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
453 __FILE__, __PRETTY_FUNCTION__,
454 source_str, group_str,
455 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
456 }
457
458 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
459 }
460
461 /* update iif vif_index */
462 old_vif_index = c_oil->oil.mfcc_parent;
463 c_oil->oil.mfcc_parent = input_iface_vif_index;
464
465 /* update kernel multicast forwarding cache (MFC) */
466 if (pim_mroute_add(&c_oil->oil)) {
467 /* just log warning */
468 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
469 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
470 char source_str[100];
471 char group_str[100];
472 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
473 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
474 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
475 __FILE__, __PRETTY_FUNCTION__,
476 source_str, group_str,
477 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
478 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
479 continue;
480 }
481
482 } /* for (qpim_channel_oil_list) */
483}
484
485static int on_rpf_cache_refresh(struct thread *t)
486{
487 zassert(t);
488 zassert(qpim_rpf_cache_refresher);
489
490 qpim_rpf_cache_refresher = 0;
491
492 /* update PIM protocol state */
493 scan_upstream_rpf_cache();
494
495 /* update kernel multicast forwarding cache (MFC) */
Everton Marquesf24200d2014-02-14 16:40:34 -0200496 pim_scan_oil();
Everton Marques871dbcf2009-08-11 15:43:05 -0300497
Everton Marquesbcc4abe2009-08-17 18:18:59 -0300498 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
Everton Marques613938d2009-08-13 15:39:31 -0300499 ++qpim_rpf_cache_refresh_events;
500
Everton Marques871dbcf2009-08-11 15:43:05 -0300501 return 0;
502}
503
504static void sched_rpf_cache_refresh()
505{
Everton Marques613938d2009-08-13 15:39:31 -0300506 ++qpim_rpf_cache_refresh_requests;
507
508 if (qpim_rpf_cache_refresher) {
509 /* Refresh timer is already running */
Everton Marques871dbcf2009-08-11 15:43:05 -0300510 return;
Everton Marques613938d2009-08-13 15:39:31 -0300511 }
512
513 /* Start refresh timer */
Everton Marques871dbcf2009-08-11 15:43:05 -0300514
515 if (PIM_DEBUG_ZEBRA) {
516 zlog_debug("%s: triggering %ld msec timer",
517 __PRETTY_FUNCTION__,
518 qpim_rpf_cache_refresh_delay_msec);
519 }
520
521 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
522 on_rpf_cache_refresh,
523 0, qpim_rpf_cache_refresh_delay_msec);
524}
525
526static int redist_read_ipv4_route(int command, struct zclient *zclient,
527 zebra_size_t length)
528{
529 struct stream *s;
530 struct zapi_ipv4 api;
531 unsigned long ifindex;
532 struct in_addr nexthop;
533 struct prefix_ipv4 p;
534 int min_len = 4;
535
536 if (length < min_len) {
537 zlog_warn("%s %s: short buffer: length=%d min=%d",
538 __FILE__, __PRETTY_FUNCTION__,
539 length, min_len);
540 return -1;
541 }
542
543 s = zclient->ibuf;
544 ifindex = 0;
545 nexthop.s_addr = 0;
546
547 /* Type, flags, message. */
548 api.type = stream_getc(s);
549 api.flags = stream_getc(s);
550 api.message = stream_getc(s);
551
552 /* IPv4 prefix length. */
553 memset(&p, 0, sizeof(struct prefix_ipv4));
554 p.family = AF_INET;
555 p.prefixlen = stream_getc(s);
556
557 min_len +=
558 PSIZE(p.prefixlen) +
559 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
560 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
561 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
562 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
563
564 if (PIM_DEBUG_ZEBRA) {
565 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
566 __FILE__, __PRETTY_FUNCTION__,
567 length, min_len,
568 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
569 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
570 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
571 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
572 }
573
574 if (length < min_len) {
575 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
576 __FILE__, __PRETTY_FUNCTION__,
577 length, min_len,
578 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
579 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
580 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
581 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
582 return -1;
583 }
584
585 /* IPv4 prefix. */
586 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
587
588 /* Nexthop, ifindex, distance, metric. */
589 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
590 api.nexthop_num = stream_getc(s);
591 nexthop.s_addr = stream_get_ipv4(s);
592 }
593 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
594 api.ifindex_num = stream_getc(s);
595 ifindex = stream_getl(s);
596 }
597
598 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
David Lamparter105ad862012-02-16 04:50:35 +0000599 stream_getc(s) :
Everton Marques871dbcf2009-08-11 15:43:05 -0300600 0;
601
602 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
603 stream_getl(s) :
604 0;
605
606 switch (command) {
607 case ZEBRA_IPV4_ROUTE_ADD:
608 if (PIM_DEBUG_ZEBRA) {
609 char buf[2][INET_ADDRSTRLEN];
610 zlog_debug("%s: add %s %s/%d "
611 "nexthop %s ifindex %ld metric%s %u distance%s %u",
612 __PRETTY_FUNCTION__,
613 zebra_route_string(api.type),
614 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
615 p.prefixlen,
616 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
617 ifindex,
618 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
619 api.metric,
620 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
621 api.distance);
622 }
623 break;
624 case ZEBRA_IPV4_ROUTE_DELETE:
625 if (PIM_DEBUG_ZEBRA) {
626 char buf[2][INET_ADDRSTRLEN];
627 zlog_debug("%s: delete %s %s/%d "
628 "nexthop %s ifindex %ld metric%s %u distance%s %u",
629 __PRETTY_FUNCTION__,
630 zebra_route_string(api.type),
631 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
632 p.prefixlen,
633 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
634 ifindex,
635 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
636 api.metric,
637 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
638 api.distance);
639 }
640 break;
641 default:
642 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
643 return -1;
644 }
645
646 sched_rpf_cache_refresh();
647
648 return 0;
649}
650
Everton Marques1f298942014-08-21 15:47:28 -0300651void pim_zebra_init(char *zebra_sock_path)
Everton Marques871dbcf2009-08-11 15:43:05 -0300652{
Everton Marques871dbcf2009-08-11 15:43:05 -0300653 int i;
654
Everton Marques1f298942014-08-21 15:47:28 -0300655 if (zebra_sock_path)
656 zclient_serv_path_set(zebra_sock_path);
657
Everton Marques871dbcf2009-08-11 15:43:05 -0300658#ifdef HAVE_TCP_ZEBRA
659 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
660#else
Everton Marques1f298942014-08-21 15:47:28 -0300661 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
Everton Marques871dbcf2009-08-11 15:43:05 -0300662#endif
663
664 /* Socket for receiving updates from Zebra daemon */
Everton Marques3456a802014-07-22 14:52:57 -0300665 qpim_zclient_update = zclient_new();
Everton Marques871dbcf2009-08-11 15:43:05 -0300666
Everton Marques3456a802014-07-22 14:52:57 -0300667 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
668 qpim_zclient_update->interface_add = pim_zebra_if_add;
669 qpim_zclient_update->interface_delete = pim_zebra_if_del;
670 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
671 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
672 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
673 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
674 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
675 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
Everton Marques871dbcf2009-08-11 15:43:05 -0300676
David Lampartera2805de2015-02-04 06:33:26 +0100677 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300678 if (PIM_DEBUG_PIM_TRACE) {
679 zlog_info("zclient_init cleared redistribution request");
680 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300681
Everton Marques3456a802014-07-22 14:52:57 -0300682 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300683
684 /* Request all redistribution */
685 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300686 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300687 continue;
Everton Marques3456a802014-07-22 14:52:57 -0300688 qpim_zclient_update->redist[i] = 1;
Everton Marquesc1b228c2014-08-27 15:27:26 -0300689 if (PIM_DEBUG_PIM_TRACE) {
690 zlog_debug("%s: requesting redistribution for %s (%i)",
691 __PRETTY_FUNCTION__, zebra_route_string(i), i);
692 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300693 }
694
695 /* Request default information */
Everton Marques3456a802014-07-22 14:52:57 -0300696 qpim_zclient_update->default_information = 1;
Everton Marquesc1b228c2014-08-27 15:27:26 -0300697 if (PIM_DEBUG_PIM_TRACE) {
698 zlog_info("%s: requesting default information redistribution",
Everton Marques871dbcf2009-08-11 15:43:05 -0300699 __PRETTY_FUNCTION__);
700
Everton Marquesc1b228c2014-08-27 15:27:26 -0300701 zlog_notice("%s: zclient update socket initialized",
702 __PRETTY_FUNCTION__);
703 }
704
Everton Marques871dbcf2009-08-11 15:43:05 -0300705 zassert(!qpim_zclient_lookup);
706 qpim_zclient_lookup = zclient_lookup_new();
707 zassert(qpim_zclient_lookup);
708}
709
710void igmp_anysource_forward_start(struct igmp_group *group)
711{
712 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
713 zassert(group->group_filtermode_isexcl);
714 zassert(listcount(group->group_source_list) < 1);
715
716 if (PIM_DEBUG_IGMP_TRACE) {
717 zlog_debug("%s %s: UNIMPLEMENTED",
718 __FILE__, __PRETTY_FUNCTION__);
719 }
720}
721
722void igmp_anysource_forward_stop(struct igmp_group *group)
723{
724 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
725 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
726
727 if (PIM_DEBUG_IGMP_TRACE) {
728 zlog_debug("%s %s: UNIMPLEMENTED",
729 __FILE__, __PRETTY_FUNCTION__);
730 }
731}
732
733static int fib_lookup_if_vif_index(struct in_addr addr)
734{
735 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
736 int num_ifindex;
737 int vif_index;
738 int first_ifindex;
739
740 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
741 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
742 PIM_NEXTHOP_LOOKUP_MAX);
743 if (num_ifindex < 1) {
744 char addr_str[100];
745 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
746 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
747 __FILE__, __PRETTY_FUNCTION__,
748 addr_str);
749 return -1;
750 }
751
752 first_ifindex = nexthop_tab[0].ifindex;
753
754 if (num_ifindex > 1) {
755 char addr_str[100];
756 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
757 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
758 __FILE__, __PRETTY_FUNCTION__,
759 num_ifindex, addr_str, first_ifindex);
760 /* debug warning only, do not return */
761 }
762
763 if (PIM_DEBUG_ZEBRA) {
764 char addr_str[100];
765 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
766 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
767 __FILE__, __PRETTY_FUNCTION__,
768 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
769 }
770
771 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
772
773 if (vif_index < 1) {
774 char addr_str[100];
775 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
776 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
777 __FILE__, __PRETTY_FUNCTION__,
778 vif_index, addr_str);
779 return -2;
780 }
781
782 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
783
784 if (vif_index > qpim_mroute_oif_highest_vif_index) {
785 char addr_str[100];
786 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
787 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
788 __FILE__, __PRETTY_FUNCTION__,
789 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
790
791 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
792 __FILE__, __PRETTY_FUNCTION__,
793 ifindex2ifname(vif_index),
794 vif_index);
795
796 return -3;
797 }
798
799 return vif_index;
800}
801
802static int add_oif(struct channel_oil *channel_oil,
803 struct interface *oif,
804 uint32_t proto_mask)
805{
806 struct pim_interface *pim_ifp;
807 int old_ttl;
808
809 zassert(channel_oil);
810
811 pim_ifp = oif->info;
812
Everton Marques67faabc2010-02-23 12:11:11 -0300813 if (PIM_DEBUG_MROUTE) {
814 char group_str[100];
815 char source_str[100];
816 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
817 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
818 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
819 __FILE__, __PRETTY_FUNCTION__,
820 source_str, group_str,
821 proto_mask, oif->name, pim_ifp->mroute_vif_index);
822 }
823
Everton Marques871dbcf2009-08-11 15:43:05 -0300824 if (pim_ifp->mroute_vif_index < 1) {
825 zlog_warn("%s %s: interface %s vif_index=%d < 1",
826 __FILE__, __PRETTY_FUNCTION__,
827 oif->name, pim_ifp->mroute_vif_index);
828 return -1;
829 }
830
831#ifdef PIM_ENFORCE_LOOPFREE_MFC
832 /*
833 Prevent creating MFC entry with OIF=IIF.
834
835 This is a protection against implementation mistakes.
836
837 PIM protocol implicitely ensures loopfree multicast topology.
838
839 IGMP must be protected against adding looped MFC entries created
840 by both source and receiver attached to the same interface. See
841 TODO T22.
842 */
843 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
844 char group_str[100];
845 char source_str[100];
846 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
847 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
848 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
849 __FILE__, __PRETTY_FUNCTION__,
850 proto_mask, oif->name, pim_ifp->mroute_vif_index,
851 source_str, group_str);
852 return -2;
853 }
854#endif
855
856 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
857 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
858
859 /* Prevent single protocol from subscribing same interface to
860 channel (S,G) multiple times */
861 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
862 char group_str[100];
863 char source_str[100];
864 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
865 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
866 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
867 __FILE__, __PRETTY_FUNCTION__,
868 proto_mask, oif->name, pim_ifp->mroute_vif_index,
869 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
870 source_str, group_str);
871 return -3;
872 }
873
874 /* Allow other protocol to request subscription of same interface to
875 channel (S,G) multiple times, by silently ignoring further
876 requests */
877 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
878
879 /* Check the OIF really exists before returning, and only log
880 warning otherwise */
881 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
882 char group_str[100];
883 char source_str[100];
884 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
885 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
886 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
887 __FILE__, __PRETTY_FUNCTION__,
888 proto_mask, oif->name, pim_ifp->mroute_vif_index,
889 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
890 source_str, group_str);
891 }
892
893 return 0;
894 }
895
896 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
897
898 if (old_ttl > 0) {
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: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
904 __FILE__, __PRETTY_FUNCTION__,
905 oif->name, pim_ifp->mroute_vif_index,
906 source_str, group_str);
907 return -4;
908 }
909
910 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
911
912 if (pim_mroute_add(&channel_oil->oil)) {
913 char group_str[100];
914 char source_str[100];
915 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
916 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
917 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
918 __FILE__, __PRETTY_FUNCTION__,
919 oif->name, pim_ifp->mroute_vif_index,
920 source_str, group_str);
921
922 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
923 return -5;
924 }
925
926 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
927 ++channel_oil->oil_size;
928 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
929
Everton Marques67faabc2010-02-23 12:11:11 -0300930 if (PIM_DEBUG_MROUTE) {
931 char group_str[100];
932 char source_str[100];
933 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
934 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
935 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
936 __FILE__, __PRETTY_FUNCTION__,
937 source_str, group_str,
938 proto_mask, oif->name, pim_ifp->mroute_vif_index);
939 }
940
Everton Marques871dbcf2009-08-11 15:43:05 -0300941 return 0;
942}
943
944static int del_oif(struct channel_oil *channel_oil,
945 struct interface *oif,
946 uint32_t proto_mask)
947{
948 struct pim_interface *pim_ifp;
949 int old_ttl;
950
951 zassert(channel_oil);
952
953 pim_ifp = oif->info;
954
955 zassert(pim_ifp->mroute_vif_index >= 1);
956 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
957 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
958
Everton Marques67faabc2010-02-23 12:11:11 -0300959 if (PIM_DEBUG_MROUTE) {
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_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
965 __FILE__, __PRETTY_FUNCTION__,
966 source_str, group_str,
967 proto_mask, oif->name, pim_ifp->mroute_vif_index);
968 }
969
Everton Marques871dbcf2009-08-11 15:43:05 -0300970 /* Prevent single protocol from unsubscribing same interface from
971 channel (S,G) multiple times */
972 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
973 char group_str[100];
974 char source_str[100];
975 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
976 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
977 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
978 __FILE__, __PRETTY_FUNCTION__,
979 proto_mask, oif->name, pim_ifp->mroute_vif_index,
980 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
981 source_str, group_str);
982 return -2;
983 }
984
985 /* Mark that protocol is no longer interested in this OIF */
986 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
987
988 /* Allow multiple protocols to unsubscribe same interface from
989 channel (S,G) multiple times, by silently ignoring requests while
990 there is at least one protocol interested in the channel */
991 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
992
993 /* Check the OIF keeps existing before returning, and only log
994 warning otherwise */
995 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
996 char group_str[100];
997 char source_str[100];
998 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
999 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1000 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
1001 __FILE__, __PRETTY_FUNCTION__,
1002 proto_mask, oif->name, pim_ifp->mroute_vif_index,
1003 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
1004 source_str, group_str);
1005 }
1006
1007 return 0;
1008 }
1009
1010 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1011
1012 if (old_ttl < 1) {
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: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1018 __FILE__, __PRETTY_FUNCTION__,
1019 oif->name, pim_ifp->mroute_vif_index,
1020 source_str, group_str);
1021 return -3;
1022 }
1023
1024 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1025
1026 if (pim_mroute_add(&channel_oil->oil)) {
1027 char group_str[100];
1028 char source_str[100];
1029 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1030 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1031 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1032 __FILE__, __PRETTY_FUNCTION__,
1033 oif->name, pim_ifp->mroute_vif_index,
1034 source_str, group_str);
1035
1036 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1037 return -4;
1038 }
1039
1040 --channel_oil->oil_size;
1041
1042 if (channel_oil->oil_size < 1) {
1043 if (pim_mroute_del(&channel_oil->oil)) {
1044 /* just log a warning in case of failure */
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_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1050 __FILE__, __PRETTY_FUNCTION__,
1051 source_str, group_str);
1052 }
1053 }
1054
Everton Marques67faabc2010-02-23 12:11:11 -03001055 if (PIM_DEBUG_MROUTE) {
1056 char group_str[100];
1057 char source_str[100];
1058 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1059 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1060 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1061 __FILE__, __PRETTY_FUNCTION__,
1062 source_str, group_str,
1063 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1064 }
1065
Everton Marques871dbcf2009-08-11 15:43:05 -03001066 return 0;
1067}
1068
1069void igmp_source_forward_start(struct igmp_source *source)
1070{
1071 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001072 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001073
1074 if (PIM_DEBUG_IGMP_TRACE) {
1075 char source_str[100];
1076 char group_str[100];
1077 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1078 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1079 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1080 __PRETTY_FUNCTION__,
1081 source_str, group_str,
1082 source->source_group->group_igmp_sock->fd,
1083 source->source_group->group_igmp_sock->interface->name,
1084 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1085 }
1086
1087 /* Prevent IGMP interface from installing multicast route multiple
1088 times */
1089 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1090 return;
1091 }
1092
1093 group = source->source_group;
1094
1095 if (!source->source_channel_oil) {
1096 struct pim_interface *pim_oif;
1097 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1098 if (input_iface_vif_index < 1) {
1099 char source_str[100];
1100 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1101 zlog_warn("%s %s: could not find input interface for source %s",
1102 __FILE__, __PRETTY_FUNCTION__,
1103 source_str);
1104 return;
1105 }
1106
1107 /*
1108 Protect IGMP against adding looped MFC entries created by both
1109 source and receiver attached to the same interface. See TODO
1110 T22.
1111 */
1112 pim_oif = source->source_group->group_igmp_sock->interface->info;
1113 if (!pim_oif) {
1114 zlog_warn("%s: multicast not enabled on oif=%s ?",
1115 __PRETTY_FUNCTION__,
1116 source->source_group->group_igmp_sock->interface->name);
1117 return;
1118 }
1119 if (pim_oif->mroute_vif_index < 1) {
1120 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1121 __FILE__, __PRETTY_FUNCTION__,
1122 source->source_group->group_igmp_sock->interface->name,
1123 pim_oif->mroute_vif_index);
1124 return;
1125 }
1126 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1127 /* ignore request for looped MFC entry */
1128 if (PIM_DEBUG_IGMP_TRACE) {
1129 char source_str[100];
1130 char group_str[100];
1131 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1132 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1133 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1134 __PRETTY_FUNCTION__,
1135 source_str, group_str,
1136 source->source_group->group_igmp_sock->fd,
1137 source->source_group->group_igmp_sock->interface->name,
1138 input_iface_vif_index);
1139 }
1140 return;
1141 }
1142
1143 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1144 source->source_addr,
1145 input_iface_vif_index);
1146 if (!source->source_channel_oil) {
1147 char group_str[100];
1148 char source_str[100];
1149 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1150 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1151 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1152 __FILE__, __PRETTY_FUNCTION__,
1153 source_str, group_str);
1154 return;
1155 }
1156 }
1157
Everton Marques24e3a9b2014-09-30 19:14:19 -03001158 result = add_oif(source->source_channel_oil,
1159 group->group_igmp_sock->interface,
1160 PIM_OIF_FLAG_PROTO_IGMP);
1161 if (result) {
1162 zlog_warn("%s: add_oif() failed with return=%d",
1163 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001164 return;
1165 }
1166
1167 /*
1168 Feed IGMPv3-gathered local membership information into PIM
1169 per-interface (S,G) state.
1170 */
1171 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1172 source->source_addr, group->group_addr);
1173
1174 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1175}
1176
Everton Marques24e3a9b2014-09-30 19:14:19 -03001177/*
1178 igmp_source_forward_stop: stop fowarding, but keep the source
1179 igmp_source_delete: stop fowarding, and delete the source
1180 */
Everton Marques871dbcf2009-08-11 15:43:05 -03001181void igmp_source_forward_stop(struct igmp_source *source)
1182{
1183 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001184 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001185
1186 if (PIM_DEBUG_IGMP_TRACE) {
1187 char source_str[100];
1188 char group_str[100];
1189 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1190 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1191 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1192 __PRETTY_FUNCTION__,
1193 source_str, group_str,
1194 source->source_group->group_igmp_sock->fd,
1195 source->source_group->group_igmp_sock->interface->name,
1196 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1197 }
1198
1199 /* Prevent IGMP interface from removing multicast route multiple
1200 times */
1201 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1202 return;
1203 }
1204
1205 group = source->source_group;
1206
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001207 /*
1208 It appears that in certain circumstances that
1209 igmp_source_forward_stop is called when IGMP forwarding
1210 was not enabled in oif_flags for this outgoing interface.
1211 Possibly because of multiple calls. When that happens, we
1212 enter the below if statement and this function returns early
1213 which in turn triggers the calling function to assert.
1214 Making the call to del_oif and ignoring the return code
1215 fixes the issue without ill effect, similar to
1216 pim_forward_stop below.
1217 */
Everton Marques24e3a9b2014-09-30 19:14:19 -03001218 result = del_oif(source->source_channel_oil,
1219 group->group_igmp_sock->interface,
1220 PIM_OIF_FLAG_PROTO_IGMP);
1221 if (result) {
1222 zlog_warn("%s: del_oif() failed with return=%d",
1223 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001224 return;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001225 }
Everton Marques871dbcf2009-08-11 15:43:05 -03001226
1227 /*
1228 Feed IGMPv3-gathered local membership information into PIM
1229 per-interface (S,G) state.
1230 */
1231 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1232 source->source_addr, group->group_addr);
1233
1234 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1235}
1236
1237void pim_forward_start(struct pim_ifchannel *ch)
1238{
1239 struct pim_upstream *up = ch->upstream;
1240
1241 if (PIM_DEBUG_PIM_TRACE) {
1242 char source_str[100];
1243 char group_str[100];
1244 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1245 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1246 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1247 __PRETTY_FUNCTION__,
1248 source_str, group_str, ch->interface->name);
1249 }
1250
1251 if (!up->channel_oil) {
1252 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1253 if (input_iface_vif_index < 1) {
1254 char source_str[100];
1255 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1256 zlog_warn("%s %s: could not find input interface for source %s",
1257 __FILE__, __PRETTY_FUNCTION__,
1258 source_str);
1259 return;
1260 }
1261
1262 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1263 input_iface_vif_index);
1264 if (!up->channel_oil) {
1265 char group_str[100];
1266 char source_str[100];
1267 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1268 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1269 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1270 __FILE__, __PRETTY_FUNCTION__,
1271 source_str, group_str);
1272 return;
1273 }
1274 }
1275
1276 add_oif(up->channel_oil,
1277 ch->interface,
1278 PIM_OIF_FLAG_PROTO_PIM);
1279}
1280
1281void pim_forward_stop(struct pim_ifchannel *ch)
1282{
1283 struct pim_upstream *up = ch->upstream;
1284
1285 if (PIM_DEBUG_PIM_TRACE) {
1286 char source_str[100];
1287 char group_str[100];
1288 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1289 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1290 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1291 __PRETTY_FUNCTION__,
1292 source_str, group_str, ch->interface->name);
1293 }
1294
1295 if (!up->channel_oil) {
1296 char source_str[100];
1297 char group_str[100];
1298 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1299 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1300 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1301 __PRETTY_FUNCTION__,
1302 source_str, group_str, ch->interface->name);
1303
1304 return;
1305 }
1306
1307 del_oif(up->channel_oil,
1308 ch->interface,
1309 PIM_OIF_FLAG_PROTO_PIM);
1310}