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