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