]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_rpf.c
pimd: Refactor functions
[mirror_frr.git] / pimd / pim_rpf.c
CommitLineData
12e41d03
DL
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
12e41d03
DL
19*/
20
21#include <zebra.h>
22
744d91b3
DS
23#include "if.h"
24
12e41d03
DL
25#include "log.h"
26#include "prefix.h"
27#include "memory.h"
28
29#include "pimd.h"
30#include "pim_rpf.h"
31#include "pim_pim.h"
32#include "pim_str.h"
33#include "pim_iface.h"
34#include "pim_zlookup.h"
35#include "pim_ifchannel.h"
e71bf8f7
DS
36#include "pim_time.h"
37
38static long long last_route_change_time = -1;
39long long nexthop_lookups_avoided = 0;
12e41d03
DL
40
41static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
42
e71bf8f7
DS
43void
44pim_rpf_set_refresh_time (void)
45{
46 last_route_change_time = pim_time_monotonic_usec();
47 if (PIM_DEBUG_TRACE)
48 zlog_debug ("%s: New last route change time: %lld",
49 __PRETTY_FUNCTION__, last_route_change_time);
50}
51
63b8f7a3 52int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed)
12e41d03 53{
7b2c4d16 54 struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
12e41d03 55 int num_ifindex;
7a6e6567
DS
56 struct interface *ifp = NULL;
57 ifindex_t first_ifindex = 0;
63b8f7a3
DS
58 int found = 0;
59 int i = 0;
12e41d03 60
e71bf8f7
DS
61 if ((nexthop->last_lookup.s_addr == addr.s_addr) &&
62 (nexthop->last_lookup_time > last_route_change_time))
63 {
64 if (PIM_DEBUG_TRACE)
65 {
66 char addr_str[INET_ADDRSTRLEN];
67 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
68 zlog_debug ("%s: Using last lookup for %s at %lld, %lld",
69 __PRETTY_FUNCTION__,
70 addr_str,
71 nexthop->last_lookup_time,
72 last_route_change_time);
73 }
74 nexthop_lookups_avoided++;
75 return 0;
76 }
77 else
78 {
79 if (PIM_DEBUG_TRACE)
80 {
81 char addr_str[INET_ADDRSTRLEN];
82 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
83 zlog_debug ("%s: Looking up: %s, last lookup time: %lld, %lld",
84 __PRETTY_FUNCTION__,
85 addr_str,
86 nexthop->last_lookup_time,
87 last_route_change_time);
88 }
89 }
90
7b2c4d16 91 memset (nexthop_tab, 0, sizeof (struct pim_zlookup_nexthop) * MULTIPATH_NUM);
f24405b1 92 num_ifindex = zclient_lookup_nexthop(nexthop_tab,
7b2c4d16 93 MULTIPATH_NUM,
f24405b1
DS
94 addr, PIM_NEXTHOP_LOOKUP_MAX);
95 if (num_ifindex < 1) {
eaa54bdb 96 char addr_str[INET_ADDRSTRLEN];
f24405b1
DS
97 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
98 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
99 __FILE__, __PRETTY_FUNCTION__,
100 addr_str);
101 return -1;
102 }
103
518e5727 104 while (!found && (i < num_ifindex))
63b8f7a3
DS
105 {
106 first_ifindex = nexthop_tab[i].ifindex;
107
108 ifp = if_lookup_by_index(first_ifindex);
109 if (!ifp)
110 {
111 if (PIM_DEBUG_ZEBRA)
112 {
eaa54bdb 113 char addr_str[INET_ADDRSTRLEN];
63b8f7a3
DS
114 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
115 zlog_debug("%s %s: could not find interface for ifindex %d (address %s)",
116 __FILE__, __PRETTY_FUNCTION__,
117 first_ifindex, addr_str);
118 }
28185336
DS
119 i++;
120 continue;
63b8f7a3
DS
121 }
122
518e5727 123 if (!ifp->info)
63b8f7a3 124 {
518e5727
DS
125 if (PIM_DEBUG_ZEBRA)
126 {
127 char addr_str[INET_ADDRSTRLEN];
128 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
129 zlog_debug("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
130 __PRETTY_FUNCTION__,
131 ifp->name, first_ifindex, addr_str);
132 }
133 i++;
63b8f7a3 134 }
518e5727 135 else if (neighbor_needed && !pim_if_connected_to_source (ifp, addr))
63b8f7a3
DS
136 {
137 struct pim_neighbor *nbr;
138
139 nbr = pim_neighbor_find (ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
802b226c 140 if (PIM_DEBUG_PIM_TRACE_DETAIL)
63b8f7a3
DS
141 zlog_debug ("ifp name: %s, pim nbr: %p", ifp->name, nbr);
142 if (!nbr && !if_is_loopback (ifp))
143 i++;
144 else
145 found = 1;
146 }
147 else
148 found = 1;
149 }
150
151 if (found)
152 {
153 if (PIM_DEBUG_ZEBRA) {
eaa54bdb
DW
154 char nexthop_str[PREFIX_STRLEN];
155 char addr_str[INET_ADDRSTRLEN];
58c51da2 156 pim_addr_dump("<nexthop?>", &nexthop_tab[i].nexthop_addr, nexthop_str, sizeof(nexthop_str));
63b8f7a3
DS
157 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
158 zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
159 __FILE__, __PRETTY_FUNCTION__,
160 nexthop_str, addr_str,
161 ifp->name, first_ifindex,
58c51da2 162 nexthop_tab[i].route_metric,
163 nexthop_tab[i].protocol_distance);
63b8f7a3
DS
164 }
165 /* update nextop data */
166 nexthop->interface = ifp;
58c51da2 167 nexthop->mrib_nexthop_addr = nexthop_tab[i].nexthop_addr;
168 nexthop->mrib_metric_preference = nexthop_tab[i].protocol_distance;
169 nexthop->mrib_route_metric = nexthop_tab[i].route_metric;
e71bf8f7
DS
170 nexthop->last_lookup = addr;
171 nexthop->last_lookup_time = pim_time_monotonic_usec();
63b8f7a3
DS
172 return 0;
173 }
174 else
7f748d95 175 return -1;
12e41d03
DL
176}
177
178static int nexthop_mismatch(const struct pim_nexthop *nh1,
179 const struct pim_nexthop *nh2)
180{
63c59d0c
DS
181 return (nh1->interface != nh2->interface) ||
182 (nh1->mrib_nexthop_addr.u.prefix4.s_addr != nh2->mrib_nexthop_addr.u.prefix4.s_addr) ||
183 (nh1->mrib_metric_preference != nh2->mrib_metric_preference) ||
12e41d03
DL
184 (nh1->mrib_route_metric != nh2->mrib_route_metric);
185}
186
f24405b1 187enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr)
12e41d03 188{
63c59d0c 189 struct prefix save_rpf_addr;
12e41d03
DL
190 struct pim_nexthop save_nexthop;
191 struct pim_rpf *rpf = &up->rpf;
192
193 save_nexthop = rpf->source_nexthop; /* detect change in pim_nexthop */
194 save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */
195
63b8f7a3 196 if (pim_nexthop_lookup(&rpf->source_nexthop,
4a40c37a
DS
197 up->upstream_addr,
198 !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
199 !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) {
12e41d03
DL
200 return PIM_RPF_FAILURE;
201 }
202
63c59d0c
DS
203 rpf->rpf_addr.family = AF_INET;
204 rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
205 if (pim_rpf_addr_is_inaddr_any(rpf) && PIM_DEBUG_ZEBRA) {
12e41d03 206 /* RPF'(S,G) not found */
05e451f8 207 zlog_debug("%s %s: RPF'%s not found: won't send join upstream",
7adf0260 208 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 209 up->sg_str);
12e41d03
DL
210 /* warning only */
211 }
212
213 /* detect change in pim_nexthop */
214 if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) {
215
ff67a923 216 if (PIM_DEBUG_ZEBRA) {
eaa54bdb 217 char nhaddr_str[PREFIX_STRLEN];
63c59d0c 218 pim_addr_dump("<addr?>", &rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str));
05e451f8 219 zlog_debug("%s %s: (S,G)=%s source nexthop now is: interface=%s address=%s pref=%d metric=%d",
12e41d03 220 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 221 up->sg_str,
12e41d03
DL
222 rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>",
223 nhaddr_str,
224 rpf->source_nexthop.mrib_metric_preference,
225 rpf->source_nexthop.mrib_route_metric);
12e41d03
DL
226 }
227
228 pim_upstream_update_join_desired(up);
229 pim_upstream_update_could_assert(up);
230 pim_upstream_update_my_assert_metric(up);
231 }
232
233 /* detect change in RPF_interface(S) */
234 if (save_nexthop.interface != rpf->source_nexthop.interface) {
235
ff67a923 236 if (PIM_DEBUG_ZEBRA) {
05e451f8 237 zlog_debug("%s %s: (S,G)=%s RPF_interface(S) changed from %s to %s",
12e41d03 238 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 239 up->sg_str,
12e41d03
DL
240 save_nexthop.interface ? save_nexthop.interface->name : "<oldif?>",
241 rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<newif?>");
242 /* warning only */
243 }
244
245 pim_upstream_rpf_interface_changed(up, save_nexthop.interface);
246 }
247
248 /* detect change in RPF'(S,G) */
63c59d0c 249 if (save_rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) {
12e41d03
DL
250
251 /* return old rpf to caller ? */
252 if (old_rpf_addr)
63c59d0c 253 *old_rpf_addr = save_rpf_addr.u.prefix4;
12e41d03
DL
254
255 return PIM_RPF_CHANGED;
256 }
257
258 return PIM_RPF_OK;
259}
260
261/*
262 RFC 4601: 4.1.6. State Summarization Macros
263
264 neighbor RPF'(S,G) {
265 if ( I_Am_Assert_Loser(S, G, RPF_interface(S) )) {
266 return AssertWinner(S, G, RPF_interface(S) )
267 } else {
268 return NBR( RPF_interface(S), MRIB.next_hop( S ) )
269 }
270 }
271
272 RPF'(*,G) and RPF'(S,G) indicate the neighbor from which data
273 packets should be coming and to which joins should be sent on the RP
274 tree and SPT, respectively.
275*/
276static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
277{
278 struct pim_ifchannel *rpf_ch;
279 struct pim_neighbor *neigh;
280 struct in_addr rpf_addr;
281
282 if (!up->rpf.source_nexthop.interface) {
05e451f8 283 zlog_warn("%s: missing RPF interface for upstream (S,G)=%s",
12e41d03 284 __PRETTY_FUNCTION__,
8bfb8b67 285 up->sg_str);
12e41d03
DL
286
287 rpf_addr.s_addr = PIM_NET_INADDR_ANY;
288 return rpf_addr;
289 }
290
291 rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface,
5074a423 292 &up->sg);
12e41d03
DL
293 if (rpf_ch) {
294 if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
295 return rpf_ch->ifassert_winner;
296 }
297 }
298
299 /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */
300
301 neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface,
63c59d0c 302 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4);
12e41d03
DL
303 if (neigh)
304 rpf_addr = neigh->source_addr;
305 else
306 rpf_addr.s_addr = PIM_NET_INADDR_ANY;
307
308 return rpf_addr;
309}
63c59d0c
DS
310
311int
312pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf)
313{
314 switch (rpf->rpf_addr.family)
315 {
fa8da98c 316 case AF_INET:
63c59d0c
DS
317 return rpf->rpf_addr.u.prefix4.s_addr == INADDR_NONE;
318 break;
fa8da98c 319 case AF_INET6:
63c59d0c
DS
320 zlog_warn ("%s: v6 Unimplmeneted", __PRETTY_FUNCTION__);
321 return 1;
322 break;
323 default:
324 return 0;
325 break;
326 }
327
328 return 0;
329}
330
331int
332pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf)
333{
334 switch (rpf->rpf_addr.family)
335 {
fa8da98c 336 case AF_INET:
63c59d0c
DS
337 return rpf->rpf_addr.u.prefix4.s_addr == INADDR_ANY;
338 break;
fa8da98c 339 case AF_INET6:
63c59d0c
DS
340 zlog_warn ("%s: v6 Unimplmented", __PRETTY_FUNCTION__);
341 return 1;
342 break;
343 default:
344 return 0;
345 break;
346 }
347
348 return 0;
349}
66cc32fa
DS
350
351int
352pim_rpf_is_same (struct pim_rpf *rpf1, struct pim_rpf *rpf2)
353{
354 if (rpf1->source_nexthop.interface == rpf2->source_nexthop.interface)
355 return 1;
356
357 return 0;
358}