blob: 321e31712c31d6d897ace90adf90fe60945acad8 [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 Marques871dbcf2009-08-11 15:43:05 -0300673 zlog_info("zclient_init cleared redistribution request");
674
Everton Marques3456a802014-07-22 14:52:57 -0300675 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
Everton Marques871dbcf2009-08-11 15:43:05 -0300676
677 /* Request all redistribution */
678 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
Everton Marques3456a802014-07-22 14:52:57 -0300679 if (i == qpim_zclient_update->redist_default)
Everton Marques871dbcf2009-08-11 15:43:05 -0300680 continue;
Everton Marques3456a802014-07-22 14:52:57 -0300681 qpim_zclient_update->redist[i] = 1;
Everton Marques871dbcf2009-08-11 15:43:05 -0300682 zlog_info("%s: requesting redistribution for %s (%i)",
683 __PRETTY_FUNCTION__, zebra_route_string(i), i);
684 }
685
686 /* Request default information */
Everton Marques3456a802014-07-22 14:52:57 -0300687 qpim_zclient_update->default_information = 1;
Everton Marques871dbcf2009-08-11 15:43:05 -0300688 zlog_info("%s: requesting default information redistribution",
689 __PRETTY_FUNCTION__);
690
691 zlog_notice("%s: zclient update socket initialized",
692 __PRETTY_FUNCTION__);
693
694 zassert(!qpim_zclient_lookup);
695 qpim_zclient_lookup = zclient_lookup_new();
696 zassert(qpim_zclient_lookup);
697}
698
699void igmp_anysource_forward_start(struct igmp_group *group)
700{
701 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
702 zassert(group->group_filtermode_isexcl);
703 zassert(listcount(group->group_source_list) < 1);
704
705 if (PIM_DEBUG_IGMP_TRACE) {
706 zlog_debug("%s %s: UNIMPLEMENTED",
707 __FILE__, __PRETTY_FUNCTION__);
708 }
709}
710
711void igmp_anysource_forward_stop(struct igmp_group *group)
712{
713 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
714 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
715
716 if (PIM_DEBUG_IGMP_TRACE) {
717 zlog_debug("%s %s: UNIMPLEMENTED",
718 __FILE__, __PRETTY_FUNCTION__);
719 }
720}
721
722static int fib_lookup_if_vif_index(struct in_addr addr)
723{
724 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
725 int num_ifindex;
726 int vif_index;
727 int first_ifindex;
728
729 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
730 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
731 PIM_NEXTHOP_LOOKUP_MAX);
732 if (num_ifindex < 1) {
733 char addr_str[100];
734 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
735 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
736 __FILE__, __PRETTY_FUNCTION__,
737 addr_str);
738 return -1;
739 }
740
741 first_ifindex = nexthop_tab[0].ifindex;
742
743 if (num_ifindex > 1) {
744 char addr_str[100];
745 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
746 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
747 __FILE__, __PRETTY_FUNCTION__,
748 num_ifindex, addr_str, first_ifindex);
749 /* debug warning only, do not return */
750 }
751
752 if (PIM_DEBUG_ZEBRA) {
753 char addr_str[100];
754 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
755 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
756 __FILE__, __PRETTY_FUNCTION__,
757 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
758 }
759
760 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
761
762 if (vif_index < 1) {
763 char addr_str[100];
764 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
765 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
766 __FILE__, __PRETTY_FUNCTION__,
767 vif_index, addr_str);
768 return -2;
769 }
770
771 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
772
773 if (vif_index > qpim_mroute_oif_highest_vif_index) {
774 char addr_str[100];
775 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
776 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
777 __FILE__, __PRETTY_FUNCTION__,
778 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
779
780 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
781 __FILE__, __PRETTY_FUNCTION__,
782 ifindex2ifname(vif_index),
783 vif_index);
784
785 return -3;
786 }
787
788 return vif_index;
789}
790
791static int add_oif(struct channel_oil *channel_oil,
792 struct interface *oif,
793 uint32_t proto_mask)
794{
795 struct pim_interface *pim_ifp;
796 int old_ttl;
797
798 zassert(channel_oil);
799
800 pim_ifp = oif->info;
801
Everton Marques67faabc2010-02-23 12:11:11 -0300802 if (PIM_DEBUG_MROUTE) {
803 char group_str[100];
804 char source_str[100];
805 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
806 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
807 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
808 __FILE__, __PRETTY_FUNCTION__,
809 source_str, group_str,
810 proto_mask, oif->name, pim_ifp->mroute_vif_index);
811 }
812
Everton Marques871dbcf2009-08-11 15:43:05 -0300813 if (pim_ifp->mroute_vif_index < 1) {
814 zlog_warn("%s %s: interface %s vif_index=%d < 1",
815 __FILE__, __PRETTY_FUNCTION__,
816 oif->name, pim_ifp->mroute_vif_index);
817 return -1;
818 }
819
820#ifdef PIM_ENFORCE_LOOPFREE_MFC
821 /*
822 Prevent creating MFC entry with OIF=IIF.
823
824 This is a protection against implementation mistakes.
825
826 PIM protocol implicitely ensures loopfree multicast topology.
827
828 IGMP must be protected against adding looped MFC entries created
829 by both source and receiver attached to the same interface. See
830 TODO T22.
831 */
832 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
833 char group_str[100];
834 char source_str[100];
835 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
836 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
837 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
838 __FILE__, __PRETTY_FUNCTION__,
839 proto_mask, oif->name, pim_ifp->mroute_vif_index,
840 source_str, group_str);
841 return -2;
842 }
843#endif
844
845 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
846 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
847
848 /* Prevent single protocol from subscribing same interface to
849 channel (S,G) multiple times */
850 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
851 char group_str[100];
852 char source_str[100];
853 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
854 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
855 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
856 __FILE__, __PRETTY_FUNCTION__,
857 proto_mask, oif->name, pim_ifp->mroute_vif_index,
858 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
859 source_str, group_str);
860 return -3;
861 }
862
863 /* Allow other protocol to request subscription of same interface to
864 channel (S,G) multiple times, by silently ignoring further
865 requests */
866 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
867
868 /* Check the OIF really exists before returning, and only log
869 warning otherwise */
870 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
871 char group_str[100];
872 char source_str[100];
873 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
874 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
875 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
876 __FILE__, __PRETTY_FUNCTION__,
877 proto_mask, oif->name, pim_ifp->mroute_vif_index,
878 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
879 source_str, group_str);
880 }
881
882 return 0;
883 }
884
885 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
886
887 if (old_ttl > 0) {
888 char group_str[100];
889 char source_str[100];
890 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
891 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
892 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
893 __FILE__, __PRETTY_FUNCTION__,
894 oif->name, pim_ifp->mroute_vif_index,
895 source_str, group_str);
896 return -4;
897 }
898
899 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
900
901 if (pim_mroute_add(&channel_oil->oil)) {
902 char group_str[100];
903 char source_str[100];
904 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
905 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
906 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
907 __FILE__, __PRETTY_FUNCTION__,
908 oif->name, pim_ifp->mroute_vif_index,
909 source_str, group_str);
910
911 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
912 return -5;
913 }
914
915 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
916 ++channel_oil->oil_size;
917 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
918
Everton Marques67faabc2010-02-23 12:11:11 -0300919 if (PIM_DEBUG_MROUTE) {
920 char group_str[100];
921 char source_str[100];
922 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
923 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
924 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
925 __FILE__, __PRETTY_FUNCTION__,
926 source_str, group_str,
927 proto_mask, oif->name, pim_ifp->mroute_vif_index);
928 }
929
Everton Marques871dbcf2009-08-11 15:43:05 -0300930 return 0;
931}
932
933static int del_oif(struct channel_oil *channel_oil,
934 struct interface *oif,
935 uint32_t proto_mask)
936{
937 struct pim_interface *pim_ifp;
938 int old_ttl;
939
940 zassert(channel_oil);
941
942 pim_ifp = oif->info;
943
944 zassert(pim_ifp->mroute_vif_index >= 1);
945 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
946 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
947
Everton Marques67faabc2010-02-23 12:11:11 -0300948 if (PIM_DEBUG_MROUTE) {
949 char group_str[100];
950 char source_str[100];
951 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
952 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
953 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
954 __FILE__, __PRETTY_FUNCTION__,
955 source_str, group_str,
956 proto_mask, oif->name, pim_ifp->mroute_vif_index);
957 }
958
Everton Marques871dbcf2009-08-11 15:43:05 -0300959 /* Prevent single protocol from unsubscribing same interface from
960 channel (S,G) multiple times */
961 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
962 char group_str[100];
963 char source_str[100];
964 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
965 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
966 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
967 __FILE__, __PRETTY_FUNCTION__,
968 proto_mask, oif->name, pim_ifp->mroute_vif_index,
969 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
970 source_str, group_str);
971 return -2;
972 }
973
974 /* Mark that protocol is no longer interested in this OIF */
975 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
976
977 /* Allow multiple protocols to unsubscribe same interface from
978 channel (S,G) multiple times, by silently ignoring requests while
979 there is at least one protocol interested in the channel */
980 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
981
982 /* Check the OIF keeps existing before returning, and only log
983 warning otherwise */
984 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
985 char group_str[100];
986 char source_str[100];
987 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
988 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
989 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
990 __FILE__, __PRETTY_FUNCTION__,
991 proto_mask, oif->name, pim_ifp->mroute_vif_index,
992 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
993 source_str, group_str);
994 }
995
996 return 0;
997 }
998
999 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1000
1001 if (old_ttl < 1) {
1002 char group_str[100];
1003 char source_str[100];
1004 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1005 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1006 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1007 __FILE__, __PRETTY_FUNCTION__,
1008 oif->name, pim_ifp->mroute_vif_index,
1009 source_str, group_str);
1010 return -3;
1011 }
1012
1013 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1014
1015 if (pim_mroute_add(&channel_oil->oil)) {
1016 char group_str[100];
1017 char source_str[100];
1018 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1019 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1020 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1021 __FILE__, __PRETTY_FUNCTION__,
1022 oif->name, pim_ifp->mroute_vif_index,
1023 source_str, group_str);
1024
1025 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1026 return -4;
1027 }
1028
1029 --channel_oil->oil_size;
1030
1031 if (channel_oil->oil_size < 1) {
1032 if (pim_mroute_del(&channel_oil->oil)) {
1033 /* just log a warning in case of failure */
1034 char group_str[100];
1035 char source_str[100];
1036 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1037 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1038 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1039 __FILE__, __PRETTY_FUNCTION__,
1040 source_str, group_str);
1041 }
1042 }
1043
Everton Marques67faabc2010-02-23 12:11:11 -03001044 if (PIM_DEBUG_MROUTE) {
1045 char group_str[100];
1046 char source_str[100];
1047 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1048 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1049 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1050 __FILE__, __PRETTY_FUNCTION__,
1051 source_str, group_str,
1052 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1053 }
1054
Everton Marques871dbcf2009-08-11 15:43:05 -03001055 return 0;
1056}
1057
1058void igmp_source_forward_start(struct igmp_source *source)
1059{
1060 struct igmp_group *group;
1061
1062 if (PIM_DEBUG_IGMP_TRACE) {
1063 char source_str[100];
1064 char group_str[100];
1065 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1066 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1067 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1068 __PRETTY_FUNCTION__,
1069 source_str, group_str,
1070 source->source_group->group_igmp_sock->fd,
1071 source->source_group->group_igmp_sock->interface->name,
1072 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1073 }
1074
1075 /* Prevent IGMP interface from installing multicast route multiple
1076 times */
1077 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1078 return;
1079 }
1080
1081 group = source->source_group;
1082
1083 if (!source->source_channel_oil) {
1084 struct pim_interface *pim_oif;
1085 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1086 if (input_iface_vif_index < 1) {
1087 char source_str[100];
1088 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1089 zlog_warn("%s %s: could not find input interface for source %s",
1090 __FILE__, __PRETTY_FUNCTION__,
1091 source_str);
1092 return;
1093 }
1094
1095 /*
1096 Protect IGMP against adding looped MFC entries created by both
1097 source and receiver attached to the same interface. See TODO
1098 T22.
1099 */
1100 pim_oif = source->source_group->group_igmp_sock->interface->info;
1101 if (!pim_oif) {
1102 zlog_warn("%s: multicast not enabled on oif=%s ?",
1103 __PRETTY_FUNCTION__,
1104 source->source_group->group_igmp_sock->interface->name);
1105 return;
1106 }
1107 if (pim_oif->mroute_vif_index < 1) {
1108 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1109 __FILE__, __PRETTY_FUNCTION__,
1110 source->source_group->group_igmp_sock->interface->name,
1111 pim_oif->mroute_vif_index);
1112 return;
1113 }
1114 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1115 /* ignore request for looped MFC entry */
1116 if (PIM_DEBUG_IGMP_TRACE) {
1117 char source_str[100];
1118 char group_str[100];
1119 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1120 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1121 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1122 __PRETTY_FUNCTION__,
1123 source_str, group_str,
1124 source->source_group->group_igmp_sock->fd,
1125 source->source_group->group_igmp_sock->interface->name,
1126 input_iface_vif_index);
1127 }
1128 return;
1129 }
1130
1131 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1132 source->source_addr,
1133 input_iface_vif_index);
1134 if (!source->source_channel_oil) {
1135 char group_str[100];
1136 char source_str[100];
1137 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1138 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1139 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1140 __FILE__, __PRETTY_FUNCTION__,
1141 source_str, group_str);
1142 return;
1143 }
1144 }
1145
1146 if (add_oif(source->source_channel_oil,
1147 group->group_igmp_sock->interface,
1148 PIM_OIF_FLAG_PROTO_IGMP)) {
1149 return;
1150 }
1151
1152 /*
1153 Feed IGMPv3-gathered local membership information into PIM
1154 per-interface (S,G) state.
1155 */
1156 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1157 source->source_addr, group->group_addr);
1158
1159 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1160}
1161
1162void igmp_source_forward_stop(struct igmp_source *source)
1163{
1164 struct igmp_group *group;
1165
1166 if (PIM_DEBUG_IGMP_TRACE) {
1167 char source_str[100];
1168 char group_str[100];
1169 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1170 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1171 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1172 __PRETTY_FUNCTION__,
1173 source_str, group_str,
1174 source->source_group->group_igmp_sock->fd,
1175 source->source_group->group_igmp_sock->interface->name,
1176 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1177 }
1178
1179 /* Prevent IGMP interface from removing multicast route multiple
1180 times */
1181 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1182 return;
1183 }
1184
1185 group = source->source_group;
1186
1187 if (del_oif(source->source_channel_oil,
1188 group->group_igmp_sock->interface,
1189 PIM_OIF_FLAG_PROTO_IGMP)) {
1190 return;
1191 }
1192
1193 /*
1194 Feed IGMPv3-gathered local membership information into PIM
1195 per-interface (S,G) state.
1196 */
1197 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1198 source->source_addr, group->group_addr);
1199
1200 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1201}
1202
1203void pim_forward_start(struct pim_ifchannel *ch)
1204{
1205 struct pim_upstream *up = ch->upstream;
1206
1207 if (PIM_DEBUG_PIM_TRACE) {
1208 char source_str[100];
1209 char group_str[100];
1210 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1211 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1212 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1213 __PRETTY_FUNCTION__,
1214 source_str, group_str, ch->interface->name);
1215 }
1216
1217 if (!up->channel_oil) {
1218 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1219 if (input_iface_vif_index < 1) {
1220 char source_str[100];
1221 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1222 zlog_warn("%s %s: could not find input interface for source %s",
1223 __FILE__, __PRETTY_FUNCTION__,
1224 source_str);
1225 return;
1226 }
1227
1228 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1229 input_iface_vif_index);
1230 if (!up->channel_oil) {
1231 char group_str[100];
1232 char source_str[100];
1233 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1234 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1235 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1236 __FILE__, __PRETTY_FUNCTION__,
1237 source_str, group_str);
1238 return;
1239 }
1240 }
1241
1242 add_oif(up->channel_oil,
1243 ch->interface,
1244 PIM_OIF_FLAG_PROTO_PIM);
1245}
1246
1247void pim_forward_stop(struct pim_ifchannel *ch)
1248{
1249 struct pim_upstream *up = ch->upstream;
1250
1251 if (PIM_DEBUG_PIM_TRACE) {
1252 char source_str[100];
1253 char group_str[100];
1254 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1255 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1256 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1257 __PRETTY_FUNCTION__,
1258 source_str, group_str, ch->interface->name);
1259 }
1260
1261 if (!up->channel_oil) {
1262 char source_str[100];
1263 char group_str[100];
1264 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1265 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1266 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1267 __PRETTY_FUNCTION__,
1268 source_str, group_str, ch->interface->name);
1269
1270 return;
1271 }
1272
1273 del_oif(up->channel_oil,
1274 ch->interface,
1275 PIM_OIF_FLAG_PROTO_PIM);
1276}