blob: dfc871b3b2703ab80bfe0dae6b582d65fc17b78a [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
David Lampartere0704522015-03-03 10:41:21 +010054#if 0
Everton Marques2a0ecf22014-09-22 18:18:26 -030055static void zclient_broken(struct zclient *zclient)
56{
Everton Marques075ac8d2014-09-24 15:18:37 -030057 struct listnode *ifnode;
58 struct interface *ifp;
59
Everton Marques2a0ecf22014-09-22 18:18:26 -030060 zlog_warn("%s %s: broken zclient connection",
Everton Marques075ac8d2014-09-24 15:18:37 -030061 __FILE__, __PRETTY_FUNCTION__);
62
63 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
Everton Marques2a0ecf22014-09-22 18:18:26 -030064 pim_if_addr_del_all(ifp);
Everton Marques075ac8d2014-09-24 15:18:37 -030065 }
Everton Marques2a0ecf22014-09-22 18:18:26 -030066
David Lamparter5d5af782015-02-04 06:33:59 +010067 /* upon return, zclient will discard connected addresses */
Everton Marques075ac8d2014-09-24 15:18:37 -030068}
David Lampartere0704522015-03-03 10:41:21 +010069#endif
Everton Marques075ac8d2014-09-24 15:18:37 -030070
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,
Feng Luc99f3482014-10-16 09:52:36 +080073 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -030074{
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,
Feng Luc99f3482014-10-16 09:52:36 +080083 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -030084{
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 */
Feng Luc99f3482014-10-16 09:52:36 +080091 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -030092 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,
Feng Luc99f3482014-10-16 09:52:36 +0800109 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300110{
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 */
Feng Luc99f3482014-10-16 09:52:36 +0800123 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
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,
Feng Luc99f3482014-10-16 09:52:36 +0800141 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300142{
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 */
Feng Luc99f3482014-10-16 09:52:36 +0800149 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300150 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,
Feng Luc99f3482014-10-16 09:52:36 +0800173 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300174{
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 */
Feng Luc99f3482014-10-16 09:52:36 +0800181 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300182 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,
Feng Luc99f3482014-10-16 09:52:36 +0800240 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300241{
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 */
Feng Luc99f3482014-10-16 09:52:36 +0800255 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300256 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,
Feng Luc99f3482014-10-16 09:52:36 +0800302 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300303{
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 */
Feng Luc99f3482014-10-16 09:52:36 +0800317 c = zebra_interface_address_read(command, client->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300318 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,
Feng Luc99f3482014-10-16 09:52:36 +0800529 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300530{
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
Feng Luc99f3482014-10-16 09:52:36 +0800653static void pim_zebra_connected(struct zclient *zclient)
654{
655 zclient_send_requests(zclient, VRF_DEFAULT);
656}
657
Everton Marques1f298942014-08-21 15:47:28 -0300658void pim_zebra_init(char *zebra_sock_path)
Everton Marques871dbcf2009-08-11 15:43:05 -0300659{
Everton Marques871dbcf2009-08-11 15:43:05 -0300660 int i;
661
Everton Marques1f298942014-08-21 15:47:28 -0300662 if (zebra_sock_path)
663 zclient_serv_path_set(zebra_sock_path);
664
Everton Marques871dbcf2009-08-11 15:43:05 -0300665#ifdef HAVE_TCP_ZEBRA
666 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
667#else
Everton Marques1f298942014-08-21 15:47:28 -0300668 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
Everton Marques871dbcf2009-08-11 15:43:05 -0300669#endif
670
671 /* Socket for receiving updates from Zebra daemon */
Everton Marques3456a802014-07-22 14:52:57 -0300672 qpim_zclient_update = zclient_new();
Everton Marques871dbcf2009-08-11 15:43:05 -0300673
Feng Luc99f3482014-10-16 09:52:36 +0800674 qpim_zclient_update->zebra_connected = pim_zebra_connected;
Everton Marques3456a802014-07-22 14:52:57 -0300675 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
676 qpim_zclient_update->interface_add = pim_zebra_if_add;
677 qpim_zclient_update->interface_delete = pim_zebra_if_del;
678 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
679 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
680 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
681 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
682 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
683 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
Everton Marques871dbcf2009-08-11 15:43:05 -0300684
David Lampartera2805de2015-02-04 06:33:26 +0100685 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300686 if (PIM_DEBUG_PIM_TRACE) {
687 zlog_info("zclient_init cleared redistribution request");
688 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300689
Everton Marques3456a802014-07-22 14:52:57 -0300690 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300691
692 /* Request all redistribution */
693 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300694 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300695 continue;
Feng Luc99f3482014-10-16 09:52:36 +0800696 vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300697 if (PIM_DEBUG_PIM_TRACE) {
698 zlog_debug("%s: requesting redistribution for %s (%i)",
699 __PRETTY_FUNCTION__, zebra_route_string(i), i);
700 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300701 }
702
703 /* Request default information */
Feng Luc99f3482014-10-16 09:52:36 +0800704 vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300705 if (PIM_DEBUG_PIM_TRACE) {
706 zlog_info("%s: requesting default information redistribution",
Everton Marques871dbcf2009-08-11 15:43:05 -0300707 __PRETTY_FUNCTION__);
708
Everton Marquesc1b228c2014-08-27 15:27:26 -0300709 zlog_notice("%s: zclient update socket initialized",
710 __PRETTY_FUNCTION__);
711 }
712
Everton Marques871dbcf2009-08-11 15:43:05 -0300713 zassert(!qpim_zclient_lookup);
714 qpim_zclient_lookup = zclient_lookup_new();
715 zassert(qpim_zclient_lookup);
716}
717
718void igmp_anysource_forward_start(struct igmp_group *group)
719{
720 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
721 zassert(group->group_filtermode_isexcl);
722 zassert(listcount(group->group_source_list) < 1);
723
724 if (PIM_DEBUG_IGMP_TRACE) {
725 zlog_debug("%s %s: UNIMPLEMENTED",
726 __FILE__, __PRETTY_FUNCTION__);
727 }
728}
729
730void igmp_anysource_forward_stop(struct igmp_group *group)
731{
732 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
733 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
734
735 if (PIM_DEBUG_IGMP_TRACE) {
736 zlog_debug("%s %s: UNIMPLEMENTED",
737 __FILE__, __PRETTY_FUNCTION__);
738 }
739}
740
741static int fib_lookup_if_vif_index(struct in_addr addr)
742{
743 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
744 int num_ifindex;
745 int vif_index;
746 int first_ifindex;
747
748 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
749 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
750 PIM_NEXTHOP_LOOKUP_MAX);
751 if (num_ifindex < 1) {
752 char addr_str[100];
753 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
754 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
755 __FILE__, __PRETTY_FUNCTION__,
756 addr_str);
757 return -1;
758 }
759
760 first_ifindex = nexthop_tab[0].ifindex;
761
762 if (num_ifindex > 1) {
763 char addr_str[100];
764 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
765 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
766 __FILE__, __PRETTY_FUNCTION__,
767 num_ifindex, addr_str, first_ifindex);
768 /* debug warning only, do not return */
769 }
770
771 if (PIM_DEBUG_ZEBRA) {
772 char addr_str[100];
773 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
774 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
775 __FILE__, __PRETTY_FUNCTION__,
776 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
777 }
778
779 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
780
781 if (vif_index < 1) {
782 char addr_str[100];
783 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
784 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
785 __FILE__, __PRETTY_FUNCTION__,
786 vif_index, addr_str);
787 return -2;
788 }
789
790 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
791
792 if (vif_index > qpim_mroute_oif_highest_vif_index) {
793 char addr_str[100];
794 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
795 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
796 __FILE__, __PRETTY_FUNCTION__,
797 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
798
799 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
800 __FILE__, __PRETTY_FUNCTION__,
801 ifindex2ifname(vif_index),
802 vif_index);
803
804 return -3;
805 }
806
807 return vif_index;
808}
809
810static int add_oif(struct channel_oil *channel_oil,
811 struct interface *oif,
812 uint32_t proto_mask)
813{
814 struct pim_interface *pim_ifp;
815 int old_ttl;
816
817 zassert(channel_oil);
818
819 pim_ifp = oif->info;
820
Everton Marques67faabc2010-02-23 12:11:11 -0300821 if (PIM_DEBUG_MROUTE) {
822 char group_str[100];
823 char source_str[100];
824 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
825 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
826 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
827 __FILE__, __PRETTY_FUNCTION__,
828 source_str, group_str,
829 proto_mask, oif->name, pim_ifp->mroute_vif_index);
830 }
831
Everton Marques871dbcf2009-08-11 15:43:05 -0300832 if (pim_ifp->mroute_vif_index < 1) {
833 zlog_warn("%s %s: interface %s vif_index=%d < 1",
834 __FILE__, __PRETTY_FUNCTION__,
835 oif->name, pim_ifp->mroute_vif_index);
836 return -1;
837 }
838
839#ifdef PIM_ENFORCE_LOOPFREE_MFC
840 /*
841 Prevent creating MFC entry with OIF=IIF.
842
843 This is a protection against implementation mistakes.
844
845 PIM protocol implicitely ensures loopfree multicast topology.
846
847 IGMP must be protected against adding looped MFC entries created
848 by both source and receiver attached to the same interface. See
849 TODO T22.
850 */
851 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
852 char group_str[100];
853 char source_str[100];
854 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
855 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
856 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
857 __FILE__, __PRETTY_FUNCTION__,
858 proto_mask, oif->name, pim_ifp->mroute_vif_index,
859 source_str, group_str);
860 return -2;
861 }
862#endif
863
864 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
865 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
866
867 /* Prevent single protocol from subscribing same interface to
868 channel (S,G) multiple times */
869 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
870 char group_str[100];
871 char source_str[100];
872 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
873 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
874 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
875 __FILE__, __PRETTY_FUNCTION__,
876 proto_mask, oif->name, pim_ifp->mroute_vif_index,
877 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
878 source_str, group_str);
879 return -3;
880 }
881
882 /* Allow other protocol to request subscription of same interface to
883 channel (S,G) multiple times, by silently ignoring further
884 requests */
885 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
886
887 /* Check the OIF really exists before returning, and only log
888 warning otherwise */
889 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
890 char group_str[100];
891 char source_str[100];
892 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
893 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
894 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
895 __FILE__, __PRETTY_FUNCTION__,
896 proto_mask, oif->name, pim_ifp->mroute_vif_index,
897 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
898 source_str, group_str);
899 }
900
901 return 0;
902 }
903
904 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
905
906 if (old_ttl > 0) {
907 char group_str[100];
908 char source_str[100];
909 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
910 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
911 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
912 __FILE__, __PRETTY_FUNCTION__,
913 oif->name, pim_ifp->mroute_vif_index,
914 source_str, group_str);
915 return -4;
916 }
917
918 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
919
920 if (pim_mroute_add(&channel_oil->oil)) {
921 char group_str[100];
922 char source_str[100];
923 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
924 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
925 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
926 __FILE__, __PRETTY_FUNCTION__,
927 oif->name, pim_ifp->mroute_vif_index,
928 source_str, group_str);
929
930 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
931 return -5;
932 }
933
934 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
935 ++channel_oil->oil_size;
936 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
937
Everton Marques67faabc2010-02-23 12:11:11 -0300938 if (PIM_DEBUG_MROUTE) {
939 char group_str[100];
940 char source_str[100];
941 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
942 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
943 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
944 __FILE__, __PRETTY_FUNCTION__,
945 source_str, group_str,
946 proto_mask, oif->name, pim_ifp->mroute_vif_index);
947 }
948
Everton Marques871dbcf2009-08-11 15:43:05 -0300949 return 0;
950}
951
952static int del_oif(struct channel_oil *channel_oil,
953 struct interface *oif,
954 uint32_t proto_mask)
955{
956 struct pim_interface *pim_ifp;
957 int old_ttl;
958
959 zassert(channel_oil);
960
961 pim_ifp = oif->info;
962
963 zassert(pim_ifp->mroute_vif_index >= 1);
964 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
965 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
966
Everton Marques67faabc2010-02-23 12:11:11 -0300967 if (PIM_DEBUG_MROUTE) {
968 char group_str[100];
969 char source_str[100];
970 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
971 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
972 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
973 __FILE__, __PRETTY_FUNCTION__,
974 source_str, group_str,
975 proto_mask, oif->name, pim_ifp->mroute_vif_index);
976 }
977
Everton Marques871dbcf2009-08-11 15:43:05 -0300978 /* Prevent single protocol from unsubscribing same interface from
979 channel (S,G) multiple times */
980 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
981 char group_str[100];
982 char source_str[100];
983 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
984 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
985 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
986 __FILE__, __PRETTY_FUNCTION__,
987 proto_mask, oif->name, pim_ifp->mroute_vif_index,
988 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
989 source_str, group_str);
990 return -2;
991 }
992
993 /* Mark that protocol is no longer interested in this OIF */
994 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
995
996 /* Allow multiple protocols to unsubscribe same interface from
997 channel (S,G) multiple times, by silently ignoring requests while
998 there is at least one protocol interested in the channel */
999 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
1000
1001 /* Check the OIF keeps existing before returning, and only log
1002 warning otherwise */
1003 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
1004 char group_str[100];
1005 char source_str[100];
1006 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1007 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1008 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
1009 __FILE__, __PRETTY_FUNCTION__,
1010 proto_mask, oif->name, pim_ifp->mroute_vif_index,
1011 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
1012 source_str, group_str);
1013 }
1014
1015 return 0;
1016 }
1017
1018 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1019
1020 if (old_ttl < 1) {
1021 char group_str[100];
1022 char source_str[100];
1023 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1024 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1025 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1026 __FILE__, __PRETTY_FUNCTION__,
1027 oif->name, pim_ifp->mroute_vif_index,
1028 source_str, group_str);
1029 return -3;
1030 }
1031
1032 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1033
1034 if (pim_mroute_add(&channel_oil->oil)) {
1035 char group_str[100];
1036 char source_str[100];
1037 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1038 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1039 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1040 __FILE__, __PRETTY_FUNCTION__,
1041 oif->name, pim_ifp->mroute_vif_index,
1042 source_str, group_str);
1043
1044 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1045 return -4;
1046 }
1047
1048 --channel_oil->oil_size;
1049
1050 if (channel_oil->oil_size < 1) {
1051 if (pim_mroute_del(&channel_oil->oil)) {
1052 /* just log a warning in case of failure */
1053 char group_str[100];
1054 char source_str[100];
1055 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1056 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1057 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1058 __FILE__, __PRETTY_FUNCTION__,
1059 source_str, group_str);
1060 }
1061 }
1062
Everton Marques67faabc2010-02-23 12:11:11 -03001063 if (PIM_DEBUG_MROUTE) {
1064 char group_str[100];
1065 char source_str[100];
1066 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1067 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1068 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1069 __FILE__, __PRETTY_FUNCTION__,
1070 source_str, group_str,
1071 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1072 }
1073
Everton Marques871dbcf2009-08-11 15:43:05 -03001074 return 0;
1075}
1076
1077void igmp_source_forward_start(struct igmp_source *source)
1078{
1079 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001080 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001081
1082 if (PIM_DEBUG_IGMP_TRACE) {
1083 char source_str[100];
1084 char group_str[100];
1085 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1086 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1087 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1088 __PRETTY_FUNCTION__,
1089 source_str, group_str,
1090 source->source_group->group_igmp_sock->fd,
1091 source->source_group->group_igmp_sock->interface->name,
1092 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1093 }
1094
1095 /* Prevent IGMP interface from installing multicast route multiple
1096 times */
1097 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1098 return;
1099 }
1100
1101 group = source->source_group;
1102
1103 if (!source->source_channel_oil) {
1104 struct pim_interface *pim_oif;
1105 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1106 if (input_iface_vif_index < 1) {
1107 char source_str[100];
1108 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1109 zlog_warn("%s %s: could not find input interface for source %s",
1110 __FILE__, __PRETTY_FUNCTION__,
1111 source_str);
1112 return;
1113 }
1114
1115 /*
1116 Protect IGMP against adding looped MFC entries created by both
1117 source and receiver attached to the same interface. See TODO
1118 T22.
1119 */
1120 pim_oif = source->source_group->group_igmp_sock->interface->info;
1121 if (!pim_oif) {
1122 zlog_warn("%s: multicast not enabled on oif=%s ?",
1123 __PRETTY_FUNCTION__,
1124 source->source_group->group_igmp_sock->interface->name);
1125 return;
1126 }
1127 if (pim_oif->mroute_vif_index < 1) {
1128 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1129 __FILE__, __PRETTY_FUNCTION__,
1130 source->source_group->group_igmp_sock->interface->name,
1131 pim_oif->mroute_vif_index);
1132 return;
1133 }
1134 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1135 /* ignore request for looped MFC entry */
1136 if (PIM_DEBUG_IGMP_TRACE) {
1137 char source_str[100];
1138 char group_str[100];
1139 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1140 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1141 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1142 __PRETTY_FUNCTION__,
1143 source_str, group_str,
1144 source->source_group->group_igmp_sock->fd,
1145 source->source_group->group_igmp_sock->interface->name,
1146 input_iface_vif_index);
1147 }
1148 return;
1149 }
1150
1151 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1152 source->source_addr,
1153 input_iface_vif_index);
1154 if (!source->source_channel_oil) {
1155 char group_str[100];
1156 char source_str[100];
1157 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1158 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1159 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1160 __FILE__, __PRETTY_FUNCTION__,
1161 source_str, group_str);
1162 return;
1163 }
1164 }
1165
Everton Marques24e3a9b2014-09-30 19:14:19 -03001166 result = add_oif(source->source_channel_oil,
1167 group->group_igmp_sock->interface,
1168 PIM_OIF_FLAG_PROTO_IGMP);
1169 if (result) {
1170 zlog_warn("%s: add_oif() failed with return=%d",
1171 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001172 return;
1173 }
1174
1175 /*
1176 Feed IGMPv3-gathered local membership information into PIM
1177 per-interface (S,G) state.
1178 */
1179 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1180 source->source_addr, group->group_addr);
1181
1182 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1183}
1184
Everton Marques24e3a9b2014-09-30 19:14:19 -03001185/*
1186 igmp_source_forward_stop: stop fowarding, but keep the source
1187 igmp_source_delete: stop fowarding, and delete the source
1188 */
Everton Marques871dbcf2009-08-11 15:43:05 -03001189void igmp_source_forward_stop(struct igmp_source *source)
1190{
1191 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001192 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001193
1194 if (PIM_DEBUG_IGMP_TRACE) {
1195 char source_str[100];
1196 char group_str[100];
1197 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1198 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1199 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1200 __PRETTY_FUNCTION__,
1201 source_str, group_str,
1202 source->source_group->group_igmp_sock->fd,
1203 source->source_group->group_igmp_sock->interface->name,
1204 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1205 }
1206
1207 /* Prevent IGMP interface from removing multicast route multiple
1208 times */
1209 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1210 return;
1211 }
1212
1213 group = source->source_group;
1214
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001215 /*
1216 It appears that in certain circumstances that
1217 igmp_source_forward_stop is called when IGMP forwarding
1218 was not enabled in oif_flags for this outgoing interface.
1219 Possibly because of multiple calls. When that happens, we
1220 enter the below if statement and this function returns early
1221 which in turn triggers the calling function to assert.
1222 Making the call to del_oif and ignoring the return code
1223 fixes the issue without ill effect, similar to
1224 pim_forward_stop below.
1225 */
Everton Marques24e3a9b2014-09-30 19:14:19 -03001226 result = del_oif(source->source_channel_oil,
1227 group->group_igmp_sock->interface,
1228 PIM_OIF_FLAG_PROTO_IGMP);
1229 if (result) {
1230 zlog_warn("%s: del_oif() failed with return=%d",
1231 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001232 return;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001233 }
Everton Marques871dbcf2009-08-11 15:43:05 -03001234
1235 /*
1236 Feed IGMPv3-gathered local membership information into PIM
1237 per-interface (S,G) state.
1238 */
1239 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1240 source->source_addr, group->group_addr);
1241
1242 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1243}
1244
1245void pim_forward_start(struct pim_ifchannel *ch)
1246{
1247 struct pim_upstream *up = ch->upstream;
1248
1249 if (PIM_DEBUG_PIM_TRACE) {
1250 char source_str[100];
1251 char group_str[100];
1252 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1253 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1254 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1255 __PRETTY_FUNCTION__,
1256 source_str, group_str, ch->interface->name);
1257 }
1258
1259 if (!up->channel_oil) {
1260 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1261 if (input_iface_vif_index < 1) {
1262 char source_str[100];
1263 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1264 zlog_warn("%s %s: could not find input interface for source %s",
1265 __FILE__, __PRETTY_FUNCTION__,
1266 source_str);
1267 return;
1268 }
1269
1270 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1271 input_iface_vif_index);
1272 if (!up->channel_oil) {
1273 char group_str[100];
1274 char source_str[100];
1275 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1276 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1277 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1278 __FILE__, __PRETTY_FUNCTION__,
1279 source_str, group_str);
1280 return;
1281 }
1282 }
1283
1284 add_oif(up->channel_oil,
1285 ch->interface,
1286 PIM_OIF_FLAG_PROTO_PIM);
1287}
1288
1289void pim_forward_stop(struct pim_ifchannel *ch)
1290{
1291 struct pim_upstream *up = ch->upstream;
1292
1293 if (PIM_DEBUG_PIM_TRACE) {
1294 char source_str[100];
1295 char group_str[100];
1296 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1297 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1298 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1299 __PRETTY_FUNCTION__,
1300 source_str, group_str, ch->interface->name);
1301 }
1302
1303 if (!up->channel_oil) {
1304 char source_str[100];
1305 char group_str[100];
1306 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1307 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1308 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1309 __PRETTY_FUNCTION__,
1310 source_str, group_str, ch->interface->name);
1311
1312 return;
1313 }
1314
1315 del_oif(up->channel_oil,
1316 ch->interface,
1317 PIM_OIF_FLAG_PROTO_PIM);
1318}