blob: 7072a3b28d8f89d1c18a461f4fae79ab3e08d389 [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
54/* Router-id update message from zebra. */
55static int pim_router_id_update_zebra(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +080056 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -030057{
58 struct prefix router_id;
59
Everton Marques871dbcf2009-08-11 15:43:05 -030060 zebra_router_id_update_read(zclient->ibuf, &router_id);
61
62 return 0;
63}
64
65static int pim_zebra_if_add(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +080066 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -030067{
68 struct interface *ifp;
69
70 /*
71 zebra api adds/dels interfaces using the same call
72 interface_add_read below, see comments in lib/zclient.c
73 */
Feng Luc99f3482014-10-16 09:52:36 +080074 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -030075 if (!ifp)
76 return 0;
77
78 if (PIM_DEBUG_ZEBRA) {
79 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
80 __PRETTY_FUNCTION__,
81 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
82 ifp->mtu, if_is_operative(ifp));
83 }
84
85 if (if_is_operative(ifp))
86 pim_if_addr_add_all(ifp);
87
88 return 0;
89}
90
91static int pim_zebra_if_del(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +080092 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -030093{
94 struct interface *ifp;
95
96 /*
97 zebra api adds/dels interfaces using the same call
98 interface_add_read below, see comments in lib/zclient.c
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -030099
100 comments in lib/zclient.c seem to indicate that calling
101 zebra_interface_add_read is the correct call, but that
102 results in an attemted out of bounds read which causes
103 pimd to assert. Other clients use zebra_interface_state_read
104 and it appears to work just fine.
Everton Marques871dbcf2009-08-11 15:43:05 -0300105 */
Feng Luc99f3482014-10-16 09:52:36 +0800106 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300107 if (!ifp)
108 return 0;
109
110 if (PIM_DEBUG_ZEBRA) {
111 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
112 __PRETTY_FUNCTION__,
113 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
114 ifp->mtu, if_is_operative(ifp));
115 }
116
117 if (!if_is_operative(ifp))
118 pim_if_addr_del_all(ifp);
119
120 return 0;
121}
122
123static int pim_zebra_if_state_up(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +0800124 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300125{
126 struct interface *ifp;
127
128 /*
129 zebra api notifies interface up/down events by using the same call
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -0300130 zebra_interface_state_read below, see comments in lib/zclient.c
Everton Marques871dbcf2009-08-11 15:43:05 -0300131 */
Feng Luc99f3482014-10-16 09:52:36 +0800132 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300133 if (!ifp)
134 return 0;
135
136 if (PIM_DEBUG_ZEBRA) {
137 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
138 __PRETTY_FUNCTION__,
139 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
140 ifp->mtu, if_is_operative(ifp));
141 }
142
143 if (if_is_operative(ifp)) {
144 /*
145 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
146 */
147 pim_if_addr_add_all(ifp);
148 }
149
150 return 0;
151}
152
153static int pim_zebra_if_state_down(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +0800154 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300155{
156 struct interface *ifp;
157
158 /*
159 zebra api notifies interface up/down events by using the same call
Savannah SR#1085426ab3e2f2014-09-25 16:59:38 -0300160 zebra_interface_state_read below, see comments in lib/zclient.c
Everton Marques871dbcf2009-08-11 15:43:05 -0300161 */
Feng Luc99f3482014-10-16 09:52:36 +0800162 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300163 if (!ifp)
164 return 0;
165
166 if (PIM_DEBUG_ZEBRA) {
167 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
168 __PRETTY_FUNCTION__,
169 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
170 ifp->mtu, if_is_operative(ifp));
171 }
172
173 if (!if_is_operative(ifp)) {
174 /*
175 pim_if_addr_del_all() suffices for shutting down IGMP,
176 but not for shutting down PIM
177 */
178 pim_if_addr_del_all(ifp);
179
180 /*
181 pim_sock_delete() closes the socket, stops read and timer threads,
182 and kills all neighbors.
183 */
Everton Marquese96f0af2009-08-11 15:48:02 -0300184 if (ifp->info) {
185 pim_sock_delete(ifp, "link down");
186 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300187 }
188
189 return 0;
190}
191
192#ifdef PIM_DEBUG_IFADDR_DUMP
193static void dump_if_address(struct interface *ifp)
194{
195 struct connected *ifc;
196 struct listnode *node;
197
198 zlog_debug("%s %s: interface %s addresses:",
199 __FILE__, __PRETTY_FUNCTION__,
200 ifp->name);
201
202 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
203 struct prefix *p = ifc->address;
204
205 if (p->family != AF_INET)
206 continue;
207
Everton Marques306c99e2014-07-16 15:51:37 -0300208 zlog_debug("%s %s: interface %s address %s %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300209 __FILE__, __PRETTY_FUNCTION__,
210 ifp->name,
Everton Marques306c99e2014-07-16 15:51:37 -0300211 inet_ntoa(p->u.prefix4),
212 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
213 "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300214 }
215}
216#endif
217
218static int pim_zebra_if_address_add(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +0800219 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300220{
221 struct connected *c;
222 struct prefix *p;
223
Everton Marques871dbcf2009-08-11 15:43:05 -0300224 /*
225 zebra api notifies address adds/dels events by using the same call
226 interface_add_read below, see comments in lib/zclient.c
227
228 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
229 will add address to interface list by calling
230 connected_add_by_prefix()
231 */
Feng Luc99f3482014-10-16 09:52:36 +0800232 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300233 if (!c)
234 return 0;
235
236 p = c->address;
237 if (p->family != AF_INET)
238 return 0;
239
240 if (PIM_DEBUG_ZEBRA) {
241 char buf[BUFSIZ];
242 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300243 zlog_debug("%s: %s connected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300244 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300245 c->ifp->name, buf, c->flags,
246 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300247
248#ifdef PIM_DEBUG_IFADDR_DUMP
249 dump_if_address(c->ifp);
250#endif
251 }
252
Everton Marques306c99e2014-07-16 15:51:37 -0300253 if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
254 /* trying to add primary address */
255
256 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
257 if (primary_addr.s_addr != p->u.prefix4.s_addr) {
Donald Sharpa6a11762015-10-02 12:27:27 -0400258 if (PIM_DEBUG_ZEBRA) {
259 /* but we had a primary address already */
Everton Marques306c99e2014-07-16 15:51:37 -0300260
Donald Sharpa6a11762015-10-02 12:27:27 -0400261 char buf[BUFSIZ];
262 char old[100];
Everton Marques306c99e2014-07-16 15:51:37 -0300263
Donald Sharpa6a11762015-10-02 12:27:27 -0400264 prefix2str(p, buf, BUFSIZ);
265 pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
Everton Marques306c99e2014-07-16 15:51:37 -0300266
Donald Sharpa6a11762015-10-02 12:27:27 -0400267 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
268 __PRETTY_FUNCTION__,
269 c->ifp->name, old, buf);
270 }
Everton Marques306c99e2014-07-16 15:51:37 -0300271 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
272 }
273 }
274
Everton Marques871dbcf2009-08-11 15:43:05 -0300275 pim_if_addr_add(c);
276
277 return 0;
278}
279
280static int pim_zebra_if_address_del(int command, struct zclient *client,
Feng Luc99f3482014-10-16 09:52:36 +0800281 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300282{
283 struct connected *c;
284 struct prefix *p;
285
Everton Marques871dbcf2009-08-11 15:43:05 -0300286 /*
287 zebra api notifies address adds/dels events by using the same call
288 interface_add_read below, see comments in lib/zclient.c
289
290 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
291 will remove address from interface list by calling
292 connected_delete_by_prefix()
293 */
Feng Luc99f3482014-10-16 09:52:36 +0800294 c = zebra_interface_address_read(command, client->ibuf, vrf_id);
Everton Marques871dbcf2009-08-11 15:43:05 -0300295 if (!c)
296 return 0;
297
298 p = c->address;
299 if (p->family != AF_INET)
300 return 0;
301
302 if (PIM_DEBUG_ZEBRA) {
303 char buf[BUFSIZ];
304 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300305 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300306 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300307 c->ifp->name, buf, c->flags,
308 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300309
310#ifdef PIM_DEBUG_IFADDR_DUMP
311 dump_if_address(c->ifp);
312#endif
313 }
Everton Marques306c99e2014-07-16 15:51:37 -0300314
Everton Marques2a0ecf22014-09-22 18:18:26 -0300315 pim_if_addr_del(c, 0);
Everton Marques871dbcf2009-08-11 15:43:05 -0300316
317 return 0;
318}
319
320static void scan_upstream_rpf_cache()
321{
322 struct listnode *up_node;
323 struct listnode *up_nextnode;
324 struct pim_upstream *up;
325
326 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
Jafar Al-Gharaibeh06de82e2016-05-09 15:18:56 -0500327 struct pim_rpf old_rpf;
Everton Marques871dbcf2009-08-11 15:43:05 -0300328 enum pim_rpf_result rpf_result;
329
Jafar Al-Gharaibeh06de82e2016-05-09 15:18:56 -0500330 rpf_result = pim_rpf_update(up, &old_rpf);
Everton Marques871dbcf2009-08-11 15:43:05 -0300331 if (rpf_result == PIM_RPF_FAILURE)
332 continue;
333
334 if (rpf_result == PIM_RPF_CHANGED) {
335
336 if (up->join_state == PIM_UPSTREAM_JOINED) {
337
338 /*
339 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
340
341 Transitions from Joined State
342
343 RPF'(S,G) changes not due to an Assert
344
345 The upstream (S,G) state machine remains in Joined
346 state. Send Join(S,G) to the new upstream neighbor, which is
347 the new value of RPF'(S,G). Send Prune(S,G) to the old
348 upstream neighbor, which is the old value of RPF'(S,G). Set
349 the Join Timer (JT) to expire after t_periodic seconds.
350 */
351
352
353 /* send Prune(S,G) to the old upstream neighbor */
Jafar Al-Gharaibeh06de82e2016-05-09 15:18:56 -0500354 pim_joinprune_send(old_rpf.source_nexthop.interface,
355 old_rpf.rpf_addr,
Everton Marques871dbcf2009-08-11 15:43:05 -0300356 up->source_addr,
357 up->group_addr,
358 0 /* prune */);
359
360 /* send Join(S,G) to the current upstream neighbor */
361 pim_joinprune_send(up->rpf.source_nexthop.interface,
362 up->rpf.rpf_addr,
363 up->source_addr,
364 up->group_addr,
365 1 /* join */);
366
367 pim_upstream_join_timer_restart(up);
368 } /* up->join_state == PIM_UPSTREAM_JOINED */
369
370 /* FIXME can join_desired actually be changed by pim_rpf_update()
371 returning PIM_RPF_CHANGED ? */
372 pim_upstream_update_join_desired(up);
373
374 } /* PIM_RPF_CHANGED */
375
376 } /* for (qpim_upstream_list) */
377
378}
379
Everton Marquesf24200d2014-02-14 16:40:34 -0200380void pim_scan_oil()
Everton Marques871dbcf2009-08-11 15:43:05 -0300381{
382 struct listnode *node;
383 struct listnode *nextnode;
384 struct channel_oil *c_oil;
385
Everton Marquesf24200d2014-02-14 16:40:34 -0200386 qpim_scan_oil_last = pim_time_monotonic_sec();
387 ++qpim_scan_oil_events;
388
Everton Marques871dbcf2009-08-11 15:43:05 -0300389 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
390 int old_vif_index;
391 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
392 if (input_iface_vif_index < 1) {
393 char source_str[100];
394 char group_str[100];
395 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
396 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
397 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
398 __FILE__, __PRETTY_FUNCTION__,
399 source_str, group_str);
400 continue;
401 }
402
403 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
404 /* RPF unchanged */
405 continue;
406 }
407
408 if (PIM_DEBUG_ZEBRA) {
409 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
410 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
411 char source_str[100];
412 char group_str[100];
413 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
414 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
415 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
416 __FILE__, __PRETTY_FUNCTION__,
417 source_str, group_str,
418 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
419 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
420 }
421
422 /* new iif loops to existing oif ? */
423 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
424 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
425
426 if (PIM_DEBUG_ZEBRA) {
427 char source_str[100];
428 char group_str[100];
429 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
430 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
431 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
432 __FILE__, __PRETTY_FUNCTION__,
433 source_str, group_str,
434 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
435 }
436
437 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
438 }
439
440 /* update iif vif_index */
441 old_vif_index = c_oil->oil.mfcc_parent;
442 c_oil->oil.mfcc_parent = input_iface_vif_index;
443
444 /* update kernel multicast forwarding cache (MFC) */
445 if (pim_mroute_add(&c_oil->oil)) {
446 /* just log warning */
447 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
448 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
449 char source_str[100];
450 char group_str[100];
451 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
452 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
453 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
454 __FILE__, __PRETTY_FUNCTION__,
455 source_str, group_str,
456 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
457 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
458 continue;
459 }
460
461 } /* for (qpim_channel_oil_list) */
462}
463
464static int on_rpf_cache_refresh(struct thread *t)
465{
466 zassert(t);
467 zassert(qpim_rpf_cache_refresher);
468
469 qpim_rpf_cache_refresher = 0;
470
471 /* update PIM protocol state */
472 scan_upstream_rpf_cache();
473
474 /* update kernel multicast forwarding cache (MFC) */
Everton Marquesf24200d2014-02-14 16:40:34 -0200475 pim_scan_oil();
Everton Marques871dbcf2009-08-11 15:43:05 -0300476
Everton Marquesbcc4abe2009-08-17 18:18:59 -0300477 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
Everton Marques613938d2009-08-13 15:39:31 -0300478 ++qpim_rpf_cache_refresh_events;
479
Everton Marques871dbcf2009-08-11 15:43:05 -0300480 return 0;
481}
482
483static void sched_rpf_cache_refresh()
484{
Everton Marques613938d2009-08-13 15:39:31 -0300485 ++qpim_rpf_cache_refresh_requests;
486
487 if (qpim_rpf_cache_refresher) {
488 /* Refresh timer is already running */
Everton Marques871dbcf2009-08-11 15:43:05 -0300489 return;
Everton Marques613938d2009-08-13 15:39:31 -0300490 }
491
492 /* Start refresh timer */
Everton Marques871dbcf2009-08-11 15:43:05 -0300493
494 if (PIM_DEBUG_ZEBRA) {
495 zlog_debug("%s: triggering %ld msec timer",
496 __PRETTY_FUNCTION__,
497 qpim_rpf_cache_refresh_delay_msec);
498 }
499
500 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
501 on_rpf_cache_refresh,
502 0, qpim_rpf_cache_refresh_delay_msec);
503}
504
505static int redist_read_ipv4_route(int command, struct zclient *zclient,
Feng Luc99f3482014-10-16 09:52:36 +0800506 zebra_size_t length, vrf_id_t vrf_id)
Everton Marques871dbcf2009-08-11 15:43:05 -0300507{
508 struct stream *s;
509 struct zapi_ipv4 api;
Paul Jakma9099f9b2016-01-18 10:12:10 +0000510 ifindex_t ifindex;
Everton Marques871dbcf2009-08-11 15:43:05 -0300511 struct in_addr nexthop;
512 struct prefix_ipv4 p;
513 int min_len = 4;
514
515 if (length < min_len) {
516 zlog_warn("%s %s: short buffer: length=%d min=%d",
517 __FILE__, __PRETTY_FUNCTION__,
518 length, min_len);
519 return -1;
520 }
521
522 s = zclient->ibuf;
523 ifindex = 0;
524 nexthop.s_addr = 0;
525
526 /* Type, flags, message. */
527 api.type = stream_getc(s);
528 api.flags = stream_getc(s);
529 api.message = stream_getc(s);
530
531 /* IPv4 prefix length. */
532 memset(&p, 0, sizeof(struct prefix_ipv4));
533 p.family = AF_INET;
534 p.prefixlen = stream_getc(s);
535
536 min_len +=
537 PSIZE(p.prefixlen) +
538 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
539 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
540 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
541 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
542
543 if (PIM_DEBUG_ZEBRA) {
544 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
545 __FILE__, __PRETTY_FUNCTION__,
546 length, min_len,
547 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
548 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
549 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
550 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
551 }
552
553 if (length < min_len) {
554 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
555 __FILE__, __PRETTY_FUNCTION__,
556 length, min_len,
557 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
558 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
559 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
560 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
561 return -1;
562 }
563
564 /* IPv4 prefix. */
565 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
566
567 /* Nexthop, ifindex, distance, metric. */
568 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
569 api.nexthop_num = stream_getc(s);
570 nexthop.s_addr = stream_get_ipv4(s);
571 }
572 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
573 api.ifindex_num = stream_getc(s);
574 ifindex = stream_getl(s);
575 }
576
577 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
David Lamparter105ad862012-02-16 04:50:35 +0000578 stream_getc(s) :
Everton Marques871dbcf2009-08-11 15:43:05 -0300579 0;
580
581 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
582 stream_getl(s) :
583 0;
584
585 switch (command) {
586 case ZEBRA_IPV4_ROUTE_ADD:
587 if (PIM_DEBUG_ZEBRA) {
588 char buf[2][INET_ADDRSTRLEN];
589 zlog_debug("%s: add %s %s/%d "
Paul Jakma9099f9b2016-01-18 10:12:10 +0000590 "nexthop %s ifindex %d metric%s %u distance%s %u",
Everton Marques871dbcf2009-08-11 15:43:05 -0300591 __PRETTY_FUNCTION__,
592 zebra_route_string(api.type),
593 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
594 p.prefixlen,
595 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
596 ifindex,
597 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
598 api.metric,
599 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
600 api.distance);
601 }
602 break;
603 case ZEBRA_IPV4_ROUTE_DELETE:
604 if (PIM_DEBUG_ZEBRA) {
605 char buf[2][INET_ADDRSTRLEN];
606 zlog_debug("%s: delete %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 default:
621 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
622 return -1;
623 }
624
625 sched_rpf_cache_refresh();
626
627 return 0;
628}
629
Feng Luc99f3482014-10-16 09:52:36 +0800630static void pim_zebra_connected(struct zclient *zclient)
631{
632 zclient_send_requests(zclient, VRF_DEFAULT);
633}
634
Donald Sharp71252932015-09-24 09:25:19 -0400635void pim_zebra_init (struct thread_master *master, char *zebra_sock_path)
Everton Marques871dbcf2009-08-11 15:43:05 -0300636{
Everton Marques871dbcf2009-08-11 15:43:05 -0300637 int i;
638
Everton Marques1f298942014-08-21 15:47:28 -0300639 if (zebra_sock_path)
640 zclient_serv_path_set(zebra_sock_path);
641
Everton Marques871dbcf2009-08-11 15:43:05 -0300642#ifdef HAVE_TCP_ZEBRA
643 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
644#else
Everton Marques1f298942014-08-21 15:47:28 -0300645 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
Everton Marques871dbcf2009-08-11 15:43:05 -0300646#endif
647
648 /* Socket for receiving updates from Zebra daemon */
Donald Sharp71252932015-09-24 09:25:19 -0400649 qpim_zclient_update = zclient_new (master);
Everton Marques871dbcf2009-08-11 15:43:05 -0300650
Feng Luc99f3482014-10-16 09:52:36 +0800651 qpim_zclient_update->zebra_connected = pim_zebra_connected;
Everton Marques3456a802014-07-22 14:52:57 -0300652 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
653 qpim_zclient_update->interface_add = pim_zebra_if_add;
654 qpim_zclient_update->interface_delete = pim_zebra_if_del;
655 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
656 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
657 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
658 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
659 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
660 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
Everton Marques871dbcf2009-08-11 15:43:05 -0300661
David Lampartera2805de2015-02-04 06:33:26 +0100662 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300663 if (PIM_DEBUG_PIM_TRACE) {
664 zlog_info("zclient_init cleared redistribution request");
665 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300666
Everton Marques3456a802014-07-22 14:52:57 -0300667 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300668
669 /* Request all redistribution */
670 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300671 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300672 continue;
Feng Luc99f3482014-10-16 09:52:36 +0800673 vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300674 if (PIM_DEBUG_PIM_TRACE) {
675 zlog_debug("%s: requesting redistribution for %s (%i)",
676 __PRETTY_FUNCTION__, zebra_route_string(i), i);
677 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300678 }
679
680 /* Request default information */
Feng Luc99f3482014-10-16 09:52:36 +0800681 vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300682 if (PIM_DEBUG_PIM_TRACE) {
683 zlog_info("%s: requesting default information redistribution",
Everton Marques871dbcf2009-08-11 15:43:05 -0300684 __PRETTY_FUNCTION__);
685
Everton Marquesc1b228c2014-08-27 15:27:26 -0300686 zlog_notice("%s: zclient update socket initialized",
687 __PRETTY_FUNCTION__);
688 }
689
Everton Marques871dbcf2009-08-11 15:43:05 -0300690 zassert(!qpim_zclient_lookup);
691 qpim_zclient_lookup = zclient_lookup_new();
692 zassert(qpim_zclient_lookup);
693}
694
695void igmp_anysource_forward_start(struct igmp_group *group)
696{
697 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
698 zassert(group->group_filtermode_isexcl);
699 zassert(listcount(group->group_source_list) < 1);
700
701 if (PIM_DEBUG_IGMP_TRACE) {
702 zlog_debug("%s %s: UNIMPLEMENTED",
703 __FILE__, __PRETTY_FUNCTION__);
704 }
705}
706
707void igmp_anysource_forward_stop(struct igmp_group *group)
708{
709 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
710 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
711
712 if (PIM_DEBUG_IGMP_TRACE) {
713 zlog_debug("%s %s: UNIMPLEMENTED",
714 __FILE__, __PRETTY_FUNCTION__);
715 }
716}
717
718static int fib_lookup_if_vif_index(struct in_addr addr)
719{
720 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
721 int num_ifindex;
722 int vif_index;
Paul Jakma9099f9b2016-01-18 10:12:10 +0000723 ifindex_t first_ifindex;
Everton Marques871dbcf2009-08-11 15:43:05 -0300724
725 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
726 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
727 PIM_NEXTHOP_LOOKUP_MAX);
728 if (num_ifindex < 1) {
729 char addr_str[100];
730 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
731 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
732 __FILE__, __PRETTY_FUNCTION__,
733 addr_str);
734 return -1;
735 }
736
737 first_ifindex = nexthop_tab[0].ifindex;
738
739 if (num_ifindex > 1) {
740 char addr_str[100];
741 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
Donald Sharpf3734dd2015-09-30 10:22:46 -0400742 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 -0300743 __FILE__, __PRETTY_FUNCTION__,
744 num_ifindex, addr_str, first_ifindex);
745 /* debug warning only, do not return */
746 }
747
748 if (PIM_DEBUG_ZEBRA) {
749 char addr_str[100];
750 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
751 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
752 __FILE__, __PRETTY_FUNCTION__,
753 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
754 }
755
756 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
757
758 if (vif_index < 1) {
759 char addr_str[100];
760 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
761 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
762 __FILE__, __PRETTY_FUNCTION__,
763 vif_index, addr_str);
764 return -2;
765 }
766
767 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
768
769 if (vif_index > qpim_mroute_oif_highest_vif_index) {
770 char addr_str[100];
771 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
772 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
773 __FILE__, __PRETTY_FUNCTION__,
774 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
775
776 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
777 __FILE__, __PRETTY_FUNCTION__,
778 ifindex2ifname(vif_index),
779 vif_index);
780
781 return -3;
782 }
783
784 return vif_index;
785}
786
787static int add_oif(struct channel_oil *channel_oil,
788 struct interface *oif,
789 uint32_t proto_mask)
790{
791 struct pim_interface *pim_ifp;
792 int old_ttl;
793
794 zassert(channel_oil);
795
796 pim_ifp = oif->info;
797
Everton Marques67faabc2010-02-23 12:11:11 -0300798 if (PIM_DEBUG_MROUTE) {
799 char group_str[100];
800 char source_str[100];
801 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
802 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
803 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
804 __FILE__, __PRETTY_FUNCTION__,
805 source_str, group_str,
806 proto_mask, oif->name, pim_ifp->mroute_vif_index);
807 }
808
Everton Marques871dbcf2009-08-11 15:43:05 -0300809 if (pim_ifp->mroute_vif_index < 1) {
810 zlog_warn("%s %s: interface %s vif_index=%d < 1",
811 __FILE__, __PRETTY_FUNCTION__,
812 oif->name, pim_ifp->mroute_vif_index);
813 return -1;
814 }
815
816#ifdef PIM_ENFORCE_LOOPFREE_MFC
817 /*
818 Prevent creating MFC entry with OIF=IIF.
819
820 This is a protection against implementation mistakes.
821
822 PIM protocol implicitely ensures loopfree multicast topology.
823
824 IGMP must be protected against adding looped MFC entries created
825 by both source and receiver attached to the same interface. See
826 TODO T22.
827 */
828 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
829 char group_str[100];
830 char source_str[100];
831 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
832 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
833 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
834 __FILE__, __PRETTY_FUNCTION__,
835 proto_mask, oif->name, pim_ifp->mroute_vif_index,
836 source_str, group_str);
837 return -2;
838 }
839#endif
840
841 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
842 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
843
844 /* Prevent single protocol from subscribing same interface to
845 channel (S,G) multiple times */
846 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
847 char group_str[100];
848 char source_str[100];
849 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
850 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
851 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
852 __FILE__, __PRETTY_FUNCTION__,
853 proto_mask, oif->name, pim_ifp->mroute_vif_index,
854 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
855 source_str, group_str);
856 return -3;
857 }
858
859 /* Allow other protocol to request subscription of same interface to
860 channel (S,G) multiple times, by silently ignoring further
861 requests */
862 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
863
864 /* Check the OIF really exists before returning, and only log
865 warning otherwise */
866 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
867 char group_str[100];
868 char source_str[100];
869 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
870 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
871 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
872 __FILE__, __PRETTY_FUNCTION__,
873 proto_mask, oif->name, pim_ifp->mroute_vif_index,
874 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
875 source_str, group_str);
876 }
877
878 return 0;
879 }
880
881 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
882
883 if (old_ttl > 0) {
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: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
889 __FILE__, __PRETTY_FUNCTION__,
890 oif->name, pim_ifp->mroute_vif_index,
891 source_str, group_str);
892 return -4;
893 }
894
895 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
896
897 if (pim_mroute_add(&channel_oil->oil)) {
898 char group_str[100];
899 char source_str[100];
900 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
901 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
902 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
903 __FILE__, __PRETTY_FUNCTION__,
904 oif->name, pim_ifp->mroute_vif_index,
905 source_str, group_str);
906
907 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
908 return -5;
909 }
910
911 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
912 ++channel_oil->oil_size;
913 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
914
Everton Marques67faabc2010-02-23 12:11:11 -0300915 if (PIM_DEBUG_MROUTE) {
916 char group_str[100];
917 char source_str[100];
918 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
919 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
920 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
921 __FILE__, __PRETTY_FUNCTION__,
922 source_str, group_str,
923 proto_mask, oif->name, pim_ifp->mroute_vif_index);
924 }
925
Everton Marques871dbcf2009-08-11 15:43:05 -0300926 return 0;
927}
928
929static int del_oif(struct channel_oil *channel_oil,
930 struct interface *oif,
931 uint32_t proto_mask)
932{
933 struct pim_interface *pim_ifp;
934 int old_ttl;
935
936 zassert(channel_oil);
937
938 pim_ifp = oif->info;
939
940 zassert(pim_ifp->mroute_vif_index >= 1);
941 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
942 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
943
Everton Marques67faabc2010-02-23 12:11:11 -0300944 if (PIM_DEBUG_MROUTE) {
945 char group_str[100];
946 char source_str[100];
947 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
948 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
949 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
950 __FILE__, __PRETTY_FUNCTION__,
951 source_str, group_str,
952 proto_mask, oif->name, pim_ifp->mroute_vif_index);
953 }
954
Everton Marques871dbcf2009-08-11 15:43:05 -0300955 /* Prevent single protocol from unsubscribing same interface from
956 channel (S,G) multiple times */
957 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
958 char group_str[100];
959 char source_str[100];
960 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
961 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
962 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
963 __FILE__, __PRETTY_FUNCTION__,
964 proto_mask, oif->name, pim_ifp->mroute_vif_index,
965 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
966 source_str, group_str);
967 return -2;
968 }
969
970 /* Mark that protocol is no longer interested in this OIF */
971 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
972
973 /* Allow multiple protocols to unsubscribe same interface from
974 channel (S,G) multiple times, by silently ignoring requests while
975 there is at least one protocol interested in the channel */
976 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
977
978 /* Check the OIF keeps existing before returning, and only log
979 warning otherwise */
980 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
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: protocol mask %u removing nonexistent 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 }
991
992 return 0;
993 }
994
995 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
996
997 if (old_ttl < 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: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1003 __FILE__, __PRETTY_FUNCTION__,
1004 oif->name, pim_ifp->mroute_vif_index,
1005 source_str, group_str);
1006 return -3;
1007 }
1008
1009 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1010
1011 if (pim_mroute_add(&channel_oil->oil)) {
1012 char group_str[100];
1013 char source_str[100];
1014 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1015 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1016 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1017 __FILE__, __PRETTY_FUNCTION__,
1018 oif->name, pim_ifp->mroute_vif_index,
1019 source_str, group_str);
1020
1021 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1022 return -4;
1023 }
1024
1025 --channel_oil->oil_size;
1026
1027 if (channel_oil->oil_size < 1) {
1028 if (pim_mroute_del(&channel_oil->oil)) {
1029 /* just log a warning in case of failure */
1030 char group_str[100];
1031 char source_str[100];
1032 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1033 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1034 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1035 __FILE__, __PRETTY_FUNCTION__,
1036 source_str, group_str);
1037 }
1038 }
1039
Everton Marques67faabc2010-02-23 12:11:11 -03001040 if (PIM_DEBUG_MROUTE) {
1041 char group_str[100];
1042 char source_str[100];
1043 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1044 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1045 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1046 __FILE__, __PRETTY_FUNCTION__,
1047 source_str, group_str,
1048 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1049 }
1050
Everton Marques871dbcf2009-08-11 15:43:05 -03001051 return 0;
1052}
1053
1054void igmp_source_forward_start(struct igmp_source *source)
1055{
1056 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001057 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001058
1059 if (PIM_DEBUG_IGMP_TRACE) {
1060 char source_str[100];
1061 char group_str[100];
1062 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1063 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1064 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1065 __PRETTY_FUNCTION__,
1066 source_str, group_str,
1067 source->source_group->group_igmp_sock->fd,
1068 source->source_group->group_igmp_sock->interface->name,
1069 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1070 }
1071
1072 /* Prevent IGMP interface from installing multicast route multiple
1073 times */
1074 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1075 return;
1076 }
1077
1078 group = source->source_group;
1079
1080 if (!source->source_channel_oil) {
1081 struct pim_interface *pim_oif;
1082 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1083 if (input_iface_vif_index < 1) {
1084 char source_str[100];
1085 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1086 zlog_warn("%s %s: could not find input interface for source %s",
1087 __FILE__, __PRETTY_FUNCTION__,
1088 source_str);
1089 return;
1090 }
1091
1092 /*
1093 Protect IGMP against adding looped MFC entries created by both
1094 source and receiver attached to the same interface. See TODO
1095 T22.
1096 */
1097 pim_oif = source->source_group->group_igmp_sock->interface->info;
1098 if (!pim_oif) {
1099 zlog_warn("%s: multicast not enabled on oif=%s ?",
1100 __PRETTY_FUNCTION__,
1101 source->source_group->group_igmp_sock->interface->name);
1102 return;
1103 }
1104 if (pim_oif->mroute_vif_index < 1) {
1105 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1106 __FILE__, __PRETTY_FUNCTION__,
1107 source->source_group->group_igmp_sock->interface->name,
1108 pim_oif->mroute_vif_index);
1109 return;
1110 }
1111 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1112 /* ignore request for looped MFC entry */
1113 if (PIM_DEBUG_IGMP_TRACE) {
1114 char source_str[100];
1115 char group_str[100];
1116 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1117 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1118 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1119 __PRETTY_FUNCTION__,
1120 source_str, group_str,
1121 source->source_group->group_igmp_sock->fd,
1122 source->source_group->group_igmp_sock->interface->name,
1123 input_iface_vif_index);
1124 }
1125 return;
1126 }
1127
1128 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1129 source->source_addr,
1130 input_iface_vif_index);
1131 if (!source->source_channel_oil) {
1132 char group_str[100];
1133 char source_str[100];
1134 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1135 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1136 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1137 __FILE__, __PRETTY_FUNCTION__,
1138 source_str, group_str);
1139 return;
1140 }
1141 }
1142
Everton Marques24e3a9b2014-09-30 19:14:19 -03001143 result = add_oif(source->source_channel_oil,
1144 group->group_igmp_sock->interface,
1145 PIM_OIF_FLAG_PROTO_IGMP);
1146 if (result) {
1147 zlog_warn("%s: add_oif() failed with return=%d",
1148 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001149 return;
1150 }
1151
1152 /*
1153 Feed IGMPv3-gathered local membership information into PIM
1154 per-interface (S,G) state.
1155 */
1156 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1157 source->source_addr, group->group_addr);
1158
1159 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1160}
1161
Everton Marques24e3a9b2014-09-30 19:14:19 -03001162/*
1163 igmp_source_forward_stop: stop fowarding, but keep the source
1164 igmp_source_delete: stop fowarding, and delete the source
1165 */
Everton Marques871dbcf2009-08-11 15:43:05 -03001166void igmp_source_forward_stop(struct igmp_source *source)
1167{
1168 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001169 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001170
1171 if (PIM_DEBUG_IGMP_TRACE) {
1172 char source_str[100];
1173 char group_str[100];
1174 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1175 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1176 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1177 __PRETTY_FUNCTION__,
1178 source_str, group_str,
1179 source->source_group->group_igmp_sock->fd,
1180 source->source_group->group_igmp_sock->interface->name,
1181 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1182 }
1183
1184 /* Prevent IGMP interface from removing multicast route multiple
1185 times */
1186 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1187 return;
1188 }
1189
1190 group = source->source_group;
1191
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001192 /*
1193 It appears that in certain circumstances that
1194 igmp_source_forward_stop is called when IGMP forwarding
1195 was not enabled in oif_flags for this outgoing interface.
1196 Possibly because of multiple calls. When that happens, we
1197 enter the below if statement and this function returns early
1198 which in turn triggers the calling function to assert.
1199 Making the call to del_oif and ignoring the return code
1200 fixes the issue without ill effect, similar to
1201 pim_forward_stop below.
1202 */
Everton Marques24e3a9b2014-09-30 19:14:19 -03001203 result = del_oif(source->source_channel_oil,
1204 group->group_igmp_sock->interface,
1205 PIM_OIF_FLAG_PROTO_IGMP);
1206 if (result) {
1207 zlog_warn("%s: del_oif() failed with return=%d",
1208 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001209 return;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001210 }
Everton Marques871dbcf2009-08-11 15:43:05 -03001211
1212 /*
1213 Feed IGMPv3-gathered local membership information into PIM
1214 per-interface (S,G) state.
1215 */
1216 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1217 source->source_addr, group->group_addr);
1218
1219 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1220}
1221
1222void pim_forward_start(struct pim_ifchannel *ch)
1223{
1224 struct pim_upstream *up = ch->upstream;
1225
1226 if (PIM_DEBUG_PIM_TRACE) {
1227 char source_str[100];
1228 char group_str[100];
1229 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1230 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1231 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1232 __PRETTY_FUNCTION__,
1233 source_str, group_str, ch->interface->name);
1234 }
1235
1236 if (!up->channel_oil) {
1237 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1238 if (input_iface_vif_index < 1) {
1239 char source_str[100];
1240 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1241 zlog_warn("%s %s: could not find input interface for source %s",
1242 __FILE__, __PRETTY_FUNCTION__,
1243 source_str);
1244 return;
1245 }
1246
1247 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1248 input_iface_vif_index);
1249 if (!up->channel_oil) {
1250 char group_str[100];
1251 char source_str[100];
1252 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1253 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1254 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1255 __FILE__, __PRETTY_FUNCTION__,
1256 source_str, group_str);
1257 return;
1258 }
1259 }
1260
1261 add_oif(up->channel_oil,
1262 ch->interface,
1263 PIM_OIF_FLAG_PROTO_PIM);
1264}
1265
1266void pim_forward_stop(struct pim_ifchannel *ch)
1267{
1268 struct pim_upstream *up = ch->upstream;
1269
1270 if (PIM_DEBUG_PIM_TRACE) {
1271 char source_str[100];
1272 char group_str[100];
1273 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1274 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1275 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1276 __PRETTY_FUNCTION__,
1277 source_str, group_str, ch->interface->name);
1278 }
1279
1280 if (!up->channel_oil) {
1281 char source_str[100];
1282 char group_str[100];
1283 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1284 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1285 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1286 __PRETTY_FUNCTION__,
1287 source_str, group_str, ch->interface->name);
1288
1289 return;
1290 }
1291
1292 del_oif(up->channel_oil,
1293 ch->interface,
1294 PIM_OIF_FLAG_PROTO_PIM);
1295}