blob: 43c80c8b9eb3b5fe5d67c2a1f4c5b115af4ede66 [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->zclient_broken = zclient_broken;
668 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
669 qpim_zclient_update->interface_add = pim_zebra_if_add;
670 qpim_zclient_update->interface_delete = pim_zebra_if_del;
671 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
672 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
673 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
674 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
675 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
676 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
Everton Marques871dbcf2009-08-11 15:43:05 -0300677
David Lampartera2805de2015-02-04 06:33:26 +0100678 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300679 if (PIM_DEBUG_PIM_TRACE) {
680 zlog_info("zclient_init cleared redistribution request");
681 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300682
Everton Marques3456a802014-07-22 14:52:57 -0300683 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300684
685 /* Request all redistribution */
686 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300687 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300688 continue;
Everton Marques3456a802014-07-22 14:52:57 -0300689 qpim_zclient_update->redist[i] = 1;
Everton Marquesc1b228c2014-08-27 15:27:26 -0300690 if (PIM_DEBUG_PIM_TRACE) {
691 zlog_debug("%s: requesting redistribution for %s (%i)",
692 __PRETTY_FUNCTION__, zebra_route_string(i), i);
693 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300694 }
695
696 /* Request default information */
Everton Marques3456a802014-07-22 14:52:57 -0300697 qpim_zclient_update->default_information = 1;
Everton Marquesc1b228c2014-08-27 15:27:26 -0300698 if (PIM_DEBUG_PIM_TRACE) {
699 zlog_info("%s: requesting default information redistribution",
Everton Marques871dbcf2009-08-11 15:43:05 -0300700 __PRETTY_FUNCTION__);
701
Everton Marquesc1b228c2014-08-27 15:27:26 -0300702 zlog_notice("%s: zclient update socket initialized",
703 __PRETTY_FUNCTION__);
704 }
705
Everton Marques871dbcf2009-08-11 15:43:05 -0300706 zassert(!qpim_zclient_lookup);
707 qpim_zclient_lookup = zclient_lookup_new();
708 zassert(qpim_zclient_lookup);
709}
710
711void igmp_anysource_forward_start(struct igmp_group *group)
712{
713 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
714 zassert(group->group_filtermode_isexcl);
715 zassert(listcount(group->group_source_list) < 1);
716
717 if (PIM_DEBUG_IGMP_TRACE) {
718 zlog_debug("%s %s: UNIMPLEMENTED",
719 __FILE__, __PRETTY_FUNCTION__);
720 }
721}
722
723void igmp_anysource_forward_stop(struct igmp_group *group)
724{
725 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
726 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
727
728 if (PIM_DEBUG_IGMP_TRACE) {
729 zlog_debug("%s %s: UNIMPLEMENTED",
730 __FILE__, __PRETTY_FUNCTION__);
731 }
732}
733
734static int fib_lookup_if_vif_index(struct in_addr addr)
735{
736 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
737 int num_ifindex;
738 int vif_index;
739 int first_ifindex;
740
741 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
742 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
743 PIM_NEXTHOP_LOOKUP_MAX);
744 if (num_ifindex < 1) {
745 char addr_str[100];
746 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
747 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
748 __FILE__, __PRETTY_FUNCTION__,
749 addr_str);
750 return -1;
751 }
752
753 first_ifindex = nexthop_tab[0].ifindex;
754
755 if (num_ifindex > 1) {
756 char addr_str[100];
757 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
758 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
759 __FILE__, __PRETTY_FUNCTION__,
760 num_ifindex, addr_str, first_ifindex);
761 /* debug warning only, do not return */
762 }
763
764 if (PIM_DEBUG_ZEBRA) {
765 char addr_str[100];
766 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
767 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
768 __FILE__, __PRETTY_FUNCTION__,
769 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
770 }
771
772 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
773
774 if (vif_index < 1) {
775 char addr_str[100];
776 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
777 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
778 __FILE__, __PRETTY_FUNCTION__,
779 vif_index, addr_str);
780 return -2;
781 }
782
783 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
784
785 if (vif_index > qpim_mroute_oif_highest_vif_index) {
786 char addr_str[100];
787 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
788 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
789 __FILE__, __PRETTY_FUNCTION__,
790 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
791
792 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
793 __FILE__, __PRETTY_FUNCTION__,
794 ifindex2ifname(vif_index),
795 vif_index);
796
797 return -3;
798 }
799
800 return vif_index;
801}
802
803static int add_oif(struct channel_oil *channel_oil,
804 struct interface *oif,
805 uint32_t proto_mask)
806{
807 struct pim_interface *pim_ifp;
808 int old_ttl;
809
810 zassert(channel_oil);
811
812 pim_ifp = oif->info;
813
Everton Marques67faabc2010-02-23 12:11:11 -0300814 if (PIM_DEBUG_MROUTE) {
815 char group_str[100];
816 char source_str[100];
817 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
818 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
819 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
820 __FILE__, __PRETTY_FUNCTION__,
821 source_str, group_str,
822 proto_mask, oif->name, pim_ifp->mroute_vif_index);
823 }
824
Everton Marques871dbcf2009-08-11 15:43:05 -0300825 if (pim_ifp->mroute_vif_index < 1) {
826 zlog_warn("%s %s: interface %s vif_index=%d < 1",
827 __FILE__, __PRETTY_FUNCTION__,
828 oif->name, pim_ifp->mroute_vif_index);
829 return -1;
830 }
831
832#ifdef PIM_ENFORCE_LOOPFREE_MFC
833 /*
834 Prevent creating MFC entry with OIF=IIF.
835
836 This is a protection against implementation mistakes.
837
838 PIM protocol implicitely ensures loopfree multicast topology.
839
840 IGMP must be protected against adding looped MFC entries created
841 by both source and receiver attached to the same interface. See
842 TODO T22.
843 */
844 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
845 char group_str[100];
846 char source_str[100];
847 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
848 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
849 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
850 __FILE__, __PRETTY_FUNCTION__,
851 proto_mask, oif->name, pim_ifp->mroute_vif_index,
852 source_str, group_str);
853 return -2;
854 }
855#endif
856
857 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
858 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
859
860 /* Prevent single protocol from subscribing same interface to
861 channel (S,G) multiple times */
862 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
863 char group_str[100];
864 char source_str[100];
865 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
866 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
867 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
868 __FILE__, __PRETTY_FUNCTION__,
869 proto_mask, oif->name, pim_ifp->mroute_vif_index,
870 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
871 source_str, group_str);
872 return -3;
873 }
874
875 /* Allow other protocol to request subscription of same interface to
876 channel (S,G) multiple times, by silently ignoring further
877 requests */
878 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
879
880 /* Check the OIF really exists before returning, and only log
881 warning otherwise */
882 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
883 char group_str[100];
884 char source_str[100];
885 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
886 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
887 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
888 __FILE__, __PRETTY_FUNCTION__,
889 proto_mask, oif->name, pim_ifp->mroute_vif_index,
890 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
891 source_str, group_str);
892 }
893
894 return 0;
895 }
896
897 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
898
899 if (old_ttl > 0) {
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: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
905 __FILE__, __PRETTY_FUNCTION__,
906 oif->name, pim_ifp->mroute_vif_index,
907 source_str, group_str);
908 return -4;
909 }
910
911 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
912
913 if (pim_mroute_add(&channel_oil->oil)) {
914 char group_str[100];
915 char source_str[100];
916 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
917 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
918 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
919 __FILE__, __PRETTY_FUNCTION__,
920 oif->name, pim_ifp->mroute_vif_index,
921 source_str, group_str);
922
923 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
924 return -5;
925 }
926
927 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
928 ++channel_oil->oil_size;
929 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
930
Everton Marques67faabc2010-02-23 12:11:11 -0300931 if (PIM_DEBUG_MROUTE) {
932 char group_str[100];
933 char source_str[100];
934 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
935 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
936 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
937 __FILE__, __PRETTY_FUNCTION__,
938 source_str, group_str,
939 proto_mask, oif->name, pim_ifp->mroute_vif_index);
940 }
941
Everton Marques871dbcf2009-08-11 15:43:05 -0300942 return 0;
943}
944
945static int del_oif(struct channel_oil *channel_oil,
946 struct interface *oif,
947 uint32_t proto_mask)
948{
949 struct pim_interface *pim_ifp;
950 int old_ttl;
951
952 zassert(channel_oil);
953
954 pim_ifp = oif->info;
955
956 zassert(pim_ifp->mroute_vif_index >= 1);
957 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
958 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
959
Everton Marques67faabc2010-02-23 12:11:11 -0300960 if (PIM_DEBUG_MROUTE) {
961 char group_str[100];
962 char source_str[100];
963 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
964 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
965 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
966 __FILE__, __PRETTY_FUNCTION__,
967 source_str, group_str,
968 proto_mask, oif->name, pim_ifp->mroute_vif_index);
969 }
970
Everton Marques871dbcf2009-08-11 15:43:05 -0300971 /* Prevent single protocol from unsubscribing same interface from
972 channel (S,G) multiple times */
973 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
974 char group_str[100];
975 char source_str[100];
976 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
977 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
978 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
979 __FILE__, __PRETTY_FUNCTION__,
980 proto_mask, oif->name, pim_ifp->mroute_vif_index,
981 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
982 source_str, group_str);
983 return -2;
984 }
985
986 /* Mark that protocol is no longer interested in this OIF */
987 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
988
989 /* Allow multiple protocols to unsubscribe same interface from
990 channel (S,G) multiple times, by silently ignoring requests while
991 there is at least one protocol interested in the channel */
992 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
993
994 /* Check the OIF keeps existing before returning, and only log
995 warning otherwise */
996 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
997 char group_str[100];
998 char source_str[100];
999 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1000 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1001 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
1002 __FILE__, __PRETTY_FUNCTION__,
1003 proto_mask, oif->name, pim_ifp->mroute_vif_index,
1004 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
1005 source_str, group_str);
1006 }
1007
1008 return 0;
1009 }
1010
1011 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1012
1013 if (old_ttl < 1) {
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: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1019 __FILE__, __PRETTY_FUNCTION__,
1020 oif->name, pim_ifp->mroute_vif_index,
1021 source_str, group_str);
1022 return -3;
1023 }
1024
1025 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1026
1027 if (pim_mroute_add(&channel_oil->oil)) {
1028 char group_str[100];
1029 char source_str[100];
1030 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1031 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1032 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1033 __FILE__, __PRETTY_FUNCTION__,
1034 oif->name, pim_ifp->mroute_vif_index,
1035 source_str, group_str);
1036
1037 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1038 return -4;
1039 }
1040
1041 --channel_oil->oil_size;
1042
1043 if (channel_oil->oil_size < 1) {
1044 if (pim_mroute_del(&channel_oil->oil)) {
1045 /* just log a warning in case of failure */
1046 char group_str[100];
1047 char source_str[100];
1048 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1049 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1050 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1051 __FILE__, __PRETTY_FUNCTION__,
1052 source_str, group_str);
1053 }
1054 }
1055
Everton Marques67faabc2010-02-23 12:11:11 -03001056 if (PIM_DEBUG_MROUTE) {
1057 char group_str[100];
1058 char source_str[100];
1059 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1060 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1061 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1062 __FILE__, __PRETTY_FUNCTION__,
1063 source_str, group_str,
1064 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1065 }
1066
Everton Marques871dbcf2009-08-11 15:43:05 -03001067 return 0;
1068}
1069
1070void igmp_source_forward_start(struct igmp_source *source)
1071{
1072 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001073 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001074
1075 if (PIM_DEBUG_IGMP_TRACE) {
1076 char source_str[100];
1077 char group_str[100];
1078 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1079 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1080 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1081 __PRETTY_FUNCTION__,
1082 source_str, group_str,
1083 source->source_group->group_igmp_sock->fd,
1084 source->source_group->group_igmp_sock->interface->name,
1085 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1086 }
1087
1088 /* Prevent IGMP interface from installing multicast route multiple
1089 times */
1090 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1091 return;
1092 }
1093
1094 group = source->source_group;
1095
1096 if (!source->source_channel_oil) {
1097 struct pim_interface *pim_oif;
1098 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1099 if (input_iface_vif_index < 1) {
1100 char source_str[100];
1101 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1102 zlog_warn("%s %s: could not find input interface for source %s",
1103 __FILE__, __PRETTY_FUNCTION__,
1104 source_str);
1105 return;
1106 }
1107
1108 /*
1109 Protect IGMP against adding looped MFC entries created by both
1110 source and receiver attached to the same interface. See TODO
1111 T22.
1112 */
1113 pim_oif = source->source_group->group_igmp_sock->interface->info;
1114 if (!pim_oif) {
1115 zlog_warn("%s: multicast not enabled on oif=%s ?",
1116 __PRETTY_FUNCTION__,
1117 source->source_group->group_igmp_sock->interface->name);
1118 return;
1119 }
1120 if (pim_oif->mroute_vif_index < 1) {
1121 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1122 __FILE__, __PRETTY_FUNCTION__,
1123 source->source_group->group_igmp_sock->interface->name,
1124 pim_oif->mroute_vif_index);
1125 return;
1126 }
1127 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1128 /* ignore request for looped MFC entry */
1129 if (PIM_DEBUG_IGMP_TRACE) {
1130 char source_str[100];
1131 char group_str[100];
1132 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1133 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1134 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1135 __PRETTY_FUNCTION__,
1136 source_str, group_str,
1137 source->source_group->group_igmp_sock->fd,
1138 source->source_group->group_igmp_sock->interface->name,
1139 input_iface_vif_index);
1140 }
1141 return;
1142 }
1143
1144 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1145 source->source_addr,
1146 input_iface_vif_index);
1147 if (!source->source_channel_oil) {
1148 char group_str[100];
1149 char source_str[100];
1150 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1151 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1152 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1153 __FILE__, __PRETTY_FUNCTION__,
1154 source_str, group_str);
1155 return;
1156 }
1157 }
1158
Everton Marques24e3a9b2014-09-30 19:14:19 -03001159 result = add_oif(source->source_channel_oil,
1160 group->group_igmp_sock->interface,
1161 PIM_OIF_FLAG_PROTO_IGMP);
1162 if (result) {
1163 zlog_warn("%s: add_oif() failed with return=%d",
1164 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001165 return;
1166 }
1167
1168 /*
1169 Feed IGMPv3-gathered local membership information into PIM
1170 per-interface (S,G) state.
1171 */
1172 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1173 source->source_addr, group->group_addr);
1174
1175 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1176}
1177
Everton Marques24e3a9b2014-09-30 19:14:19 -03001178/*
1179 igmp_source_forward_stop: stop fowarding, but keep the source
1180 igmp_source_delete: stop fowarding, and delete the source
1181 */
Everton Marques871dbcf2009-08-11 15:43:05 -03001182void igmp_source_forward_stop(struct igmp_source *source)
1183{
1184 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001185 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001186
1187 if (PIM_DEBUG_IGMP_TRACE) {
1188 char source_str[100];
1189 char group_str[100];
1190 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1191 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1192 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1193 __PRETTY_FUNCTION__,
1194 source_str, group_str,
1195 source->source_group->group_igmp_sock->fd,
1196 source->source_group->group_igmp_sock->interface->name,
1197 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1198 }
1199
1200 /* Prevent IGMP interface from removing multicast route multiple
1201 times */
1202 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1203 return;
1204 }
1205
1206 group = source->source_group;
1207
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001208 /*
1209 It appears that in certain circumstances that
1210 igmp_source_forward_stop is called when IGMP forwarding
1211 was not enabled in oif_flags for this outgoing interface.
1212 Possibly because of multiple calls. When that happens, we
1213 enter the below if statement and this function returns early
1214 which in turn triggers the calling function to assert.
1215 Making the call to del_oif and ignoring the return code
1216 fixes the issue without ill effect, similar to
1217 pim_forward_stop below.
1218 */
Everton Marques24e3a9b2014-09-30 19:14:19 -03001219 result = del_oif(source->source_channel_oil,
1220 group->group_igmp_sock->interface,
1221 PIM_OIF_FLAG_PROTO_IGMP);
1222 if (result) {
1223 zlog_warn("%s: del_oif() failed with return=%d",
1224 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001225 return;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001226 }
Everton Marques871dbcf2009-08-11 15:43:05 -03001227
1228 /*
1229 Feed IGMPv3-gathered local membership information into PIM
1230 per-interface (S,G) state.
1231 */
1232 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1233 source->source_addr, group->group_addr);
1234
1235 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1236}
1237
1238void pim_forward_start(struct pim_ifchannel *ch)
1239{
1240 struct pim_upstream *up = ch->upstream;
1241
1242 if (PIM_DEBUG_PIM_TRACE) {
1243 char source_str[100];
1244 char group_str[100];
1245 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1246 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1247 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1248 __PRETTY_FUNCTION__,
1249 source_str, group_str, ch->interface->name);
1250 }
1251
1252 if (!up->channel_oil) {
1253 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1254 if (input_iface_vif_index < 1) {
1255 char source_str[100];
1256 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1257 zlog_warn("%s %s: could not find input interface for source %s",
1258 __FILE__, __PRETTY_FUNCTION__,
1259 source_str);
1260 return;
1261 }
1262
1263 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1264 input_iface_vif_index);
1265 if (!up->channel_oil) {
1266 char group_str[100];
1267 char source_str[100];
1268 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1269 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1270 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1271 __FILE__, __PRETTY_FUNCTION__,
1272 source_str, group_str);
1273 return;
1274 }
1275 }
1276
1277 add_oif(up->channel_oil,
1278 ch->interface,
1279 PIM_OIF_FLAG_PROTO_PIM);
1280}
1281
1282void pim_forward_stop(struct pim_ifchannel *ch)
1283{
1284 struct pim_upstream *up = ch->upstream;
1285
1286 if (PIM_DEBUG_PIM_TRACE) {
1287 char source_str[100];
1288 char group_str[100];
1289 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1290 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1291 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1292 __PRETTY_FUNCTION__,
1293 source_str, group_str, ch->interface->name);
1294 }
1295
1296 if (!up->channel_oil) {
1297 char source_str[100];
1298 char group_str[100];
1299 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1300 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1301 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1302 __PRETTY_FUNCTION__,
1303 source_str, group_str, ch->interface->name);
1304
1305 return;
1306 }
1307
1308 del_oif(up->channel_oil,
1309 ch->interface,
1310 PIM_OIF_FLAG_PROTO_PIM);
1311}