blob: 8f85b17bb5b50f6a45cd6a9c977c8dcbe24e0ac0 [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
153 if (PIM_DEBUG_ZEBRA) {
154 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
155 __PRETTY_FUNCTION__,
156 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
157 ifp->mtu, if_is_operative(ifp));
158 }
159
160 if (if_is_operative(ifp)) {
161 /*
162 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
163 */
164 pim_if_addr_add_all(ifp);
165 }
166
167 return 0;
168}
169
170static int pim_zebra_if_state_down(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +0800171 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300172{
173 struct interface *ifp;
174
175 /*
176 zebra api notifies interface up/down events by using the same call
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -0300177 zebra_interface_state_read below, see comments in lib/zclient.c
Everton Marques871dbcf2009-08-11 15:43:05 -0300178 */
Feng Luc99f3482014-10-16 09:52:36 +0800179 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300180 if (!ifp)
181 return 0;
182
183 if (PIM_DEBUG_ZEBRA) {
184 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
185 __PRETTY_FUNCTION__,
186 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
187 ifp->mtu, if_is_operative(ifp));
188 }
189
190 if (!if_is_operative(ifp)) {
191 /*
192 pim_if_addr_del_all() suffices for shutting down IGMP,
193 but not for shutting down PIM
194 */
195 pim_if_addr_del_all(ifp);
196
197 /*
198 pim_sock_delete() closes the socket, stops read and timer threads,
199 and kills all neighbors.
200 */
Everton Marquese96f0af2009-08-11 15:48:02 -0300201 if (ifp->info) {
202 pim_sock_delete(ifp, "link down");
203 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300204 }
205
206 return 0;
207}
208
209#ifdef PIM_DEBUG_IFADDR_DUMP
210static void dump_if_address(struct interface *ifp)
211{
212 struct connected *ifc;
213 struct listnode *node;
214
215 zlog_debug("%s %s: interface %s addresses:",
216 __FILE__, __PRETTY_FUNCTION__,
217 ifp->name);
218
219 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
220 struct prefix *p = ifc->address;
221
222 if (p->family != AF_INET)
223 continue;
224
Everton Marques306c99e2014-07-16 15:51:37 -0300225 zlog_debug("%s %s: interface %s address %s %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300226 __FILE__, __PRETTY_FUNCTION__,
227 ifp->name,
Everton Marques306c99e2014-07-16 15:51:37 -0300228 inet_ntoa(p->u.prefix4),
229 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
230 "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300231 }
232}
233#endif
234
235static int pim_zebra_if_address_add(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +0800236 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300237{
238 struct connected *c;
239 struct prefix *p;
240
Everton Marques871dbcf2009-08-11 15:43:05 -0300241 /*
242 zebra api notifies address adds/dels events by using the same call
243 interface_add_read below, see comments in lib/zclient.c
244
245 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
246 will add address to interface list by calling
247 connected_add_by_prefix()
248 */
Feng Luc99f3482014-10-16 09:52:36 +0800249 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300250 if (!c)
251 return 0;
252
253 p = c->address;
254 if (p->family != AF_INET)
255 return 0;
256
257 if (PIM_DEBUG_ZEBRA) {
258 char buf[BUFSIZ];
259 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300260 zlog_debug("%s: %s connected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300261 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300262 c->ifp->name, buf, c->flags,
263 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300264
265#ifdef PIM_DEBUG_IFADDR_DUMP
266 dump_if_address(c->ifp);
267#endif
268 }
269
Everton Marques306c99e2014-07-16 15:51:37 -0300270 if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
271 /* trying to add primary address */
272
273 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
274 if (primary_addr.s_addr != p->u.prefix4.s_addr) {
Donald Sharpa6a11762015-10-02 12:27:27 -0400275 if (PIM_DEBUG_ZEBRA) {
276 /* but we had a primary address already */
Everton Marques306c99e2014-07-16 15:51:37 -0300277
Donald Sharpa6a11762015-10-02 12:27:27 -0400278 char buf[BUFSIZ];
279 char old[100];
Everton Marques306c99e2014-07-16 15:51:37 -0300280
Donald Sharpa6a11762015-10-02 12:27:27 -0400281 prefix2str(p, buf, BUFSIZ);
282 pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
Everton Marques306c99e2014-07-16 15:51:37 -0300283
Donald Sharpa6a11762015-10-02 12:27:27 -0400284 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
285 __PRETTY_FUNCTION__,
286 c->ifp->name, old, buf);
287 }
Everton Marques306c99e2014-07-16 15:51:37 -0300288 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
289 }
290 }
291
Everton Marques871dbcf2009-08-11 15:43:05 -0300292 pim_if_addr_add(c);
293
294 return 0;
295}
296
297static int pim_zebra_if_address_del(int command, struct zclient *client,
Feng Luc99f3482014-10-16 09:52:36 +0800298 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300299{
300 struct connected *c;
301 struct prefix *p;
302
Everton Marques871dbcf2009-08-11 15:43:05 -0300303 /*
304 zebra api notifies address adds/dels events by using the same call
305 interface_add_read below, see comments in lib/zclient.c
306
307 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
308 will remove address from interface list by calling
309 connected_delete_by_prefix()
310 */
Feng Luc99f3482014-10-16 09:52:36 +0800311 c = zebra_interface_address_read(command, client->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300312 if (!c)
313 return 0;
314
315 p = c->address;
316 if (p->family != AF_INET)
317 return 0;
318
319 if (PIM_DEBUG_ZEBRA) {
320 char buf[BUFSIZ];
321 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300322 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300323 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300324 c->ifp->name, buf, c->flags,
325 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300326
327#ifdef PIM_DEBUG_IFADDR_DUMP
328 dump_if_address(c->ifp);
329#endif
330 }
Everton Marques306c99e2014-07-16 15:51:37 -0300331
Everton Marques2a0ecf22014-09-22 18:18:26 -0300332 pim_if_addr_del(c, 0);
Everton Marques871dbcf2009-08-11 15:43:05 -0300333
334 return 0;
335}
336
337static void scan_upstream_rpf_cache()
338{
339 struct listnode *up_node;
340 struct listnode *up_nextnode;
341 struct pim_upstream *up;
342
343 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
344 struct in_addr old_rpf_addr;
345 enum pim_rpf_result rpf_result;
346
347 rpf_result = pim_rpf_update(up, &old_rpf_addr);
348 if (rpf_result == PIM_RPF_FAILURE)
349 continue;
350
351 if (rpf_result == PIM_RPF_CHANGED) {
352
353 if (up->join_state == PIM_UPSTREAM_JOINED) {
354
355 /*
356 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
357
358 Transitions from Joined State
359
360 RPF'(S,G) changes not due to an Assert
361
362 The upstream (S,G) state machine remains in Joined
363 state. Send Join(S,G) to the new upstream neighbor, which is
364 the new value of RPF'(S,G). Send Prune(S,G) to the old
365 upstream neighbor, which is the old value of RPF'(S,G). Set
366 the Join Timer (JT) to expire after t_periodic seconds.
367 */
368
369
370 /* send Prune(S,G) to the old upstream neighbor */
371 pim_joinprune_send(up->rpf.source_nexthop.interface,
372 old_rpf_addr,
373 up->source_addr,
374 up->group_addr,
375 0 /* prune */);
376
377 /* send Join(S,G) to the current upstream neighbor */
378 pim_joinprune_send(up->rpf.source_nexthop.interface,
379 up->rpf.rpf_addr,
380 up->source_addr,
381 up->group_addr,
382 1 /* join */);
383
384 pim_upstream_join_timer_restart(up);
385 } /* up->join_state == PIM_UPSTREAM_JOINED */
386
387 /* FIXME can join_desired actually be changed by pim_rpf_update()
388 returning PIM_RPF_CHANGED ? */
389 pim_upstream_update_join_desired(up);
390
391 } /* PIM_RPF_CHANGED */
392
393 } /* for (qpim_upstream_list) */
394
395}
396
Everton Marquesf24200d2014-02-14 16:40:34 -0200397void pim_scan_oil()
Everton Marques871dbcf2009-08-11 15:43:05 -0300398{
399 struct listnode *node;
400 struct listnode *nextnode;
401 struct channel_oil *c_oil;
402
Everton Marquesf24200d2014-02-14 16:40:34 -0200403 qpim_scan_oil_last = pim_time_monotonic_sec();
404 ++qpim_scan_oil_events;
405
Everton Marques871dbcf2009-08-11 15:43:05 -0300406 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
407 int old_vif_index;
408 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
409 if (input_iface_vif_index < 1) {
410 char source_str[100];
411 char group_str[100];
412 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
413 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
414 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
415 __FILE__, __PRETTY_FUNCTION__,
416 source_str, group_str);
417 continue;
418 }
419
420 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
421 /* RPF unchanged */
422 continue;
423 }
424
425 if (PIM_DEBUG_ZEBRA) {
426 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
427 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
428 char source_str[100];
429 char group_str[100];
430 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
431 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
432 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
433 __FILE__, __PRETTY_FUNCTION__,
434 source_str, group_str,
435 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
436 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
437 }
438
439 /* new iif loops to existing oif ? */
440 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
441 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
442
443 if (PIM_DEBUG_ZEBRA) {
444 char source_str[100];
445 char group_str[100];
446 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
447 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
448 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
449 __FILE__, __PRETTY_FUNCTION__,
450 source_str, group_str,
451 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
452 }
453
454 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
455 }
456
457 /* update iif vif_index */
458 old_vif_index = c_oil->oil.mfcc_parent;
459 c_oil->oil.mfcc_parent = input_iface_vif_index;
460
461 /* update kernel multicast forwarding cache (MFC) */
462 if (pim_mroute_add(&c_oil->oil)) {
463 /* just log warning */
464 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
465 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
466 char source_str[100];
467 char group_str[100];
468 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
469 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
470 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
471 __FILE__, __PRETTY_FUNCTION__,
472 source_str, group_str,
473 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
474 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
475 continue;
476 }
477
478 } /* for (qpim_channel_oil_list) */
479}
480
481static int on_rpf_cache_refresh(struct thread *t)
482{
483 zassert(t);
484 zassert(qpim_rpf_cache_refresher);
485
486 qpim_rpf_cache_refresher = 0;
487
488 /* update PIM protocol state */
489 scan_upstream_rpf_cache();
490
491 /* update kernel multicast forwarding cache (MFC) */
Everton Marquesf24200d2014-02-14 16:40:34 -0200492 pim_scan_oil();
Everton Marques871dbcf2009-08-11 15:43:05 -0300493
Everton Marquesbcc4abe2009-08-17 18:18:59 -0300494 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
Everton Marques613938d2009-08-13 15:39:31 -0300495 ++qpim_rpf_cache_refresh_events;
496
Everton Marques871dbcf2009-08-11 15:43:05 -0300497 return 0;
498}
499
500static void sched_rpf_cache_refresh()
501{
Everton Marques613938d2009-08-13 15:39:31 -0300502 ++qpim_rpf_cache_refresh_requests;
503
504 if (qpim_rpf_cache_refresher) {
505 /* Refresh timer is already running */
Everton Marques871dbcf2009-08-11 15:43:05 -0300506 return;
Everton Marques613938d2009-08-13 15:39:31 -0300507 }
508
509 /* Start refresh timer */
Everton Marques871dbcf2009-08-11 15:43:05 -0300510
511 if (PIM_DEBUG_ZEBRA) {
512 zlog_debug("%s: triggering %ld msec timer",
513 __PRETTY_FUNCTION__,
514 qpim_rpf_cache_refresh_delay_msec);
515 }
516
517 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
518 on_rpf_cache_refresh,
519 0, qpim_rpf_cache_refresh_delay_msec);
520}
521
522static int redist_read_ipv4_route(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +0800523 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300524{
525 struct stream *s;
526 struct zapi_ipv4 api;
Paul Jakma9099f9b2016-01-18 10:12:10 +0000527 ifindex_t ifindex;
Everton Marques871dbcf2009-08-11 15:43:05 -0300528 struct in_addr nexthop;
529 struct prefix_ipv4 p;
530 int min_len = 4;
531
532 if (length < min_len) {
533 zlog_warn("%s %s: short buffer: length=%d min=%d",
534 __FILE__, __PRETTY_FUNCTION__,
535 length, min_len);
536 return -1;
537 }
538
539 s = zclient->ibuf;
540 ifindex = 0;
541 nexthop.s_addr = 0;
542
543 /* Type, flags, message. */
544 api.type = stream_getc(s);
545 api.flags = stream_getc(s);
546 api.message = stream_getc(s);
547
548 /* IPv4 prefix length. */
549 memset(&p, 0, sizeof(struct prefix_ipv4));
550 p.family = AF_INET;
551 p.prefixlen = stream_getc(s);
552
553 min_len +=
554 PSIZE(p.prefixlen) +
555 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
556 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
557 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
558 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
559
560 if (PIM_DEBUG_ZEBRA) {
561 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
562 __FILE__, __PRETTY_FUNCTION__,
563 length, min_len,
564 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
565 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
566 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
567 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
568 }
569
570 if (length < min_len) {
571 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
572 __FILE__, __PRETTY_FUNCTION__,
573 length, min_len,
574 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
575 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
576 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
577 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
578 return -1;
579 }
580
581 /* IPv4 prefix. */
582 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
583
584 /* Nexthop, ifindex, distance, metric. */
585 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
586 api.nexthop_num = stream_getc(s);
587 nexthop.s_addr = stream_get_ipv4(s);
588 }
589 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
590 api.ifindex_num = stream_getc(s);
591 ifindex = stream_getl(s);
592 }
593
594 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
David Lamparter105ad862012-02-16 04:50:35 +0000595 stream_getc(s) :
Everton Marques871dbcf2009-08-11 15:43:05 -0300596 0;
597
598 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
599 stream_getl(s) :
600 0;
601
602 switch (command) {
603 case ZEBRA_IPV4_ROUTE_ADD:
604 if (PIM_DEBUG_ZEBRA) {
605 char buf[2][INET_ADDRSTRLEN];
606 zlog_debug("%s: add %s %s/%d "
Paul Jakma9099f9b2016-01-18 10:12:10 +0000607 "nexthop %s ifindex %d metric%s %u distance%s %u",
Everton Marques871dbcf2009-08-11 15:43:05 -0300608 __PRETTY_FUNCTION__,
609 zebra_route_string(api.type),
610 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
611 p.prefixlen,
612 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
613 ifindex,
614 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
615 api.metric,
616 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
617 api.distance);
618 }
619 break;
620 case ZEBRA_IPV4_ROUTE_DELETE:
621 if (PIM_DEBUG_ZEBRA) {
622 char buf[2][INET_ADDRSTRLEN];
623 zlog_debug("%s: delete %s %s/%d "
Paul Jakma9099f9b2016-01-18 10:12:10 +0000624 "nexthop %s ifindex %d metric%s %u distance%s %u",
Everton Marques871dbcf2009-08-11 15:43:05 -0300625 __PRETTY_FUNCTION__,
626 zebra_route_string(api.type),
627 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
628 p.prefixlen,
629 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
630 ifindex,
631 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
632 api.metric,
633 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
634 api.distance);
635 }
636 break;
637 default:
638 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
639 return -1;
640 }
641
642 sched_rpf_cache_refresh();
643
644 return 0;
645}
646
Feng Luc99f3482014-10-16 09:52:36 +0800647static void pim_zebra_connected(struct zclient *zclient)
648{
649 zclient_send_requests(zclient, VRF_DEFAULT);
650}
651
Donald Sharp71252932015-09-24 09:25:19 -0400652void pim_zebra_init (struct thread_master *master, char *zebra_sock_path)
Everton Marques871dbcf2009-08-11 15:43:05 -0300653{
Everton Marques871dbcf2009-08-11 15:43:05 -0300654 int i;
655
Everton Marques1f298942014-08-21 15:47:28 -0300656 if (zebra_sock_path)
657 zclient_serv_path_set(zebra_sock_path);
658
Everton Marques871dbcf2009-08-11 15:43:05 -0300659#ifdef HAVE_TCP_ZEBRA
660 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
661#else
Everton Marques1f298942014-08-21 15:47:28 -0300662 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
Everton Marques871dbcf2009-08-11 15:43:05 -0300663#endif
664
665 /* Socket for receiving updates from Zebra daemon */
Donald Sharp71252932015-09-24 09:25:19 -0400666 qpim_zclient_update = zclient_new (master);
Everton Marques871dbcf2009-08-11 15:43:05 -0300667
Feng Luc99f3482014-10-16 09:52:36 +0800668 qpim_zclient_update->zebra_connected = pim_zebra_connected;
Everton Marques3456a802014-07-22 14:52:57 -0300669 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
670 qpim_zclient_update->interface_add = pim_zebra_if_add;
671 qpim_zclient_update->interface_delete = pim_zebra_if_del;
672 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
673 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
674 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
675 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
676 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
677 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
Everton Marques871dbcf2009-08-11 15:43:05 -0300678
David Lampartera2805de2015-02-04 06:33:26 +0100679 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
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 Marques3456a802014-07-22 14:52:57 -0300684 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300685
686 /* Request all redistribution */
687 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300688 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300689 continue;
Feng Luc99f3482014-10-16 09:52:36 +0800690 vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300691 if (PIM_DEBUG_PIM_TRACE) {
692 zlog_debug("%s: requesting redistribution for %s (%i)",
693 __PRETTY_FUNCTION__, zebra_route_string(i), i);
694 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300695 }
696
697 /* Request default information */
Feng Luc99f3482014-10-16 09:52:36 +0800698 vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300699 if (PIM_DEBUG_PIM_TRACE) {
700 zlog_info("%s: requesting default information redistribution",
Everton Marques871dbcf2009-08-11 15:43:05 -0300701 __PRETTY_FUNCTION__);
702
Everton Marquesc1b228c2014-08-27 15:27:26 -0300703 zlog_notice("%s: zclient update socket initialized",
704 __PRETTY_FUNCTION__);
705 }
706
Everton Marques871dbcf2009-08-11 15:43:05 -0300707 zassert(!qpim_zclient_lookup);
708 qpim_zclient_lookup = zclient_lookup_new();
709 zassert(qpim_zclient_lookup);
710}
711
712void igmp_anysource_forward_start(struct igmp_group *group)
713{
714 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
715 zassert(group->group_filtermode_isexcl);
716 zassert(listcount(group->group_source_list) < 1);
717
718 if (PIM_DEBUG_IGMP_TRACE) {
719 zlog_debug("%s %s: UNIMPLEMENTED",
720 __FILE__, __PRETTY_FUNCTION__);
721 }
722}
723
724void igmp_anysource_forward_stop(struct igmp_group *group)
725{
726 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
727 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
728
729 if (PIM_DEBUG_IGMP_TRACE) {
730 zlog_debug("%s %s: UNIMPLEMENTED",
731 __FILE__, __PRETTY_FUNCTION__);
732 }
733}
734
735static int fib_lookup_if_vif_index(struct in_addr addr)
736{
737 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
738 int num_ifindex;
739 int vif_index;
Paul Jakma9099f9b2016-01-18 10:12:10 +0000740 ifindex_t first_ifindex;
Everton Marques871dbcf2009-08-11 15:43:05 -0300741
742 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
743 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
744 PIM_NEXTHOP_LOOKUP_MAX);
745 if (num_ifindex < 1) {
746 char addr_str[100];
747 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
748 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
749 __FILE__, __PRETTY_FUNCTION__,
750 addr_str);
751 return -1;
752 }
753
754 first_ifindex = nexthop_tab[0].ifindex;
755
756 if (num_ifindex > 1) {
757 char addr_str[100];
758 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
Donald Sharpf3734dd2015-09-30 10:22:46 -0400759 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
Everton Marques871dbcf2009-08-11 15:43:05 -0300760 __FILE__, __PRETTY_FUNCTION__,
761 num_ifindex, addr_str, first_ifindex);
762 /* debug warning only, do not return */
763 }
764
765 if (PIM_DEBUG_ZEBRA) {
766 char addr_str[100];
767 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
768 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
769 __FILE__, __PRETTY_FUNCTION__,
770 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
771 }
772
773 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
774
775 if (vif_index < 1) {
776 char addr_str[100];
777 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
778 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
779 __FILE__, __PRETTY_FUNCTION__,
780 vif_index, addr_str);
781 return -2;
782 }
783
784 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
785
786 if (vif_index > qpim_mroute_oif_highest_vif_index) {
787 char addr_str[100];
788 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
789 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
790 __FILE__, __PRETTY_FUNCTION__,
791 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
792
793 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
794 __FILE__, __PRETTY_FUNCTION__,
795 ifindex2ifname(vif_index),
796 vif_index);
797
798 return -3;
799 }
800
801 return vif_index;
802}
803
804static int add_oif(struct channel_oil *channel_oil,
805 struct interface *oif,
806 uint32_t proto_mask)
807{
808 struct pim_interface *pim_ifp;
809 int old_ttl;
810
811 zassert(channel_oil);
812
813 pim_ifp = oif->info;
814
Everton Marques67faabc2010-02-23 12:11:11 -0300815 if (PIM_DEBUG_MROUTE) {
816 char group_str[100];
817 char source_str[100];
818 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
819 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
820 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
821 __FILE__, __PRETTY_FUNCTION__,
822 source_str, group_str,
823 proto_mask, oif->name, pim_ifp->mroute_vif_index);
824 }
825
Everton Marques871dbcf2009-08-11 15:43:05 -0300826 if (pim_ifp->mroute_vif_index < 1) {
827 zlog_warn("%s %s: interface %s vif_index=%d < 1",
828 __FILE__, __PRETTY_FUNCTION__,
829 oif->name, pim_ifp->mroute_vif_index);
830 return -1;
831 }
832
833#ifdef PIM_ENFORCE_LOOPFREE_MFC
834 /*
835 Prevent creating MFC entry with OIF=IIF.
836
837 This is a protection against implementation mistakes.
838
839 PIM protocol implicitely ensures loopfree multicast topology.
840
841 IGMP must be protected against adding looped MFC entries created
842 by both source and receiver attached to the same interface. See
843 TODO T22.
844 */
845 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
846 char group_str[100];
847 char source_str[100];
848 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
849 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
850 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
851 __FILE__, __PRETTY_FUNCTION__,
852 proto_mask, oif->name, pim_ifp->mroute_vif_index,
853 source_str, group_str);
854 return -2;
855 }
856#endif
857
858 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
859 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
860
861 /* Prevent single protocol from subscribing same interface to
862 channel (S,G) multiple times */
863 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
864 char group_str[100];
865 char source_str[100];
866 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
867 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
868 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
869 __FILE__, __PRETTY_FUNCTION__,
870 proto_mask, oif->name, pim_ifp->mroute_vif_index,
871 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
872 source_str, group_str);
873 return -3;
874 }
875
876 /* Allow other protocol to request subscription of same interface to
877 channel (S,G) multiple times, by silently ignoring further
878 requests */
879 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
880
881 /* Check the OIF really exists before returning, and only log
882 warning otherwise */
883 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
884 char group_str[100];
885 char source_str[100];
886 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
887 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
888 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
889 __FILE__, __PRETTY_FUNCTION__,
890 proto_mask, oif->name, pim_ifp->mroute_vif_index,
891 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
892 source_str, group_str);
893 }
894
895 return 0;
896 }
897
898 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
899
900 if (old_ttl > 0) {
901 char group_str[100];
902 char source_str[100];
903 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
904 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
905 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
906 __FILE__, __PRETTY_FUNCTION__,
907 oif->name, pim_ifp->mroute_vif_index,
908 source_str, group_str);
909 return -4;
910 }
911
912 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
913
914 if (pim_mroute_add(&channel_oil->oil)) {
915 char group_str[100];
916 char source_str[100];
917 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
918 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
919 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
920 __FILE__, __PRETTY_FUNCTION__,
921 oif->name, pim_ifp->mroute_vif_index,
922 source_str, group_str);
923
924 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
925 return -5;
926 }
927
928 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
929 ++channel_oil->oil_size;
930 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
931
Everton Marques67faabc2010-02-23 12:11:11 -0300932 if (PIM_DEBUG_MROUTE) {
933 char group_str[100];
934 char source_str[100];
935 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
936 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
937 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
938 __FILE__, __PRETTY_FUNCTION__,
939 source_str, group_str,
940 proto_mask, oif->name, pim_ifp->mroute_vif_index);
941 }
942
Everton Marques871dbcf2009-08-11 15:43:05 -0300943 return 0;
944}
945
946static int del_oif(struct channel_oil *channel_oil,
947 struct interface *oif,
948 uint32_t proto_mask)
949{
950 struct pim_interface *pim_ifp;
951 int old_ttl;
952
953 zassert(channel_oil);
954
955 pim_ifp = oif->info;
956
957 zassert(pim_ifp->mroute_vif_index >= 1);
958 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
959 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
960
Everton Marques67faabc2010-02-23 12:11:11 -0300961 if (PIM_DEBUG_MROUTE) {
962 char group_str[100];
963 char source_str[100];
964 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
965 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
966 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
967 __FILE__, __PRETTY_FUNCTION__,
968 source_str, group_str,
969 proto_mask, oif->name, pim_ifp->mroute_vif_index);
970 }
971
Everton Marques871dbcf2009-08-11 15:43:05 -0300972 /* Prevent single protocol from unsubscribing same interface from
973 channel (S,G) multiple times */
974 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
975 char group_str[100];
976 char source_str[100];
977 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
978 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
979 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
980 __FILE__, __PRETTY_FUNCTION__,
981 proto_mask, oif->name, pim_ifp->mroute_vif_index,
982 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
983 source_str, group_str);
984 return -2;
985 }
986
987 /* Mark that protocol is no longer interested in this OIF */
988 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
989
990 /* Allow multiple protocols to unsubscribe same interface from
991 channel (S,G) multiple times, by silently ignoring requests while
992 there is at least one protocol interested in the channel */
993 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
994
995 /* Check the OIF keeps existing before returning, and only log
996 warning otherwise */
997 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
998 char group_str[100];
999 char source_str[100];
1000 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1001 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1002 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
1003 __FILE__, __PRETTY_FUNCTION__,
1004 proto_mask, oif->name, pim_ifp->mroute_vif_index,
1005 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
1006 source_str, group_str);
1007 }
1008
1009 return 0;
1010 }
1011
1012 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1013
1014 if (old_ttl < 1) {
1015 char group_str[100];
1016 char source_str[100];
1017 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1018 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1019 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1020 __FILE__, __PRETTY_FUNCTION__,
1021 oif->name, pim_ifp->mroute_vif_index,
1022 source_str, group_str);
1023 return -3;
1024 }
1025
1026 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1027
1028 if (pim_mroute_add(&channel_oil->oil)) {
1029 char group_str[100];
1030 char source_str[100];
1031 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1032 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1033 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1034 __FILE__, __PRETTY_FUNCTION__,
1035 oif->name, pim_ifp->mroute_vif_index,
1036 source_str, group_str);
1037
1038 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1039 return -4;
1040 }
1041
1042 --channel_oil->oil_size;
1043
1044 if (channel_oil->oil_size < 1) {
1045 if (pim_mroute_del(&channel_oil->oil)) {
1046 /* just log a warning in case of failure */
1047 char group_str[100];
1048 char source_str[100];
1049 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1050 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1051 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1052 __FILE__, __PRETTY_FUNCTION__,
1053 source_str, group_str);
1054 }
1055 }
1056
Everton Marques67faabc2010-02-23 12:11:11 -03001057 if (PIM_DEBUG_MROUTE) {
1058 char group_str[100];
1059 char source_str[100];
1060 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1061 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1062 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1063 __FILE__, __PRETTY_FUNCTION__,
1064 source_str, group_str,
1065 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1066 }
1067
Everton Marques871dbcf2009-08-11 15:43:05 -03001068 return 0;
1069}
1070
1071void igmp_source_forward_start(struct igmp_source *source)
1072{
1073 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001074 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001075
1076 if (PIM_DEBUG_IGMP_TRACE) {
1077 char source_str[100];
1078 char group_str[100];
1079 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1080 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1081 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1082 __PRETTY_FUNCTION__,
1083 source_str, group_str,
1084 source->source_group->group_igmp_sock->fd,
1085 source->source_group->group_igmp_sock->interface->name,
1086 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1087 }
1088
1089 /* Prevent IGMP interface from installing multicast route multiple
1090 times */
1091 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1092 return;
1093 }
1094
1095 group = source->source_group;
1096
1097 if (!source->source_channel_oil) {
1098 struct pim_interface *pim_oif;
1099 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1100 if (input_iface_vif_index < 1) {
1101 char source_str[100];
1102 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1103 zlog_warn("%s %s: could not find input interface for source %s",
1104 __FILE__, __PRETTY_FUNCTION__,
1105 source_str);
1106 return;
1107 }
1108
1109 /*
1110 Protect IGMP against adding looped MFC entries created by both
1111 source and receiver attached to the same interface. See TODO
1112 T22.
1113 */
1114 pim_oif = source->source_group->group_igmp_sock->interface->info;
1115 if (!pim_oif) {
1116 zlog_warn("%s: multicast not enabled on oif=%s ?",
1117 __PRETTY_FUNCTION__,
1118 source->source_group->group_igmp_sock->interface->name);
1119 return;
1120 }
1121 if (pim_oif->mroute_vif_index < 1) {
1122 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1123 __FILE__, __PRETTY_FUNCTION__,
1124 source->source_group->group_igmp_sock->interface->name,
1125 pim_oif->mroute_vif_index);
1126 return;
1127 }
1128 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1129 /* ignore request for looped MFC entry */
1130 if (PIM_DEBUG_IGMP_TRACE) {
1131 char source_str[100];
1132 char group_str[100];
1133 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1134 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1135 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1136 __PRETTY_FUNCTION__,
1137 source_str, group_str,
1138 source->source_group->group_igmp_sock->fd,
1139 source->source_group->group_igmp_sock->interface->name,
1140 input_iface_vif_index);
1141 }
1142 return;
1143 }
1144
1145 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1146 source->source_addr,
1147 input_iface_vif_index);
1148 if (!source->source_channel_oil) {
1149 char group_str[100];
1150 char source_str[100];
1151 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1152 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1153 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1154 __FILE__, __PRETTY_FUNCTION__,
1155 source_str, group_str);
1156 return;
1157 }
1158 }
1159
Everton Marques24e3a9b2014-09-30 19:14:19 -03001160 result = add_oif(source->source_channel_oil,
1161 group->group_igmp_sock->interface,
1162 PIM_OIF_FLAG_PROTO_IGMP);
1163 if (result) {
1164 zlog_warn("%s: add_oif() failed with return=%d",
1165 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001166 return;
1167 }
1168
1169 /*
1170 Feed IGMPv3-gathered local membership information into PIM
1171 per-interface (S,G) state.
1172 */
1173 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1174 source->source_addr, group->group_addr);
1175
1176 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1177}
1178
Everton Marques24e3a9b2014-09-30 19:14:19 -03001179/*
1180 igmp_source_forward_stop: stop fowarding, but keep the source
1181 igmp_source_delete: stop fowarding, and delete the source
1182 */
Everton Marques871dbcf2009-08-11 15:43:05 -03001183void igmp_source_forward_stop(struct igmp_source *source)
1184{
1185 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001186 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001187
1188 if (PIM_DEBUG_IGMP_TRACE) {
1189 char source_str[100];
1190 char group_str[100];
1191 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1192 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1193 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1194 __PRETTY_FUNCTION__,
1195 source_str, group_str,
1196 source->source_group->group_igmp_sock->fd,
1197 source->source_group->group_igmp_sock->interface->name,
1198 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1199 }
1200
1201 /* Prevent IGMP interface from removing multicast route multiple
1202 times */
1203 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1204 return;
1205 }
1206
1207 group = source->source_group;
1208
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001209 /*
1210 It appears that in certain circumstances that
1211 igmp_source_forward_stop is called when IGMP forwarding
1212 was not enabled in oif_flags for this outgoing interface.
1213 Possibly because of multiple calls. When that happens, we
1214 enter the below if statement and this function returns early
1215 which in turn triggers the calling function to assert.
1216 Making the call to del_oif and ignoring the return code
1217 fixes the issue without ill effect, similar to
1218 pim_forward_stop below.
1219 */
Everton Marques24e3a9b2014-09-30 19:14:19 -03001220 result = del_oif(source->source_channel_oil,
1221 group->group_igmp_sock->interface,
1222 PIM_OIF_FLAG_PROTO_IGMP);
1223 if (result) {
1224 zlog_warn("%s: del_oif() failed with return=%d",
1225 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001226 return;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001227 }
Everton Marques871dbcf2009-08-11 15:43:05 -03001228
1229 /*
1230 Feed IGMPv3-gathered local membership information into PIM
1231 per-interface (S,G) state.
1232 */
1233 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1234 source->source_addr, group->group_addr);
1235
1236 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1237}
1238
1239void pim_forward_start(struct pim_ifchannel *ch)
1240{
1241 struct pim_upstream *up = ch->upstream;
1242
1243 if (PIM_DEBUG_PIM_TRACE) {
1244 char source_str[100];
1245 char group_str[100];
1246 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1247 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1248 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1249 __PRETTY_FUNCTION__,
1250 source_str, group_str, ch->interface->name);
1251 }
1252
1253 if (!up->channel_oil) {
1254 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1255 if (input_iface_vif_index < 1) {
1256 char source_str[100];
1257 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1258 zlog_warn("%s %s: could not find input interface for source %s",
1259 __FILE__, __PRETTY_FUNCTION__,
1260 source_str);
1261 return;
1262 }
1263
1264 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1265 input_iface_vif_index);
1266 if (!up->channel_oil) {
1267 char group_str[100];
1268 char source_str[100];
1269 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1270 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1271 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1272 __FILE__, __PRETTY_FUNCTION__,
1273 source_str, group_str);
1274 return;
1275 }
1276 }
1277
1278 add_oif(up->channel_oil,
1279 ch->interface,
1280 PIM_OIF_FLAG_PROTO_PIM);
1281}
1282
1283void pim_forward_stop(struct pim_ifchannel *ch)
1284{
1285 struct pim_upstream *up = ch->upstream;
1286
1287 if (PIM_DEBUG_PIM_TRACE) {
1288 char source_str[100];
1289 char group_str[100];
1290 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1291 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1292 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1293 __PRETTY_FUNCTION__,
1294 source_str, group_str, ch->interface->name);
1295 }
1296
1297 if (!up->channel_oil) {
1298 char source_str[100];
1299 char group_str[100];
1300 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1301 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1302 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1303 __PRETTY_FUNCTION__,
1304 source_str, group_str, ch->interface->name);
1305
1306 return;
1307 }
1308
1309 del_oif(up->channel_oil,
1310 ch->interface,
1311 PIM_OIF_FLAG_PROTO_PIM);
1312}