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