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