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