3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
33 #include "pim_iface.h"
34 #include "pim_zlookup.h"
35 #include "pim_ifchannel.h"
37 static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
39 int pim_nexthop_lookup(struct pim_nexthop *nexthop,
42 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
44 struct interface *ifp;
47 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
48 PIM_NEXTHOP_IFINDEX_TAB_SIZE,
49 addr, PIM_NEXTHOP_LOOKUP_MAX);
50 if (num_ifindex < 1) {
52 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
53 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
54 __FILE__, __PRETTY_FUNCTION__,
59 first_ifindex = nexthop_tab[0].ifindex;
61 if (num_ifindex > 1) {
63 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
64 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
65 __FILE__, __PRETTY_FUNCTION__,
66 num_ifindex, addr_str, first_ifindex);
67 /* debug warning only, do not return */
70 ifp = if_lookup_by_index(first_ifindex);
73 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
74 zlog_warn("%s %s: could not find interface for ifindex %d (address %s)",
75 __FILE__, __PRETTY_FUNCTION__,
76 first_ifindex, addr_str);
82 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
83 zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
85 ifp->name, first_ifindex, addr_str);
86 /* debug warning only, do not return */
89 if (PIM_DEBUG_PIM_TRACE) {
90 char nexthop_str[100];
92 pim_inet4_dump("<nexthop?>", nexthop_tab[0].nexthop_addr, nexthop_str, sizeof(nexthop_str));
93 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
94 zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
95 __FILE__, __PRETTY_FUNCTION__,
96 nexthop_str, addr_str,
97 ifp->name, first_ifindex,
98 nexthop_tab[0].route_metric,
99 nexthop_tab[0].protocol_distance);
102 /* update nextop data */
103 nexthop->interface = ifp;
104 nexthop->mrib_nexthop_addr = nexthop_tab[0].nexthop_addr;
105 nexthop->mrib_metric_preference = nexthop_tab[0].protocol_distance;
106 nexthop->mrib_route_metric = nexthop_tab[0].route_metric;
111 static int nexthop_mismatch(const struct pim_nexthop *nh1,
112 const struct pim_nexthop *nh2)
114 return (nh1->interface != nh2->interface)
116 (nh1->mrib_nexthop_addr.s_addr != nh2->mrib_nexthop_addr.s_addr)
118 (nh1->mrib_metric_preference != nh2->mrib_metric_preference)
120 (nh1->mrib_route_metric != nh2->mrib_route_metric);
123 enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
124 struct pim_rpf *old_rpf)
126 struct pim_nexthop save_nexthop;
127 struct pim_rpf save_rpf;
128 struct pim_rpf *rpf = &up->rpf;
130 save_nexthop = rpf->source_nexthop; /* detect change in pim_nexthop */
133 if (pim_nexthop_lookup(&rpf->source_nexthop,
135 return PIM_RPF_FAILURE;
138 rpf->rpf_addr = pim_rpf_find_rpf_addr(up);
139 if (PIM_INADDR_IS_ANY(rpf->rpf_addr) && PIM_DEBUG_PIM_EVENTS) {
140 /* RPF'(S,G) not found */
143 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
144 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
145 zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream",
146 __FILE__, __PRETTY_FUNCTION__,
151 /* detect change in pim_nexthop */
152 if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) {
154 if (PIM_DEBUG_PIM_EVENTS) {
157 char nhaddr_str[100];
158 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
159 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
160 pim_inet4_dump("<addr?>", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str));
161 zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d",
162 __FILE__, __PRETTY_FUNCTION__,
164 rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>",
166 rpf->source_nexthop.mrib_metric_preference,
167 rpf->source_nexthop.mrib_route_metric);
171 pim_upstream_update_join_desired(up);
172 pim_upstream_update_could_assert(up);
173 pim_upstream_update_my_assert_metric(up);
176 /* detect change in RPF_interface(S) */
177 if (save_nexthop.interface != rpf->source_nexthop.interface) {
179 if (PIM_DEBUG_PIM_EVENTS) {
182 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
183 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
184 zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s",
185 __FILE__, __PRETTY_FUNCTION__,
187 save_nexthop.interface ? save_nexthop.interface->name : "<oldif?>",
188 rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<newif?>");
192 pim_upstream_rpf_interface_changed(up, save_nexthop.interface);
195 /* detect change in RPF'(S,G) */
196 if (save_rpf.rpf_addr.s_addr != rpf->rpf_addr.s_addr) {
198 /* return old rpf to caller ? */
202 return PIM_RPF_CHANGED;
209 RFC 4601: 4.1.6. State Summarization Macros
212 if ( I_Am_Assert_Loser(S, G, RPF_interface(S) )) {
213 return AssertWinner(S, G, RPF_interface(S) )
215 return NBR( RPF_interface(S), MRIB.next_hop( S ) )
219 RPF'(*,G) and RPF'(S,G) indicate the neighbor from which data
220 packets should be coming and to which joins should be sent on the RP
221 tree and SPT, respectively.
223 static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
225 struct pim_ifchannel *rpf_ch;
226 struct pim_neighbor *neigh;
227 struct in_addr rpf_addr;
229 if (!up->rpf.source_nexthop.interface) {
232 pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
233 pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
234 zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)",
238 rpf_addr.s_addr = PIM_NET_INADDR_ANY;
242 rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface,
243 up->source_addr, up->group_addr);
245 if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
246 return rpf_ch->ifassert_winner;
250 /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */
252 neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface,
253 up->rpf.source_nexthop.mrib_nexthop_addr);
255 rpf_addr = neigh->source_addr;
257 rpf_addr.s_addr = PIM_NET_INADDR_ANY;