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