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