]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_nhg.c
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
[mirror_frr.git] / zebra / zebra_nhg.c
1 /* Zebra Nexthop Group Code.
2 * Copyright (C) 2019 Cumulus Networks, Inc.
3 * Donald Sharp
4 * Stephen Worley
5 *
6 * This file is part of FRR.
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23 #include <zebra.h>
24
25 #include "lib/nexthop.h"
26 #include "lib/routemap.h"
27
28 #include "zebra/connected.h"
29 #include "zebra/debug.h"
30 #include "zebra/zebra_router.h"
31 #include "zebra/zebra_nhg.h"
32 #include "zebra/zebra_rnh.h"
33 #include "zebra/zebra_routemap.h"
34 #include "zebra/rt.h"
35
36 static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
37 struct nexthop *nexthop)
38 {
39 struct nexthop *resolved_hop;
40
41 resolved_hop = nexthop_new();
42 SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
43
44 resolved_hop->vrf_id = nexthop->vrf_id;
45 switch (newhop->type) {
46 case NEXTHOP_TYPE_IPV4:
47 case NEXTHOP_TYPE_IPV4_IFINDEX:
48 /* If the resolving route specifies a gateway, use it */
49 resolved_hop->type = newhop->type;
50 resolved_hop->gate.ipv4 = newhop->gate.ipv4;
51
52 if (newhop->ifindex) {
53 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
54 resolved_hop->ifindex = newhop->ifindex;
55 }
56 break;
57 case NEXTHOP_TYPE_IPV6:
58 case NEXTHOP_TYPE_IPV6_IFINDEX:
59 resolved_hop->type = newhop->type;
60 resolved_hop->gate.ipv6 = newhop->gate.ipv6;
61
62 if (newhop->ifindex) {
63 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
64 resolved_hop->ifindex = newhop->ifindex;
65 }
66 break;
67 case NEXTHOP_TYPE_IFINDEX:
68 /* If the resolving route is an interface route,
69 * it means the gateway we are looking up is connected
70 * to that interface. (The actual network is _not_ onlink).
71 * Therefore, the resolved route should have the original
72 * gateway as nexthop as it is directly connected.
73 *
74 * On Linux, we have to set the onlink netlink flag because
75 * otherwise, the kernel won't accept the route.
76 */
77 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
78 if (afi == AFI_IP) {
79 resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
80 resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
81 } else if (afi == AFI_IP6) {
82 resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
83 resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
84 }
85 resolved_hop->ifindex = newhop->ifindex;
86 break;
87 case NEXTHOP_TYPE_BLACKHOLE:
88 resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
89 resolved_hop->bh_type = nexthop->bh_type;
90 break;
91 }
92
93 if (newhop->flags & NEXTHOP_FLAG_ONLINK)
94 resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
95
96 /* Copy labels of the resolved route */
97 if (newhop->nh_label)
98 nexthop_add_labels(resolved_hop, newhop->nh_label_type,
99 newhop->nh_label->num_labels,
100 &newhop->nh_label->label[0]);
101
102 resolved_hop->rparent = nexthop;
103 nexthop_add(&nexthop->resolved, resolved_hop);
104 }
105
106 /*
107 * Given a nexthop we need to properly recursively resolve
108 * the route. As such, do a table lookup to find and match
109 * if at all possible. Set the nexthop->ifindex as appropriate
110 */
111 static int nexthop_active(afi_t afi, struct route_entry *re,
112 struct nexthop *nexthop, struct route_node *top)
113 {
114 struct prefix p;
115 struct route_table *table;
116 struct route_node *rn;
117 struct route_entry *match = NULL;
118 int resolved;
119 struct nexthop *newhop;
120 struct interface *ifp;
121 rib_dest_t *dest;
122
123 if ((nexthop->type == NEXTHOP_TYPE_IPV4)
124 || nexthop->type == NEXTHOP_TYPE_IPV6)
125 nexthop->ifindex = 0;
126
127 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
128 nexthops_free(nexthop->resolved);
129 nexthop->resolved = NULL;
130 re->nexthop_mtu = 0;
131
132 /*
133 * If the kernel has sent us a route, then
134 * by golly gee whiz it's a good route.
135 */
136 if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_SYSTEM)
137 return 1;
138
139 /*
140 * Check to see if we should trust the passed in information
141 * for UNNUMBERED interfaces as that we won't find the GW
142 * address in the routing table.
143 * This check should suffice to handle IPv4 or IPv6 routes
144 * sourced from EVPN routes which are installed with the
145 * next hop as the remote VTEP IP.
146 */
147 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
148 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
149 if (!ifp) {
150 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
151 zlog_debug(
152 "\t%s: Onlink and interface: %u[%u] does not exist",
153 __PRETTY_FUNCTION__, nexthop->ifindex,
154 nexthop->vrf_id);
155 return 0;
156 }
157 if (connected_is_unnumbered(ifp)) {
158 if (if_is_operative(ifp))
159 return 1;
160 else {
161 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
162 zlog_debug(
163 "\t%s: Onlink and interface %s is not operative",
164 __PRETTY_FUNCTION__, ifp->name);
165 return 0;
166 }
167 }
168 if (!if_is_operative(ifp)) {
169 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
170 zlog_debug(
171 "\t%s: Interface %s is not unnumbered",
172 __PRETTY_FUNCTION__, ifp->name);
173 return 0;
174 }
175 }
176
177 /* Make lookup prefix. */
178 memset(&p, 0, sizeof(struct prefix));
179 switch (afi) {
180 case AFI_IP:
181 p.family = AF_INET;
182 p.prefixlen = IPV4_MAX_PREFIXLEN;
183 p.u.prefix4 = nexthop->gate.ipv4;
184 break;
185 case AFI_IP6:
186 p.family = AF_INET6;
187 p.prefixlen = IPV6_MAX_PREFIXLEN;
188 p.u.prefix6 = nexthop->gate.ipv6;
189 break;
190 default:
191 assert(afi != AFI_IP && afi != AFI_IP6);
192 break;
193 }
194 /* Lookup table. */
195 table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
196 if (!table) {
197 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
198 zlog_debug("\t%s: Table not found",
199 __PRETTY_FUNCTION__);
200 return 0;
201 }
202
203 rn = route_node_match(table, (struct prefix *)&p);
204 while (rn) {
205 route_unlock_node(rn);
206
207 /* Lookup should halt if we've matched against ourselves ('top',
208 * if specified) - i.e., we cannot have a nexthop NH1 is
209 * resolved by a route NH1. The exception is if the route is a
210 * host route.
211 */
212 if (top && rn == top)
213 if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
214 || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
215 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
216 zlog_debug(
217 "\t%s: Matched against ourself and prefix length is not max bit length",
218 __PRETTY_FUNCTION__);
219 return 0;
220 }
221
222 /* Pick up selected route. */
223 /* However, do not resolve over default route unless explicitly
224 * allowed. */
225 if (is_default_prefix(&rn->p)
226 && !rnh_resolve_via_default(p.family)) {
227 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
228 zlog_debug(
229 "\t:%s: Resolved against default route",
230 __PRETTY_FUNCTION__);
231 return 0;
232 }
233
234 dest = rib_dest_from_rnode(rn);
235 if (dest && dest->selected_fib
236 && !CHECK_FLAG(dest->selected_fib->status,
237 ROUTE_ENTRY_REMOVED)
238 && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
239 match = dest->selected_fib;
240
241 /* If there is no selected route or matched route is EGP, go up
242 tree. */
243 if (!match) {
244 do {
245 rn = rn->parent;
246 } while (rn && rn->info == NULL);
247 if (rn)
248 route_lock_node(rn);
249
250 continue;
251 }
252
253 if (match->type == ZEBRA_ROUTE_CONNECT) {
254 /* Directly point connected route. */
255 newhop = match->ng.nexthop;
256 if (newhop) {
257 if (nexthop->type == NEXTHOP_TYPE_IPV4
258 || nexthop->type == NEXTHOP_TYPE_IPV6)
259 nexthop->ifindex = newhop->ifindex;
260 }
261 return 1;
262 } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
263 resolved = 0;
264 for (ALL_NEXTHOPS(match->ng, newhop)) {
265 if (!CHECK_FLAG(match->status,
266 ROUTE_ENTRY_INSTALLED))
267 continue;
268 if (CHECK_FLAG(newhop->flags,
269 NEXTHOP_FLAG_RECURSIVE))
270 continue;
271
272 SET_FLAG(nexthop->flags,
273 NEXTHOP_FLAG_RECURSIVE);
274 SET_FLAG(re->status,
275 ROUTE_ENTRY_NEXTHOPS_CHANGED);
276 nexthop_set_resolved(afi, newhop, nexthop);
277 resolved = 1;
278 }
279 if (resolved)
280 re->nexthop_mtu = match->mtu;
281 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
282 zlog_debug("\t%s: Recursion failed to find",
283 __PRETTY_FUNCTION__);
284 return resolved;
285 } else if (re->type == ZEBRA_ROUTE_STATIC) {
286 resolved = 0;
287 for (ALL_NEXTHOPS(match->ng, newhop)) {
288 if (!CHECK_FLAG(match->status,
289 ROUTE_ENTRY_INSTALLED))
290 continue;
291 if (CHECK_FLAG(newhop->flags,
292 NEXTHOP_FLAG_RECURSIVE))
293 continue;
294
295 SET_FLAG(nexthop->flags,
296 NEXTHOP_FLAG_RECURSIVE);
297 nexthop_set_resolved(afi, newhop, nexthop);
298 resolved = 1;
299 }
300 if (resolved)
301 re->nexthop_mtu = match->mtu;
302
303 if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
304 zlog_debug(
305 "\t%s: Static route unable to resolve",
306 __PRETTY_FUNCTION__);
307 return resolved;
308 } else {
309 if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
310 zlog_debug(
311 "\t%s: Route Type %s has not turned on recursion",
312 __PRETTY_FUNCTION__,
313 zebra_route_string(re->type));
314 if (re->type == ZEBRA_ROUTE_BGP
315 && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
316 zlog_debug(
317 "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
318 }
319 return 0;
320 }
321 }
322 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
323 zlog_debug("\t%s: Nexthop did not lookup in table",
324 __PRETTY_FUNCTION__);
325 return 0;
326 }
327
328 /* This function verifies reachability of one given nexthop, which can be
329 * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
330 * in nexthop->flags field. The nexthop->ifindex will be updated
331 * appropriately as well. An existing route map can turn
332 * (otherwise active) nexthop into inactive, but not vice versa.
333 *
334 * The return value is the final value of 'ACTIVE' flag.
335 */
336 static unsigned nexthop_active_check(struct route_node *rn,
337 struct route_entry *re,
338 struct nexthop *nexthop)
339 {
340 struct interface *ifp;
341 route_map_result_t ret = RMAP_PERMITMATCH;
342 int family;
343 char buf[SRCDEST2STR_BUFFER];
344 const struct prefix *p, *src_p;
345 struct zebra_vrf *zvrf;
346
347 srcdest_rnode_prefixes(rn, &p, &src_p);
348
349 if (rn->p.family == AF_INET)
350 family = AFI_IP;
351 else if (rn->p.family == AF_INET6)
352 family = AFI_IP6;
353 else
354 family = 0;
355 switch (nexthop->type) {
356 case NEXTHOP_TYPE_IFINDEX:
357 ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
358 if (ifp && if_is_operative(ifp))
359 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
360 else
361 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
362 break;
363 case NEXTHOP_TYPE_IPV4:
364 case NEXTHOP_TYPE_IPV4_IFINDEX:
365 family = AFI_IP;
366 if (nexthop_active(AFI_IP, re, nexthop, rn))
367 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
368 else
369 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
370 break;
371 case NEXTHOP_TYPE_IPV6:
372 family = AFI_IP6;
373 if (nexthop_active(AFI_IP6, re, nexthop, rn))
374 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
375 else
376 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
377 break;
378 case NEXTHOP_TYPE_IPV6_IFINDEX:
379 /* RFC 5549, v4 prefix with v6 NH */
380 if (rn->p.family != AF_INET)
381 family = AFI_IP6;
382 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
383 ifp = if_lookup_by_index(nexthop->ifindex,
384 nexthop->vrf_id);
385 if (ifp && if_is_operative(ifp))
386 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
387 else
388 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
389 } else {
390 if (nexthop_active(AFI_IP6, re, nexthop, rn))
391 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
392 else
393 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
394 }
395 break;
396 case NEXTHOP_TYPE_BLACKHOLE:
397 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
398 break;
399 default:
400 break;
401 }
402 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
403 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
404 zlog_debug("\t%s: Unable to find a active nexthop",
405 __PRETTY_FUNCTION__);
406 return 0;
407 }
408
409 /* XXX: What exactly do those checks do? Do we support
410 * e.g. IPv4 routes with IPv6 nexthops or vice versa?
411 */
412 if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
413 || (family == AFI_IP6 && p->family != AF_INET6))
414 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
415
416 /* The original code didn't determine the family correctly
417 * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
418 * from the rib_table_info in those cases.
419 * Possibly it may be better to use only the rib_table_info
420 * in every case.
421 */
422 if (!family) {
423 rib_table_info_t *info;
424
425 info = srcdest_rnode_table_info(rn);
426 family = info->afi;
427 }
428
429 memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
430
431 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
432 if (!zvrf) {
433 if (IS_ZEBRA_DEBUG_RIB_DETAILED)
434 zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
435 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
436 }
437
438 /* It'll get set if required inside */
439 ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
440 zvrf, re->tag);
441 if (ret == RMAP_DENYMATCH) {
442 if (IS_ZEBRA_DEBUG_RIB) {
443 srcdest_rnode2str(rn, buf, sizeof(buf));
444 zlog_debug(
445 "%u:%s: Filtering out with NH out %s due to route map",
446 re->vrf_id, buf,
447 ifindex2ifname(nexthop->ifindex,
448 nexthop->vrf_id));
449 }
450 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
451 }
452 return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
453 }
454
455 /*
456 * Iterate over all nexthops of the given RIB entry and refresh their
457 * ACTIVE flag. re->nexthop_active_num is updated accordingly. If any
458 * nexthop is found to toggle the ACTIVE flag, the whole re structure
459 * is flagged with ROUTE_ENTRY_CHANGED.
460 *
461 * Return value is the new number of active nexthops.
462 */
463 int nexthop_active_update(struct route_node *rn, struct route_entry *re)
464 {
465 struct nexthop *nexthop;
466 union g_addr prev_src;
467 unsigned int prev_active, new_active;
468 ifindex_t prev_index;
469
470 re->nexthop_active_num = 0;
471 UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
472
473 for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
474 /* No protocol daemon provides src and so we're skipping
475 * tracking it */
476 prev_src = nexthop->rmap_src;
477 prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
478 prev_index = nexthop->ifindex;
479 /*
480 * We need to respect the multipath_num here
481 * as that what we should be able to install from
482 * a multipath perpsective should not be a data plane
483 * decision point.
484 */
485 new_active = nexthop_active_check(rn, re, nexthop);
486 if (new_active
487 && re->nexthop_active_num >= zrouter.multipath_num) {
488 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
489 new_active = 0;
490 }
491 if (new_active)
492 re->nexthop_active_num++;
493 /* Don't allow src setting on IPv6 addr for now */
494 if (prev_active != new_active || prev_index != nexthop->ifindex
495 || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
496 && nexthop->type < NEXTHOP_TYPE_IPV6)
497 && prev_src.ipv4.s_addr
498 != nexthop->rmap_src.ipv4.s_addr)
499 || ((nexthop->type >= NEXTHOP_TYPE_IPV6
500 && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
501 && !(IPV6_ADDR_SAME(&prev_src.ipv6,
502 &nexthop->rmap_src.ipv6)))
503 || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) {
504 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
505 SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
506 }
507 }
508
509 return re->nexthop_active_num;
510 }
511