blob: ff62bec86d1c2971fede755cced3860d9a09320b [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
20 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "zebra/rib.h"
26
Everton Marques075ac8d2014-09-24 15:18:37 -030027#include "if.h"
Everton Marques871dbcf2009-08-11 15:43:05 -030028#include "log.h"
29#include "prefix.h"
30#include "zclient.h"
31#include "stream.h"
32#include "network.h"
33
34#include "pimd.h"
35#include "pim_pim.h"
36#include "pim_zebra.h"
37#include "pim_iface.h"
38#include "pim_str.h"
39#include "pim_oil.h"
40#include "pim_rpf.h"
41#include "pim_time.h"
42#include "pim_join.h"
43#include "pim_zlookup.h"
44#include "pim_ifchannel.h"
45
46#undef PIM_DEBUG_IFADDR_DUMP
47#define PIM_DEBUG_IFADDR_DUMP
48
49static int fib_lookup_if_vif_index(struct in_addr addr);
50static int del_oif(struct channel_oil *channel_oil,
51 struct interface *oif,
52 uint32_t proto_mask);
53
Everton Marques2a0ecf22014-09-22 18:18:26 -030054static void zclient_broken(struct zclient *zclient)
55{
Everton Marques075ac8d2014-09-24 15:18:37 -030056 struct listnode *ifnode;
57 struct interface *ifp;
58
Everton Marques2a0ecf22014-09-22 18:18:26 -030059 zlog_warn("%s %s: broken zclient connection",
Everton Marques075ac8d2014-09-24 15:18:37 -030060 __FILE__, __PRETTY_FUNCTION__);
61
62 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
Everton Marques2a0ecf22014-09-22 18:18:26 -030063 pim_if_addr_del_all(ifp);
Everton Marques075ac8d2014-09-24 15:18:37 -030064 }
Everton Marques2a0ecf22014-09-22 18:18:26 -030065
Everton Marques96b6dfe2014-09-22 15:47:52 -030066 /* discard connected addresses because zclient lib will reassign
67 them upon reconnection */
68 if_connected_reset_all();
Everton Marques075ac8d2014-09-24 15:18:37 -030069}
70
Everton Marques871dbcf2009-08-11 15:43:05 -030071/* Router-id update message from zebra. */
72static int pim_router_id_update_zebra(int command, struct zclient *zclient,
73 zebra_size_t length)
74{
75 struct prefix router_id;
76
Everton Marques871dbcf2009-08-11 15:43:05 -030077 zebra_router_id_update_read(zclient->ibuf, &router_id);
78
79 return 0;
80}
81
82static int pim_zebra_if_add(int command, struct zclient *zclient,
83 zebra_size_t length)
84{
85 struct interface *ifp;
86
87 /*
88 zebra api adds/dels interfaces using the same call
89 interface_add_read below, see comments in lib/zclient.c
90 */
91 ifp = zebra_interface_add_read(zclient->ibuf);
92 if (!ifp)
93 return 0;
94
95 if (PIM_DEBUG_ZEBRA) {
96 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
97 __PRETTY_FUNCTION__,
98 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
99 ifp->mtu, if_is_operative(ifp));
100 }
101
102 if (if_is_operative(ifp))
103 pim_if_addr_add_all(ifp);
104
105 return 0;
106}
107
108static int pim_zebra_if_del(int command, struct zclient *zclient,
109 zebra_size_t length)
110{
111 struct interface *ifp;
112
113 /*
114 zebra api adds/dels interfaces using the same call
115 interface_add_read below, see comments in lib/zclient.c
116 */
117 ifp = zebra_interface_add_read(zclient->ibuf);
118 if (!ifp)
119 return 0;
120
121 if (PIM_DEBUG_ZEBRA) {
122 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
123 __PRETTY_FUNCTION__,
124 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
125 ifp->mtu, if_is_operative(ifp));
126 }
127
128 if (!if_is_operative(ifp))
129 pim_if_addr_del_all(ifp);
130
131 return 0;
132}
133
134static int pim_zebra_if_state_up(int command, struct zclient *zclient,
135 zebra_size_t length)
136{
137 struct interface *ifp;
138
139 /*
140 zebra api notifies interface up/down events by using the same call
141 interface_add_read below, see comments in lib/zclient.c
142 */
143 ifp = zebra_interface_state_read(zclient->ibuf);
144 if (!ifp)
145 return 0;
146
Everton Marquese96f0af2009-08-11 15:48:02 -0300147 zlog_info("INTERFACE UP: %s", ifp->name);
148
Everton Marques871dbcf2009-08-11 15:43:05 -0300149 if (PIM_DEBUG_ZEBRA) {
150 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
151 __PRETTY_FUNCTION__,
152 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
153 ifp->mtu, if_is_operative(ifp));
154 }
155
156 if (if_is_operative(ifp)) {
157 /*
158 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
159 */
160 pim_if_addr_add_all(ifp);
161 }
162
163 return 0;
164}
165
166static int pim_zebra_if_state_down(int command, struct zclient *zclient,
167 zebra_size_t length)
168{
169 struct interface *ifp;
170
171 /*
172 zebra api notifies interface up/down events by using the same call
173 interface_add_read below, see comments in lib/zclient.c
174 */
175 ifp = zebra_interface_state_read(zclient->ibuf);
176 if (!ifp)
177 return 0;
178
Everton Marquese96f0af2009-08-11 15:48:02 -0300179 zlog_info("INTERFACE DOWN: %s", ifp->name);
180
Everton Marques871dbcf2009-08-11 15:43:05 -0300181 if (PIM_DEBUG_ZEBRA) {
182 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
183 __PRETTY_FUNCTION__,
184 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
185 ifp->mtu, if_is_operative(ifp));
186 }
187
188 if (!if_is_operative(ifp)) {
189 /*
190 pim_if_addr_del_all() suffices for shutting down IGMP,
191 but not for shutting down PIM
192 */
193 pim_if_addr_del_all(ifp);
194
195 /*
196 pim_sock_delete() closes the socket, stops read and timer threads,
197 and kills all neighbors.
198 */
Everton Marquese96f0af2009-08-11 15:48:02 -0300199 if (ifp->info) {
200 pim_sock_delete(ifp, "link down");
201 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300202 }
203
204 return 0;
205}
206
207#ifdef PIM_DEBUG_IFADDR_DUMP
208static void dump_if_address(struct interface *ifp)
209{
210 struct connected *ifc;
211 struct listnode *node;
212
213 zlog_debug("%s %s: interface %s addresses:",
214 __FILE__, __PRETTY_FUNCTION__,
215 ifp->name);
216
217 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
218 struct prefix *p = ifc->address;
219
220 if (p->family != AF_INET)
221 continue;
222
Everton Marques306c99e2014-07-16 15:51:37 -0300223 zlog_debug("%s %s: interface %s address %s %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300224 __FILE__, __PRETTY_FUNCTION__,
225 ifp->name,
Everton Marques306c99e2014-07-16 15:51:37 -0300226 inet_ntoa(p->u.prefix4),
227 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
228 "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300229 }
230}
231#endif
232
233static int pim_zebra_if_address_add(int command, struct zclient *zclient,
234 zebra_size_t length)
235{
236 struct connected *c;
237 struct prefix *p;
238
239 zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD);
240
241 /*
242 zebra api notifies address adds/dels events by using the same call
243 interface_add_read below, see comments in lib/zclient.c
244
245 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
246 will add address to interface list by calling
247 connected_add_by_prefix()
248 */
249 c = zebra_interface_address_read(command, zclient->ibuf);
250 if (!c)
251 return 0;
252
253 p = c->address;
254 if (p->family != AF_INET)
255 return 0;
256
257 if (PIM_DEBUG_ZEBRA) {
258 char buf[BUFSIZ];
259 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300260 zlog_debug("%s: %s connected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300261 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300262 c->ifp->name, buf, c->flags,
263 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300264
265#ifdef PIM_DEBUG_IFADDR_DUMP
266 dump_if_address(c->ifp);
267#endif
268 }
269
Everton Marques306c99e2014-07-16 15:51:37 -0300270 if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
271 /* trying to add primary address */
272
273 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
274 if (primary_addr.s_addr != p->u.prefix4.s_addr) {
275 /* but we had a primary address already */
276
277 char buf[BUFSIZ];
278 char old[100];
279
280 prefix2str(p, buf, BUFSIZ);
281 pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
282
283 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
284 __PRETTY_FUNCTION__,
285 c->ifp->name, old, buf);
286 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
287 }
288 }
289
Everton Marques871dbcf2009-08-11 15:43:05 -0300290 pim_if_addr_add(c);
291
292 return 0;
293}
294
295static int pim_zebra_if_address_del(int command, struct zclient *client,
296 zebra_size_t length)
297{
298 struct connected *c;
299 struct prefix *p;
300
301 zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE);
302
303 /*
304 zebra api notifies address adds/dels events by using the same call
305 interface_add_read below, see comments in lib/zclient.c
306
307 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
308 will remove address from interface list by calling
309 connected_delete_by_prefix()
310 */
311 c = zebra_interface_address_read(command, client->ibuf);
312 if (!c)
313 return 0;
314
315 p = c->address;
316 if (p->family != AF_INET)
317 return 0;
318
319 if (PIM_DEBUG_ZEBRA) {
320 char buf[BUFSIZ];
321 prefix2str(p, buf, BUFSIZ);
Everton Marques306c99e2014-07-16 15:51:37 -0300322 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300323 __PRETTY_FUNCTION__,
Everton Marques306c99e2014-07-16 15:51:37 -0300324 c->ifp->name, buf, c->flags,
325 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
Everton Marques871dbcf2009-08-11 15:43:05 -0300326
327#ifdef PIM_DEBUG_IFADDR_DUMP
328 dump_if_address(c->ifp);
329#endif
330 }
Everton Marques306c99e2014-07-16 15:51:37 -0300331
Everton Marques2a0ecf22014-09-22 18:18:26 -0300332 pim_if_addr_del(c, 0);
Everton Marques871dbcf2009-08-11 15:43:05 -0300333
334 return 0;
335}
336
337static void scan_upstream_rpf_cache()
338{
339 struct listnode *up_node;
340 struct listnode *up_nextnode;
341 struct pim_upstream *up;
342
343 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
344 struct in_addr old_rpf_addr;
345 enum pim_rpf_result rpf_result;
346
347 rpf_result = pim_rpf_update(up, &old_rpf_addr);
348 if (rpf_result == PIM_RPF_FAILURE)
349 continue;
350
351 if (rpf_result == PIM_RPF_CHANGED) {
352
353 if (up->join_state == PIM_UPSTREAM_JOINED) {
354
355 /*
356 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
357
358 Transitions from Joined State
359
360 RPF'(S,G) changes not due to an Assert
361
362 The upstream (S,G) state machine remains in Joined
363 state. Send Join(S,G) to the new upstream neighbor, which is
364 the new value of RPF'(S,G). Send Prune(S,G) to the old
365 upstream neighbor, which is the old value of RPF'(S,G). Set
366 the Join Timer (JT) to expire after t_periodic seconds.
367 */
368
369
370 /* send Prune(S,G) to the old upstream neighbor */
371 pim_joinprune_send(up->rpf.source_nexthop.interface,
372 old_rpf_addr,
373 up->source_addr,
374 up->group_addr,
375 0 /* prune */);
376
377 /* send Join(S,G) to the current upstream neighbor */
378 pim_joinprune_send(up->rpf.source_nexthop.interface,
379 up->rpf.rpf_addr,
380 up->source_addr,
381 up->group_addr,
382 1 /* join */);
383
384 pim_upstream_join_timer_restart(up);
385 } /* up->join_state == PIM_UPSTREAM_JOINED */
386
387 /* FIXME can join_desired actually be changed by pim_rpf_update()
388 returning PIM_RPF_CHANGED ? */
389 pim_upstream_update_join_desired(up);
390
391 } /* PIM_RPF_CHANGED */
392
393 } /* for (qpim_upstream_list) */
394
395}
396
Everton Marquesf24200d2014-02-14 16:40:34 -0200397void pim_scan_oil()
Everton Marques871dbcf2009-08-11 15:43:05 -0300398{
399 struct listnode *node;
400 struct listnode *nextnode;
401 struct channel_oil *c_oil;
402
Everton Marquesf24200d2014-02-14 16:40:34 -0200403 qpim_scan_oil_last = pim_time_monotonic_sec();
404 ++qpim_scan_oil_events;
405
Everton Marques871dbcf2009-08-11 15:43:05 -0300406 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
407 int old_vif_index;
408 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
409 if (input_iface_vif_index < 1) {
410 char source_str[100];
411 char group_str[100];
412 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
413 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
414 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
415 __FILE__, __PRETTY_FUNCTION__,
416 source_str, group_str);
417 continue;
418 }
419
420 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
421 /* RPF unchanged */
422 continue;
423 }
424
425 if (PIM_DEBUG_ZEBRA) {
426 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
427 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
428 char source_str[100];
429 char group_str[100];
430 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
431 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
432 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
433 __FILE__, __PRETTY_FUNCTION__,
434 source_str, group_str,
435 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
436 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
437 }
438
439 /* new iif loops to existing oif ? */
440 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
441 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
442
443 if (PIM_DEBUG_ZEBRA) {
444 char source_str[100];
445 char group_str[100];
446 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
447 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
448 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
449 __FILE__, __PRETTY_FUNCTION__,
450 source_str, group_str,
451 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
452 }
453
454 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
455 }
456
457 /* update iif vif_index */
458 old_vif_index = c_oil->oil.mfcc_parent;
459 c_oil->oil.mfcc_parent = input_iface_vif_index;
460
461 /* update kernel multicast forwarding cache (MFC) */
462 if (pim_mroute_add(&c_oil->oil)) {
463 /* just log warning */
464 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
465 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
466 char source_str[100];
467 char group_str[100];
468 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
469 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
470 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
471 __FILE__, __PRETTY_FUNCTION__,
472 source_str, group_str,
473 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
474 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
475 continue;
476 }
477
478 } /* for (qpim_channel_oil_list) */
479}
480
481static int on_rpf_cache_refresh(struct thread *t)
482{
483 zassert(t);
484 zassert(qpim_rpf_cache_refresher);
485
486 qpim_rpf_cache_refresher = 0;
487
488 /* update PIM protocol state */
489 scan_upstream_rpf_cache();
490
491 /* update kernel multicast forwarding cache (MFC) */
Everton Marquesf24200d2014-02-14 16:40:34 -0200492 pim_scan_oil();
Everton Marques871dbcf2009-08-11 15:43:05 -0300493
Everton Marquesbcc4abe2009-08-17 18:18:59 -0300494 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
Everton Marques613938d2009-08-13 15:39:31 -0300495 ++qpim_rpf_cache_refresh_events;
496
Everton Marques871dbcf2009-08-11 15:43:05 -0300497 return 0;
498}
499
500static void sched_rpf_cache_refresh()
501{
Everton Marques613938d2009-08-13 15:39:31 -0300502 ++qpim_rpf_cache_refresh_requests;
503
504 if (qpim_rpf_cache_refresher) {
505 /* Refresh timer is already running */
Everton Marques871dbcf2009-08-11 15:43:05 -0300506 return;
Everton Marques613938d2009-08-13 15:39:31 -0300507 }
508
509 /* Start refresh timer */
Everton Marques871dbcf2009-08-11 15:43:05 -0300510
511 if (PIM_DEBUG_ZEBRA) {
512 zlog_debug("%s: triggering %ld msec timer",
513 __PRETTY_FUNCTION__,
514 qpim_rpf_cache_refresh_delay_msec);
515 }
516
517 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
518 on_rpf_cache_refresh,
519 0, qpim_rpf_cache_refresh_delay_msec);
520}
521
522static int redist_read_ipv4_route(int command, struct zclient *zclient,
523 zebra_size_t length)
524{
525 struct stream *s;
526 struct zapi_ipv4 api;
527 unsigned long ifindex;
528 struct in_addr nexthop;
529 struct prefix_ipv4 p;
530 int min_len = 4;
531
532 if (length < min_len) {
533 zlog_warn("%s %s: short buffer: length=%d min=%d",
534 __FILE__, __PRETTY_FUNCTION__,
535 length, min_len);
536 return -1;
537 }
538
539 s = zclient->ibuf;
540 ifindex = 0;
541 nexthop.s_addr = 0;
542
543 /* Type, flags, message. */
544 api.type = stream_getc(s);
545 api.flags = stream_getc(s);
546 api.message = stream_getc(s);
547
548 /* IPv4 prefix length. */
549 memset(&p, 0, sizeof(struct prefix_ipv4));
550 p.family = AF_INET;
551 p.prefixlen = stream_getc(s);
552
553 min_len +=
554 PSIZE(p.prefixlen) +
555 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
556 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
557 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
558 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
559
560 if (PIM_DEBUG_ZEBRA) {
561 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
562 __FILE__, __PRETTY_FUNCTION__,
563 length, min_len,
564 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
565 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
566 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
567 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
568 }
569
570 if (length < min_len) {
571 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
572 __FILE__, __PRETTY_FUNCTION__,
573 length, min_len,
574 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
575 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
576 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
577 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
578 return -1;
579 }
580
581 /* IPv4 prefix. */
582 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
583
584 /* Nexthop, ifindex, distance, metric. */
585 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
586 api.nexthop_num = stream_getc(s);
587 nexthop.s_addr = stream_get_ipv4(s);
588 }
589 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
590 api.ifindex_num = stream_getc(s);
591 ifindex = stream_getl(s);
592 }
593
594 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
David Lamparter105ad862012-02-16 04:50:35 +0000595 stream_getc(s) :
Everton Marques871dbcf2009-08-11 15:43:05 -0300596 0;
597
598 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
599 stream_getl(s) :
600 0;
601
602 switch (command) {
603 case ZEBRA_IPV4_ROUTE_ADD:
604 if (PIM_DEBUG_ZEBRA) {
605 char buf[2][INET_ADDRSTRLEN];
606 zlog_debug("%s: add %s %s/%d "
607 "nexthop %s ifindex %ld metric%s %u distance%s %u",
608 __PRETTY_FUNCTION__,
609 zebra_route_string(api.type),
610 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
611 p.prefixlen,
612 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
613 ifindex,
614 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
615 api.metric,
616 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
617 api.distance);
618 }
619 break;
620 case ZEBRA_IPV4_ROUTE_DELETE:
621 if (PIM_DEBUG_ZEBRA) {
622 char buf[2][INET_ADDRSTRLEN];
623 zlog_debug("%s: delete %s %s/%d "
624 "nexthop %s ifindex %ld metric%s %u distance%s %u",
625 __PRETTY_FUNCTION__,
626 zebra_route_string(api.type),
627 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
628 p.prefixlen,
629 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
630 ifindex,
631 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
632 api.metric,
633 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
634 api.distance);
635 }
636 break;
637 default:
638 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
639 return -1;
640 }
641
642 sched_rpf_cache_refresh();
643
644 return 0;
645}
646
Everton Marques1f298942014-08-21 15:47:28 -0300647void pim_zebra_init(char *zebra_sock_path)
Everton Marques871dbcf2009-08-11 15:43:05 -0300648{
Everton Marques871dbcf2009-08-11 15:43:05 -0300649 int i;
650
Everton Marques1f298942014-08-21 15:47:28 -0300651 if (zebra_sock_path)
652 zclient_serv_path_set(zebra_sock_path);
653
Everton Marques871dbcf2009-08-11 15:43:05 -0300654#ifdef HAVE_TCP_ZEBRA
655 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
656#else
Everton Marques1f298942014-08-21 15:47:28 -0300657 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
Everton Marques871dbcf2009-08-11 15:43:05 -0300658#endif
659
660 /* Socket for receiving updates from Zebra daemon */
Everton Marques3456a802014-07-22 14:52:57 -0300661 qpim_zclient_update = zclient_new();
Everton Marques871dbcf2009-08-11 15:43:05 -0300662
Everton Marques3456a802014-07-22 14:52:57 -0300663 qpim_zclient_update->zclient_broken = zclient_broken;
664 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
665 qpim_zclient_update->interface_add = pim_zebra_if_add;
666 qpim_zclient_update->interface_delete = pim_zebra_if_del;
667 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
668 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
669 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
670 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
671 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
672 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
Everton Marques871dbcf2009-08-11 15:43:05 -0300673
Everton Marques3456a802014-07-22 14:52:57 -0300674 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
Everton Marquesc1b228c2014-08-27 15:27:26 -0300675 if (PIM_DEBUG_PIM_TRACE) {
676 zlog_info("zclient_init cleared redistribution request");
677 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300678
Everton Marques3456a802014-07-22 14:52:57 -0300679 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300680
681 /* Request all redistribution */
682 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300683 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300684 continue;
Everton Marques3456a802014-07-22 14:52:57 -0300685 qpim_zclient_update->redist[i] = 1;
Everton Marquesc1b228c2014-08-27 15:27:26 -0300686 if (PIM_DEBUG_PIM_TRACE) {
687 zlog_debug("%s: requesting redistribution for %s (%i)",
688 __PRETTY_FUNCTION__, zebra_route_string(i), i);
689 }
Everton Marques871dbcf2009-08-11 15:43:05 -0300690 }
691
692 /* Request default information */
Everton Marques3456a802014-07-22 14:52:57 -0300693 qpim_zclient_update->default_information = 1;
Everton Marquesc1b228c2014-08-27 15:27:26 -0300694 if (PIM_DEBUG_PIM_TRACE) {
695 zlog_info("%s: requesting default information redistribution",
Everton Marques871dbcf2009-08-11 15:43:05 -0300696 __PRETTY_FUNCTION__);
697
Everton Marquesc1b228c2014-08-27 15:27:26 -0300698 zlog_notice("%s: zclient update socket initialized",
699 __PRETTY_FUNCTION__);
700 }
701
Everton Marques871dbcf2009-08-11 15:43:05 -0300702 zassert(!qpim_zclient_lookup);
703 qpim_zclient_lookup = zclient_lookup_new();
704 zassert(qpim_zclient_lookup);
705}
706
707void igmp_anysource_forward_start(struct igmp_group *group)
708{
709 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
710 zassert(group->group_filtermode_isexcl);
711 zassert(listcount(group->group_source_list) < 1);
712
713 if (PIM_DEBUG_IGMP_TRACE) {
714 zlog_debug("%s %s: UNIMPLEMENTED",
715 __FILE__, __PRETTY_FUNCTION__);
716 }
717}
718
719void igmp_anysource_forward_stop(struct igmp_group *group)
720{
721 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
722 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
723
724 if (PIM_DEBUG_IGMP_TRACE) {
725 zlog_debug("%s %s: UNIMPLEMENTED",
726 __FILE__, __PRETTY_FUNCTION__);
727 }
728}
729
730static int fib_lookup_if_vif_index(struct in_addr addr)
731{
732 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
733 int num_ifindex;
734 int vif_index;
735 int first_ifindex;
736
737 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
738 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
739 PIM_NEXTHOP_LOOKUP_MAX);
740 if (num_ifindex < 1) {
741 char addr_str[100];
742 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
743 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
744 __FILE__, __PRETTY_FUNCTION__,
745 addr_str);
746 return -1;
747 }
748
749 first_ifindex = nexthop_tab[0].ifindex;
750
751 if (num_ifindex > 1) {
752 char addr_str[100];
753 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
754 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
755 __FILE__, __PRETTY_FUNCTION__,
756 num_ifindex, addr_str, first_ifindex);
757 /* debug warning only, do not return */
758 }
759
760 if (PIM_DEBUG_ZEBRA) {
761 char addr_str[100];
762 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
763 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
764 __FILE__, __PRETTY_FUNCTION__,
765 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
766 }
767
768 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
769
770 if (vif_index < 1) {
771 char addr_str[100];
772 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
773 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
774 __FILE__, __PRETTY_FUNCTION__,
775 vif_index, addr_str);
776 return -2;
777 }
778
779 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
780
781 if (vif_index > qpim_mroute_oif_highest_vif_index) {
782 char addr_str[100];
783 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
784 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
785 __FILE__, __PRETTY_FUNCTION__,
786 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
787
788 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
789 __FILE__, __PRETTY_FUNCTION__,
790 ifindex2ifname(vif_index),
791 vif_index);
792
793 return -3;
794 }
795
796 return vif_index;
797}
798
799static int add_oif(struct channel_oil *channel_oil,
800 struct interface *oif,
801 uint32_t proto_mask)
802{
803 struct pim_interface *pim_ifp;
804 int old_ttl;
805
806 zassert(channel_oil);
807
808 pim_ifp = oif->info;
809
Everton Marques67faabc2010-02-23 12:11:11 -0300810 if (PIM_DEBUG_MROUTE) {
811 char group_str[100];
812 char source_str[100];
813 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
814 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
815 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
816 __FILE__, __PRETTY_FUNCTION__,
817 source_str, group_str,
818 proto_mask, oif->name, pim_ifp->mroute_vif_index);
819 }
820
Everton Marques871dbcf2009-08-11 15:43:05 -0300821 if (pim_ifp->mroute_vif_index < 1) {
822 zlog_warn("%s %s: interface %s vif_index=%d < 1",
823 __FILE__, __PRETTY_FUNCTION__,
824 oif->name, pim_ifp->mroute_vif_index);
825 return -1;
826 }
827
828#ifdef PIM_ENFORCE_LOOPFREE_MFC
829 /*
830 Prevent creating MFC entry with OIF=IIF.
831
832 This is a protection against implementation mistakes.
833
834 PIM protocol implicitely ensures loopfree multicast topology.
835
836 IGMP must be protected against adding looped MFC entries created
837 by both source and receiver attached to the same interface. See
838 TODO T22.
839 */
840 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
841 char group_str[100];
842 char source_str[100];
843 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
844 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
845 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
846 __FILE__, __PRETTY_FUNCTION__,
847 proto_mask, oif->name, pim_ifp->mroute_vif_index,
848 source_str, group_str);
849 return -2;
850 }
851#endif
852
853 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
854 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
855
856 /* Prevent single protocol from subscribing same interface to
857 channel (S,G) multiple times */
858 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
859 char group_str[100];
860 char source_str[100];
861 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
862 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
863 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
864 __FILE__, __PRETTY_FUNCTION__,
865 proto_mask, oif->name, pim_ifp->mroute_vif_index,
866 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
867 source_str, group_str);
868 return -3;
869 }
870
871 /* Allow other protocol to request subscription of same interface to
872 channel (S,G) multiple times, by silently ignoring further
873 requests */
874 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
875
876 /* Check the OIF really exists before returning, and only log
877 warning otherwise */
878 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
879 char group_str[100];
880 char source_str[100];
881 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
882 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
883 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
884 __FILE__, __PRETTY_FUNCTION__,
885 proto_mask, oif->name, pim_ifp->mroute_vif_index,
886 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
887 source_str, group_str);
888 }
889
890 return 0;
891 }
892
893 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
894
895 if (old_ttl > 0) {
896 char group_str[100];
897 char source_str[100];
898 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
899 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
900 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
901 __FILE__, __PRETTY_FUNCTION__,
902 oif->name, pim_ifp->mroute_vif_index,
903 source_str, group_str);
904 return -4;
905 }
906
907 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
908
909 if (pim_mroute_add(&channel_oil->oil)) {
910 char group_str[100];
911 char source_str[100];
912 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
913 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
914 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
915 __FILE__, __PRETTY_FUNCTION__,
916 oif->name, pim_ifp->mroute_vif_index,
917 source_str, group_str);
918
919 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
920 return -5;
921 }
922
923 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
924 ++channel_oil->oil_size;
925 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
926
Everton Marques67faabc2010-02-23 12:11:11 -0300927 if (PIM_DEBUG_MROUTE) {
928 char group_str[100];
929 char source_str[100];
930 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
931 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
932 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
933 __FILE__, __PRETTY_FUNCTION__,
934 source_str, group_str,
935 proto_mask, oif->name, pim_ifp->mroute_vif_index);
936 }
937
Everton Marques871dbcf2009-08-11 15:43:05 -0300938 return 0;
939}
940
941static int del_oif(struct channel_oil *channel_oil,
942 struct interface *oif,
943 uint32_t proto_mask)
944{
945 struct pim_interface *pim_ifp;
946 int old_ttl;
947
948 zassert(channel_oil);
949
950 pim_ifp = oif->info;
951
952 zassert(pim_ifp->mroute_vif_index >= 1);
953 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
954 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
955
Everton Marques67faabc2010-02-23 12:11:11 -0300956 if (PIM_DEBUG_MROUTE) {
957 char group_str[100];
958 char source_str[100];
959 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
960 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
961 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
962 __FILE__, __PRETTY_FUNCTION__,
963 source_str, group_str,
964 proto_mask, oif->name, pim_ifp->mroute_vif_index);
965 }
966
Everton Marques871dbcf2009-08-11 15:43:05 -0300967 /* Prevent single protocol from unsubscribing same interface from
968 channel (S,G) multiple times */
969 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
970 char group_str[100];
971 char source_str[100];
972 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
973 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
974 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
975 __FILE__, __PRETTY_FUNCTION__,
976 proto_mask, oif->name, pim_ifp->mroute_vif_index,
977 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
978 source_str, group_str);
979 return -2;
980 }
981
982 /* Mark that protocol is no longer interested in this OIF */
983 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
984
985 /* Allow multiple protocols to unsubscribe same interface from
986 channel (S,G) multiple times, by silently ignoring requests while
987 there is at least one protocol interested in the channel */
988 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
989
990 /* Check the OIF keeps existing before returning, and only log
991 warning otherwise */
992 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
993 char group_str[100];
994 char source_str[100];
995 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
996 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
997 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
998 __FILE__, __PRETTY_FUNCTION__,
999 proto_mask, oif->name, pim_ifp->mroute_vif_index,
1000 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
1001 source_str, group_str);
1002 }
1003
1004 return 0;
1005 }
1006
1007 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1008
1009 if (old_ttl < 1) {
1010 char group_str[100];
1011 char source_str[100];
1012 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1013 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1014 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1015 __FILE__, __PRETTY_FUNCTION__,
1016 oif->name, pim_ifp->mroute_vif_index,
1017 source_str, group_str);
1018 return -3;
1019 }
1020
1021 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1022
1023 if (pim_mroute_add(&channel_oil->oil)) {
1024 char group_str[100];
1025 char source_str[100];
1026 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1027 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1028 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1029 __FILE__, __PRETTY_FUNCTION__,
1030 oif->name, pim_ifp->mroute_vif_index,
1031 source_str, group_str);
1032
1033 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1034 return -4;
1035 }
1036
1037 --channel_oil->oil_size;
1038
1039 if (channel_oil->oil_size < 1) {
1040 if (pim_mroute_del(&channel_oil->oil)) {
1041 /* just log a warning in case of failure */
1042 char group_str[100];
1043 char source_str[100];
1044 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1045 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1046 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1047 __FILE__, __PRETTY_FUNCTION__,
1048 source_str, group_str);
1049 }
1050 }
1051
Everton Marques67faabc2010-02-23 12:11:11 -03001052 if (PIM_DEBUG_MROUTE) {
1053 char group_str[100];
1054 char source_str[100];
1055 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1056 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1057 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1058 __FILE__, __PRETTY_FUNCTION__,
1059 source_str, group_str,
1060 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1061 }
1062
Everton Marques871dbcf2009-08-11 15:43:05 -03001063 return 0;
1064}
1065
1066void igmp_source_forward_start(struct igmp_source *source)
1067{
1068 struct igmp_group *group;
1069
1070 if (PIM_DEBUG_IGMP_TRACE) {
1071 char source_str[100];
1072 char group_str[100];
1073 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1074 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1075 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1076 __PRETTY_FUNCTION__,
1077 source_str, group_str,
1078 source->source_group->group_igmp_sock->fd,
1079 source->source_group->group_igmp_sock->interface->name,
1080 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1081 }
1082
1083 /* Prevent IGMP interface from installing multicast route multiple
1084 times */
1085 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1086 return;
1087 }
1088
1089 group = source->source_group;
1090
1091 if (!source->source_channel_oil) {
1092 struct pim_interface *pim_oif;
1093 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1094 if (input_iface_vif_index < 1) {
1095 char source_str[100];
1096 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1097 zlog_warn("%s %s: could not find input interface for source %s",
1098 __FILE__, __PRETTY_FUNCTION__,
1099 source_str);
1100 return;
1101 }
1102
1103 /*
1104 Protect IGMP against adding looped MFC entries created by both
1105 source and receiver attached to the same interface. See TODO
1106 T22.
1107 */
1108 pim_oif = source->source_group->group_igmp_sock->interface->info;
1109 if (!pim_oif) {
1110 zlog_warn("%s: multicast not enabled on oif=%s ?",
1111 __PRETTY_FUNCTION__,
1112 source->source_group->group_igmp_sock->interface->name);
1113 return;
1114 }
1115 if (pim_oif->mroute_vif_index < 1) {
1116 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1117 __FILE__, __PRETTY_FUNCTION__,
1118 source->source_group->group_igmp_sock->interface->name,
1119 pim_oif->mroute_vif_index);
1120 return;
1121 }
1122 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1123 /* ignore request for looped MFC entry */
1124 if (PIM_DEBUG_IGMP_TRACE) {
1125 char source_str[100];
1126 char group_str[100];
1127 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1128 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1129 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1130 __PRETTY_FUNCTION__,
1131 source_str, group_str,
1132 source->source_group->group_igmp_sock->fd,
1133 source->source_group->group_igmp_sock->interface->name,
1134 input_iface_vif_index);
1135 }
1136 return;
1137 }
1138
1139 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1140 source->source_addr,
1141 input_iface_vif_index);
1142 if (!source->source_channel_oil) {
1143 char group_str[100];
1144 char source_str[100];
1145 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1146 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1147 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1148 __FILE__, __PRETTY_FUNCTION__,
1149 source_str, group_str);
1150 return;
1151 }
1152 }
1153
1154 if (add_oif(source->source_channel_oil,
1155 group->group_igmp_sock->interface,
1156 PIM_OIF_FLAG_PROTO_IGMP)) {
1157 return;
1158 }
1159
1160 /*
1161 Feed IGMPv3-gathered local membership information into PIM
1162 per-interface (S,G) state.
1163 */
1164 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1165 source->source_addr, group->group_addr);
1166
1167 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1168}
1169
1170void igmp_source_forward_stop(struct igmp_source *source)
1171{
1172 struct igmp_group *group;
1173
1174 if (PIM_DEBUG_IGMP_TRACE) {
1175 char source_str[100];
1176 char group_str[100];
1177 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1178 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1179 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1180 __PRETTY_FUNCTION__,
1181 source_str, group_str,
1182 source->source_group->group_igmp_sock->fd,
1183 source->source_group->group_igmp_sock->interface->name,
1184 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1185 }
1186
1187 /* Prevent IGMP interface from removing multicast route multiple
1188 times */
1189 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1190 return;
1191 }
1192
1193 group = source->source_group;
1194
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001195 /*
1196 It appears that in certain circumstances that
1197 igmp_source_forward_stop is called when IGMP forwarding
1198 was not enabled in oif_flags for this outgoing interface.
1199 Possibly because of multiple calls. When that happens, we
1200 enter the below if statement and this function returns early
1201 which in turn triggers the calling function to assert.
1202 Making the call to del_oif and ignoring the return code
1203 fixes the issue without ill effect, similar to
1204 pim_forward_stop below.
1205 */
1206 /*if (del_oif(source->source_channel_oil,
Everton Marques871dbcf2009-08-11 15:43:05 -03001207 group->group_igmp_sock->interface,
1208 PIM_OIF_FLAG_PROTO_IGMP)) {
1209 return;
Savannah SR#108542ecc1fb92014-09-25 14:41:43 -03001210 }*/
1211 del_oif(source->source_channel_oil,
1212 group->group_igmp_sock->interface,
1213 PIM_OIF_FLAG_PROTO_IGMP);
Everton Marques871dbcf2009-08-11 15:43:05 -03001214
1215 /*
1216 Feed IGMPv3-gathered local membership information into PIM
1217 per-interface (S,G) state.
1218 */
1219 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1220 source->source_addr, group->group_addr);
1221
1222 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1223}
1224
1225void pim_forward_start(struct pim_ifchannel *ch)
1226{
1227 struct pim_upstream *up = ch->upstream;
1228
1229 if (PIM_DEBUG_PIM_TRACE) {
1230 char source_str[100];
1231 char group_str[100];
1232 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1233 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1234 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1235 __PRETTY_FUNCTION__,
1236 source_str, group_str, ch->interface->name);
1237 }
1238
1239 if (!up->channel_oil) {
1240 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1241 if (input_iface_vif_index < 1) {
1242 char source_str[100];
1243 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1244 zlog_warn("%s %s: could not find input interface for source %s",
1245 __FILE__, __PRETTY_FUNCTION__,
1246 source_str);
1247 return;
1248 }
1249
1250 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1251 input_iface_vif_index);
1252 if (!up->channel_oil) {
1253 char group_str[100];
1254 char source_str[100];
1255 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1256 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1257 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1258 __FILE__, __PRETTY_FUNCTION__,
1259 source_str, group_str);
1260 return;
1261 }
1262 }
1263
1264 add_oif(up->channel_oil,
1265 ch->interface,
1266 PIM_OIF_FLAG_PROTO_PIM);
1267}
1268
1269void pim_forward_stop(struct pim_ifchannel *ch)
1270{
1271 struct pim_upstream *up = ch->upstream;
1272
1273 if (PIM_DEBUG_PIM_TRACE) {
1274 char source_str[100];
1275 char group_str[100];
1276 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1277 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1278 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1279 __PRETTY_FUNCTION__,
1280 source_str, group_str, ch->interface->name);
1281 }
1282
1283 if (!up->channel_oil) {
1284 char source_str[100];
1285 char group_str[100];
1286 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1287 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1288 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1289 __PRETTY_FUNCTION__,
1290 source_str, group_str, ch->interface->name);
1291
1292 return;
1293 }
1294
1295 del_oif(up->channel_oil,
1296 ch->interface,
1297 PIM_OIF_FLAG_PROTO_PIM);
1298}