blob: efff100090bfbd62775f13407f562860d7fab2e9 [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
Christian Frankeddc160c2016-10-01 20:42:34 +0200585 if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
586 api.tag = stream_getl (s);
587 else
588 api.tag = 0;
589
Everton Marques871dbcf2009-08-11 15:43:05 -0300590 switch (command) {
591 case ZEBRA_IPV4_ROUTE_ADD:
592 if (PIM_DEBUG_ZEBRA) {
593 char buf[2][INET_ADDRSTRLEN];
594 zlog_debug("%s: add %s %s/%d "
Paul Jakma9099f9b2016-01-18 10:12:10 +0000595 "nexthop %s ifindex %d metric%s %u distance%s %u",
Everton Marques871dbcf2009-08-11 15:43:05 -0300596 __PRETTY_FUNCTION__,
597 zebra_route_string(api.type),
598 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
599 p.prefixlen,
600 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
601 ifindex,
602 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
603 api.metric,
604 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
605 api.distance);
606 }
607 break;
608 case ZEBRA_IPV4_ROUTE_DELETE:
609 if (PIM_DEBUG_ZEBRA) {
610 char buf[2][INET_ADDRSTRLEN];
611 zlog_debug("%s: delete %s %s/%d "
Paul Jakma9099f9b2016-01-18 10:12:10 +0000612 "nexthop %s ifindex %d metric%s %u distance%s %u",
Everton Marques871dbcf2009-08-11 15:43:05 -0300613 __PRETTY_FUNCTION__,
614 zebra_route_string(api.type),
615 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
616 p.prefixlen,
617 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
618 ifindex,
619 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
620 api.metric,
621 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
622 api.distance);
623 }
624 break;
625 default:
626 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
627 return -1;
628 }
629
630 sched_rpf_cache_refresh();
631
632 return 0;
633}
634
Feng Luc99f3482014-10-16 09:52:36 +0800635static void pim_zebra_connected(struct zclient *zclient)
636{
637 zclient_send_requests(zclient, VRF_DEFAULT);
638}
639
Donald Sharp71252932015-09-24 09:25:19 -0400640void pim_zebra_init (struct thread_master *master, char *zebra_sock_path)
Everton Marques871dbcf2009-08-11 15:43:05 -0300641{
Everton Marques871dbcf2009-08-11 15:43:05 -0300642 int i;
643
Everton Marques1f298942014-08-21 15:47:28 -0300644 if (zebra_sock_path)
645 zclient_serv_path_set(zebra_sock_path);
646
Everton Marques871dbcf2009-08-11 15:43:05 -0300647#ifdef HAVE_TCP_ZEBRA
648 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
649#else
Everton Marques1f298942014-08-21 15:47:28 -0300650 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
Everton Marques871dbcf2009-08-11 15:43:05 -0300651#endif
652
653 /* Socket for receiving updates from Zebra daemon */
Donald Sharp71252932015-09-24 09:25:19 -0400654 qpim_zclient_update = zclient_new (master);
Everton Marques871dbcf2009-08-11 15:43:05 -0300655
Feng Luc99f3482014-10-16 09:52:36 +0800656 qpim_zclient_update->zebra_connected = pim_zebra_connected;
Everton Marques3456a802014-07-22 14:52:57 -0300657 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
658 qpim_zclient_update->interface_add = pim_zebra_if_add;
659 qpim_zclient_update->interface_delete = pim_zebra_if_del;
660 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
661 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
662 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
663 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
664 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
665 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
Everton Marques871dbcf2009-08-11 15:43:05 -0300666
David Lampartera2805de2015-02-04 06:33:26 +0100667 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300668 if (PIM_DEBUG_PIM_TRACE) {
669 zlog_info("zclient_init cleared redistribution request");
670 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300671
Everton Marques3456a802014-07-22 14:52:57 -0300672 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300673
674 /* Request all redistribution */
675 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300676 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300677 continue;
Feng Luc99f3482014-10-16 09:52:36 +0800678 vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300679 if (PIM_DEBUG_PIM_TRACE) {
680 zlog_debug("%s: requesting redistribution for %s (%i)",
681 __PRETTY_FUNCTION__, zebra_route_string(i), i);
682 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300683 }
684
685 /* Request default information */
Feng Luc99f3482014-10-16 09:52:36 +0800686 vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300687 if (PIM_DEBUG_PIM_TRACE) {
688 zlog_info("%s: requesting default information redistribution",
Everton Marques871dbcf2009-08-11 15:43:05 -0300689 __PRETTY_FUNCTION__);
690
Everton Marquesc1b228c2014-08-27 15:27:26 -0300691 zlog_notice("%s: zclient update socket initialized",
692 __PRETTY_FUNCTION__);
693 }
694
Everton Marques871dbcf2009-08-11 15:43:05 -0300695 zassert(!qpim_zclient_lookup);
696 qpim_zclient_lookup = zclient_lookup_new();
697 zassert(qpim_zclient_lookup);
698}
699
700void igmp_anysource_forward_start(struct igmp_group *group)
701{
702 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
703 zassert(group->group_filtermode_isexcl);
704 zassert(listcount(group->group_source_list) < 1);
705
706 if (PIM_DEBUG_IGMP_TRACE) {
707 zlog_debug("%s %s: UNIMPLEMENTED",
708 __FILE__, __PRETTY_FUNCTION__);
709 }
710}
711
712void igmp_anysource_forward_stop(struct igmp_group *group)
713{
714 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
715 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
716
717 if (PIM_DEBUG_IGMP_TRACE) {
718 zlog_debug("%s %s: UNIMPLEMENTED",
719 __FILE__, __PRETTY_FUNCTION__);
720 }
721}
722
723static int fib_lookup_if_vif_index(struct in_addr addr)
724{
725 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
726 int num_ifindex;
727 int vif_index;
Paul Jakma9099f9b2016-01-18 10:12:10 +0000728 ifindex_t first_ifindex;
Everton Marques871dbcf2009-08-11 15:43:05 -0300729
730 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
731 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
732 PIM_NEXTHOP_LOOKUP_MAX);
733 if (num_ifindex < 1) {
734 char addr_str[100];
735 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
736 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
737 __FILE__, __PRETTY_FUNCTION__,
738 addr_str);
739 return -1;
740 }
741
742 first_ifindex = nexthop_tab[0].ifindex;
743
744 if (num_ifindex > 1) {
745 char addr_str[100];
746 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
Donald Sharpf3734dd2015-09-30 10:22:46 -0400747 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 -0300748 __FILE__, __PRETTY_FUNCTION__,
749 num_ifindex, addr_str, first_ifindex);
750 /* debug warning only, do not return */
751 }
752
753 if (PIM_DEBUG_ZEBRA) {
754 char addr_str[100];
755 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
756 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
757 __FILE__, __PRETTY_FUNCTION__,
758 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
759 }
760
761 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
762
763 if (vif_index < 1) {
764 char addr_str[100];
765 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
766 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
767 __FILE__, __PRETTY_FUNCTION__,
768 vif_index, addr_str);
769 return -2;
770 }
771
772 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
773
774 if (vif_index > qpim_mroute_oif_highest_vif_index) {
775 char addr_str[100];
776 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
777 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
778 __FILE__, __PRETTY_FUNCTION__,
779 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
780
781 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
782 __FILE__, __PRETTY_FUNCTION__,
783 ifindex2ifname(vif_index),
784 vif_index);
785
786 return -3;
787 }
788
789 return vif_index;
790}
791
792static int add_oif(struct channel_oil *channel_oil,
793 struct interface *oif,
794 uint32_t proto_mask)
795{
796 struct pim_interface *pim_ifp;
797 int old_ttl;
798
799 zassert(channel_oil);
800
801 pim_ifp = oif->info;
802
Everton Marques67faabc2010-02-23 12:11:11 -0300803 if (PIM_DEBUG_MROUTE) {
804 char group_str[100];
805 char source_str[100];
806 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
807 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
808 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
809 __FILE__, __PRETTY_FUNCTION__,
810 source_str, group_str,
811 proto_mask, oif->name, pim_ifp->mroute_vif_index);
812 }
813
Everton Marques871dbcf2009-08-11 15:43:05 -0300814 if (pim_ifp->mroute_vif_index < 1) {
815 zlog_warn("%s %s: interface %s vif_index=%d < 1",
816 __FILE__, __PRETTY_FUNCTION__,
817 oif->name, pim_ifp->mroute_vif_index);
818 return -1;
819 }
820
821#ifdef PIM_ENFORCE_LOOPFREE_MFC
822 /*
823 Prevent creating MFC entry with OIF=IIF.
824
825 This is a protection against implementation mistakes.
826
827 PIM protocol implicitely ensures loopfree multicast topology.
828
829 IGMP must be protected against adding looped MFC entries created
830 by both source and receiver attached to the same interface. See
831 TODO T22.
832 */
833 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
834 char group_str[100];
835 char source_str[100];
836 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
837 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
838 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
839 __FILE__, __PRETTY_FUNCTION__,
840 proto_mask, oif->name, pim_ifp->mroute_vif_index,
841 source_str, group_str);
842 return -2;
843 }
844#endif
845
846 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
847 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
848
849 /* Prevent single protocol from subscribing same interface to
850 channel (S,G) multiple times */
851 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
852 char group_str[100];
853 char source_str[100];
854 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
855 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
856 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
857 __FILE__, __PRETTY_FUNCTION__,
858 proto_mask, oif->name, pim_ifp->mroute_vif_index,
859 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
860 source_str, group_str);
861 return -3;
862 }
863
864 /* Allow other protocol to request subscription of same interface to
865 channel (S,G) multiple times, by silently ignoring further
866 requests */
867 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
868
869 /* Check the OIF really exists before returning, and only log
870 warning otherwise */
871 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
872 char group_str[100];
873 char source_str[100];
874 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
875 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
876 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
877 __FILE__, __PRETTY_FUNCTION__,
878 proto_mask, oif->name, pim_ifp->mroute_vif_index,
879 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
880 source_str, group_str);
881 }
882
883 return 0;
884 }
885
886 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
887
888 if (old_ttl > 0) {
889 char group_str[100];
890 char source_str[100];
891 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
892 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
893 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
894 __FILE__, __PRETTY_FUNCTION__,
895 oif->name, pim_ifp->mroute_vif_index,
896 source_str, group_str);
897 return -4;
898 }
899
900 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
901
902 if (pim_mroute_add(&channel_oil->oil)) {
903 char group_str[100];
904 char source_str[100];
905 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
906 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
907 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
908 __FILE__, __PRETTY_FUNCTION__,
909 oif->name, pim_ifp->mroute_vif_index,
910 source_str, group_str);
911
912 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
913 return -5;
914 }
915
916 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
917 ++channel_oil->oil_size;
918 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
919
Everton Marques67faabc2010-02-23 12:11:11 -0300920 if (PIM_DEBUG_MROUTE) {
921 char group_str[100];
922 char source_str[100];
923 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
924 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
925 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
926 __FILE__, __PRETTY_FUNCTION__,
927 source_str, group_str,
928 proto_mask, oif->name, pim_ifp->mroute_vif_index);
929 }
930
Everton Marques871dbcf2009-08-11 15:43:05 -0300931 return 0;
932}
933
934static int del_oif(struct channel_oil *channel_oil,
935 struct interface *oif,
936 uint32_t proto_mask)
937{
938 struct pim_interface *pim_ifp;
939 int old_ttl;
940
941 zassert(channel_oil);
942
943 pim_ifp = oif->info;
944
945 zassert(pim_ifp->mroute_vif_index >= 1);
946 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
947 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
948
Everton Marques67faabc2010-02-23 12:11:11 -0300949 if (PIM_DEBUG_MROUTE) {
950 char group_str[100];
951 char source_str[100];
952 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
953 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
954 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
955 __FILE__, __PRETTY_FUNCTION__,
956 source_str, group_str,
957 proto_mask, oif->name, pim_ifp->mroute_vif_index);
958 }
959
Everton Marques871dbcf2009-08-11 15:43:05 -0300960 /* Prevent single protocol from unsubscribing same interface from
961 channel (S,G) multiple times */
962 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
963 char group_str[100];
964 char source_str[100];
965 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
966 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
967 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
968 __FILE__, __PRETTY_FUNCTION__,
969 proto_mask, oif->name, pim_ifp->mroute_vif_index,
970 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
971 source_str, group_str);
972 return -2;
973 }
974
975 /* Mark that protocol is no longer interested in this OIF */
976 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
977
978 /* Allow multiple protocols to unsubscribe same interface from
979 channel (S,G) multiple times, by silently ignoring requests while
980 there is at least one protocol interested in the channel */
981 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
982
983 /* Check the OIF keeps existing before returning, and only log
984 warning otherwise */
985 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
986 char group_str[100];
987 char source_str[100];
988 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
989 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
990 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
991 __FILE__, __PRETTY_FUNCTION__,
992 proto_mask, oif->name, pim_ifp->mroute_vif_index,
993 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
994 source_str, group_str);
995 }
996
997 return 0;
998 }
999
1000 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1001
1002 if (old_ttl < 1) {
1003 char group_str[100];
1004 char source_str[100];
1005 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1006 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1007 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1008 __FILE__, __PRETTY_FUNCTION__,
1009 oif->name, pim_ifp->mroute_vif_index,
1010 source_str, group_str);
1011 return -3;
1012 }
1013
1014 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1015
1016 if (pim_mroute_add(&channel_oil->oil)) {
1017 char group_str[100];
1018 char source_str[100];
1019 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1020 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1021 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1022 __FILE__, __PRETTY_FUNCTION__,
1023 oif->name, pim_ifp->mroute_vif_index,
1024 source_str, group_str);
1025
1026 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1027 return -4;
1028 }
1029
1030 --channel_oil->oil_size;
1031
1032 if (channel_oil->oil_size < 1) {
1033 if (pim_mroute_del(&channel_oil->oil)) {
1034 /* just log a warning in case of failure */
1035 char group_str[100];
1036 char source_str[100];
1037 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1038 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1039 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1040 __FILE__, __PRETTY_FUNCTION__,
1041 source_str, group_str);
1042 }
1043 }
1044
Everton Marques67faabc2010-02-23 12:11:11 -03001045 if (PIM_DEBUG_MROUTE) {
1046 char group_str[100];
1047 char source_str[100];
1048 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1049 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1050 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1051 __FILE__, __PRETTY_FUNCTION__,
1052 source_str, group_str,
1053 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1054 }
1055
Everton Marques871dbcf2009-08-11 15:43:05 -03001056 return 0;
1057}
1058
1059void igmp_source_forward_start(struct igmp_source *source)
1060{
1061 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001062 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001063
1064 if (PIM_DEBUG_IGMP_TRACE) {
1065 char source_str[100];
1066 char group_str[100];
1067 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1068 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1069 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1070 __PRETTY_FUNCTION__,
1071 source_str, group_str,
1072 source->source_group->group_igmp_sock->fd,
1073 source->source_group->group_igmp_sock->interface->name,
1074 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1075 }
1076
1077 /* Prevent IGMP interface from installing multicast route multiple
1078 times */
1079 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1080 return;
1081 }
1082
1083 group = source->source_group;
1084
1085 if (!source->source_channel_oil) {
1086 struct pim_interface *pim_oif;
1087 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1088 if (input_iface_vif_index < 1) {
1089 char source_str[100];
1090 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1091 zlog_warn("%s %s: could not find input interface for source %s",
1092 __FILE__, __PRETTY_FUNCTION__,
1093 source_str);
1094 return;
1095 }
1096
1097 /*
1098 Protect IGMP against adding looped MFC entries created by both
1099 source and receiver attached to the same interface. See TODO
1100 T22.
1101 */
1102 pim_oif = source->source_group->group_igmp_sock->interface->info;
1103 if (!pim_oif) {
1104 zlog_warn("%s: multicast not enabled on oif=%s ?",
1105 __PRETTY_FUNCTION__,
1106 source->source_group->group_igmp_sock->interface->name);
1107 return;
1108 }
1109 if (pim_oif->mroute_vif_index < 1) {
1110 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1111 __FILE__, __PRETTY_FUNCTION__,
1112 source->source_group->group_igmp_sock->interface->name,
1113 pim_oif->mroute_vif_index);
1114 return;
1115 }
1116 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1117 /* ignore request for looped MFC entry */
1118 if (PIM_DEBUG_IGMP_TRACE) {
1119 char source_str[100];
1120 char group_str[100];
1121 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1122 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1123 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1124 __PRETTY_FUNCTION__,
1125 source_str, group_str,
1126 source->source_group->group_igmp_sock->fd,
1127 source->source_group->group_igmp_sock->interface->name,
1128 input_iface_vif_index);
1129 }
1130 return;
1131 }
1132
1133 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1134 source->source_addr,
1135 input_iface_vif_index);
1136 if (!source->source_channel_oil) {
1137 char group_str[100];
1138 char source_str[100];
1139 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1140 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1141 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1142 __FILE__, __PRETTY_FUNCTION__,
1143 source_str, group_str);
1144 return;
1145 }
1146 }
1147
Everton Marques24e3a9b2014-09-30 19:14:19 -03001148 result = add_oif(source->source_channel_oil,
1149 group->group_igmp_sock->interface,
1150 PIM_OIF_FLAG_PROTO_IGMP);
1151 if (result) {
1152 zlog_warn("%s: add_oif() failed with return=%d",
1153 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001154 return;
1155 }
1156
1157 /*
1158 Feed IGMPv3-gathered local membership information into PIM
1159 per-interface (S,G) state.
1160 */
1161 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1162 source->source_addr, group->group_addr);
1163
1164 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1165}
1166
Everton Marques24e3a9b2014-09-30 19:14:19 -03001167/*
1168 igmp_source_forward_stop: stop fowarding, but keep the source
1169 igmp_source_delete: stop fowarding, and delete the source
1170 */
Everton Marques871dbcf2009-08-11 15:43:05 -03001171void igmp_source_forward_stop(struct igmp_source *source)
1172{
1173 struct igmp_group *group;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001174 int result;
Everton Marques871dbcf2009-08-11 15:43:05 -03001175
1176 if (PIM_DEBUG_IGMP_TRACE) {
1177 char source_str[100];
1178 char group_str[100];
1179 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1180 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1181 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1182 __PRETTY_FUNCTION__,
1183 source_str, group_str,
1184 source->source_group->group_igmp_sock->fd,
1185 source->source_group->group_igmp_sock->interface->name,
1186 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1187 }
1188
1189 /* Prevent IGMP interface from removing multicast route multiple
1190 times */
1191 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1192 return;
1193 }
1194
1195 group = source->source_group;
1196
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001197 /*
1198 It appears that in certain circumstances that
1199 igmp_source_forward_stop is called when IGMP forwarding
1200 was not enabled in oif_flags for this outgoing interface.
1201 Possibly because of multiple calls. When that happens, we
1202 enter the below if statement and this function returns early
1203 which in turn triggers the calling function to assert.
1204 Making the call to del_oif and ignoring the return code
1205 fixes the issue without ill effect, similar to
1206 pim_forward_stop below.
1207 */
Everton Marques24e3a9b2014-09-30 19:14:19 -03001208 result = del_oif(source->source_channel_oil,
1209 group->group_igmp_sock->interface,
1210 PIM_OIF_FLAG_PROTO_IGMP);
1211 if (result) {
1212 zlog_warn("%s: del_oif() failed with return=%d",
1213 __func__, result);
Everton Marques871dbcf2009-08-11 15:43:05 -03001214 return;
Everton Marques24e3a9b2014-09-30 19:14:19 -03001215 }
Everton Marques871dbcf2009-08-11 15:43:05 -03001216
1217 /*
1218 Feed IGMPv3-gathered local membership information into PIM
1219 per-interface (S,G) state.
1220 */
1221 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1222 source->source_addr, group->group_addr);
1223
1224 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1225}
1226
1227void pim_forward_start(struct pim_ifchannel *ch)
1228{
1229 struct pim_upstream *up = ch->upstream;
1230
1231 if (PIM_DEBUG_PIM_TRACE) {
1232 char source_str[100];
1233 char group_str[100];
1234 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1235 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1236 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1237 __PRETTY_FUNCTION__,
1238 source_str, group_str, ch->interface->name);
1239 }
1240
1241 if (!up->channel_oil) {
1242 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1243 if (input_iface_vif_index < 1) {
1244 char source_str[100];
1245 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1246 zlog_warn("%s %s: could not find input interface for source %s",
1247 __FILE__, __PRETTY_FUNCTION__,
1248 source_str);
1249 return;
1250 }
1251
1252 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1253 input_iface_vif_index);
1254 if (!up->channel_oil) {
1255 char group_str[100];
1256 char source_str[100];
1257 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1258 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1259 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1260 __FILE__, __PRETTY_FUNCTION__,
1261 source_str, group_str);
1262 return;
1263 }
1264 }
1265
1266 add_oif(up->channel_oil,
1267 ch->interface,
1268 PIM_OIF_FLAG_PROTO_PIM);
1269}
1270
1271void pim_forward_stop(struct pim_ifchannel *ch)
1272{
1273 struct pim_upstream *up = ch->upstream;
1274
1275 if (PIM_DEBUG_PIM_TRACE) {
1276 char source_str[100];
1277 char group_str[100];
1278 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1279 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1280 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1281 __PRETTY_FUNCTION__,
1282 source_str, group_str, ch->interface->name);
1283 }
1284
1285 if (!up->channel_oil) {
1286 char source_str[100];
1287 char group_str[100];
1288 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1289 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1290 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1291 __PRETTY_FUNCTION__,
1292 source_str, group_str, ch->interface->name);
1293
1294 return;
1295 }
1296
1297 del_oif(up->channel_oil,
1298 ch->interface,
1299 PIM_OIF_FLAG_PROTO_PIM);
1300}