]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_static.c
doc: manually finish conversion
[mirror_frr.git] / zebra / zebra_static.c
1 /*
2 * Static Routing Information code
3 * Copyright (C) 2016 Cumulus Networks
4 * Donald Sharp
5 *
6 * This file is part of Quagga.
7 *
8 * Quagga 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 * Quagga 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 along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 #include <zebra.h>
23
24 #include <lib/nexthop.h>
25 #include <lib/memory.h>
26 #include <lib/srcdest_table.h>
27 #include <lib/if.h>
28
29 #include "vty.h"
30 #include "zebra/debug.h"
31 #include "zebra/rib.h"
32 #include "zebra/zserv.h"
33 #include "zebra/zebra_vrf.h"
34 #include "zebra/zebra_static.h"
35 #include "zebra/zebra_rnh.h"
36 #include "zebra/redistribute.h"
37 #include "zebra/zebra_memory.h"
38
39 /* Install static route into rib. */
40 void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
41 struct prefix_ipv6 *src_p, struct static_route *si)
42 {
43 struct route_entry *re;
44 struct route_node *rn;
45 struct route_table *table;
46 struct prefix nh_p;
47 struct nexthop *nexthop = NULL;
48 enum blackhole_type bh_type = 0;
49
50 /* Lookup table. */
51 table = zebra_vrf_table(afi, safi, si->vrf_id);
52 if (!table)
53 return;
54
55 memset(&nh_p, 0, sizeof(nh_p));
56 if (si->type == STATIC_BLACKHOLE) {
57 switch (si->bh_type) {
58 case STATIC_BLACKHOLE_DROP:
59 case STATIC_BLACKHOLE_NULL:
60 bh_type = BLACKHOLE_NULL;
61 break;
62 case STATIC_BLACKHOLE_REJECT:
63 bh_type = BLACKHOLE_REJECT;
64 break;
65 }
66 }
67
68 /* Lookup existing route */
69 rn = srcdest_rnode_get(table, p, src_p);
70 RNODE_FOREACH_RE (rn, re) {
71 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
72 continue;
73
74 if (re->type == ZEBRA_ROUTE_STATIC
75 && re->distance == si->distance)
76 break;
77 }
78
79 if (re) {
80 /* if tag value changed , update old value in RIB */
81 if (re->tag != si->tag)
82 re->tag = si->tag;
83
84 /* Same distance static route is there. Update it with new
85 nexthop. */
86 route_unlock_node(rn);
87 switch (si->type) {
88 case STATIC_IPV4_GATEWAY:
89 nexthop = route_entry_nexthop_ipv4_add(
90 re, &si->addr.ipv4, NULL);
91 nh_p.family = AF_INET;
92 nh_p.prefixlen = IPV4_MAX_BITLEN;
93 nh_p.u.prefix4 = si->addr.ipv4;
94 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
95 break;
96 case STATIC_IPV4_GATEWAY_IFNAME:
97 nexthop = route_entry_nexthop_ipv4_ifindex_add(
98 re, &si->addr.ipv4, NULL, si->ifindex);
99 break;
100 case STATIC_IFNAME:
101 nexthop = route_entry_nexthop_ifindex_add(re,
102 si->ifindex);
103 break;
104 case STATIC_BLACKHOLE:
105 nexthop = route_entry_nexthop_blackhole_add(
106 re, bh_type);
107 break;
108 case STATIC_IPV6_GATEWAY:
109 nexthop = route_entry_nexthop_ipv6_add(re,
110 &si->addr.ipv6);
111 nh_p.family = AF_INET6;
112 nh_p.prefixlen = IPV6_MAX_BITLEN;
113 nh_p.u.prefix6 = si->addr.ipv6;
114 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
115 break;
116 case STATIC_IPV6_GATEWAY_IFNAME:
117 nexthop = route_entry_nexthop_ipv6_ifindex_add(
118 re, &si->addr.ipv6, si->ifindex);
119 break;
120 }
121 /* Update label(s), if present. */
122 if (si->snh_label.num_labels)
123 nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC,
124 si->snh_label.num_labels,
125 &si->snh_label.label[0]);
126
127 if (IS_ZEBRA_DEBUG_RIB) {
128 char buf[INET6_ADDRSTRLEN];
129 if (IS_ZEBRA_DEBUG_RIB) {
130 inet_ntop(p->family, &p->u.prefix, buf,
131 INET6_ADDRSTRLEN);
132 zlog_debug(
133 "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
134 si->vrf_id, buf, p->prefixlen, rn, re,
135 re->type);
136 }
137 }
138
139 re->uptime = time(NULL);
140 /* Schedule route for processing or invoke NHT, as appropriate.
141 */
142 if (si->type == STATIC_IPV4_GATEWAY
143 || si->type == STATIC_IPV6_GATEWAY)
144 zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1,
145 RNH_NEXTHOP_TYPE, &nh_p);
146 else
147 rib_queue_add(rn);
148 } else {
149 /* This is new static route. */
150 re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
151
152 re->type = ZEBRA_ROUTE_STATIC;
153 re->instance = 0;
154 re->distance = si->distance;
155 re->metric = 0;
156 re->mtu = 0;
157 re->vrf_id = si->vrf_id;
158 re->table =
159 si->vrf_id
160 ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id
161 : zebrad.rtm_table_default;
162 re->nexthop_num = 0;
163 re->tag = si->tag;
164
165 switch (si->type) {
166 case STATIC_IPV4_GATEWAY:
167 nexthop = route_entry_nexthop_ipv4_add(
168 re, &si->addr.ipv4, NULL);
169 nh_p.family = AF_INET;
170 nh_p.prefixlen = IPV4_MAX_BITLEN;
171 nh_p.u.prefix4 = si->addr.ipv4;
172 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
173 break;
174 case STATIC_IPV4_GATEWAY_IFNAME:
175 nexthop = route_entry_nexthop_ipv4_ifindex_add(
176 re, &si->addr.ipv4, NULL, si->ifindex);
177 break;
178 case STATIC_IFNAME:
179 nexthop = route_entry_nexthop_ifindex_add(re,
180 si->ifindex);
181 break;
182 case STATIC_BLACKHOLE:
183 nexthop = route_entry_nexthop_blackhole_add(
184 re, bh_type);
185 break;
186 case STATIC_IPV6_GATEWAY:
187 nexthop = route_entry_nexthop_ipv6_add(re,
188 &si->addr.ipv6);
189 nh_p.family = AF_INET6;
190 nh_p.prefixlen = IPV6_MAX_BITLEN;
191 nh_p.u.prefix6 = si->addr.ipv6;
192 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
193 break;
194 case STATIC_IPV6_GATEWAY_IFNAME:
195 nexthop = route_entry_nexthop_ipv6_ifindex_add(
196 re, &si->addr.ipv6, si->ifindex);
197 break;
198 }
199 /* Update label(s), if present. */
200 if (si->snh_label.num_labels)
201 nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC,
202 si->snh_label.num_labels,
203 &si->snh_label.label[0]);
204
205 if (IS_ZEBRA_DEBUG_RIB) {
206 char buf[INET6_ADDRSTRLEN];
207 if (IS_ZEBRA_DEBUG_RIB) {
208 inet_ntop(p->family, &p->u.prefix, buf,
209 INET6_ADDRSTRLEN);
210 zlog_debug(
211 "%u:%s/%d: Inserting route rn %p, re %p (type %d)",
212 si->vrf_id, buf, p->prefixlen, rn, re,
213 re->type);
214 }
215 }
216 re->uptime = time(NULL);
217 /* Link this re to the tree. Schedule for processing or invoke
218 * NHT,
219 * as appropriate.
220 */
221 if (si->type == STATIC_IPV4_GATEWAY
222 || si->type == STATIC_IPV6_GATEWAY) {
223 rib_addnode(rn, re, 0);
224 zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1,
225 RNH_NEXTHOP_TYPE, &nh_p);
226 } else
227 rib_addnode(rn, re, 1);
228 }
229 }
230
231 /* this works correctly with IFNAME<>IFINDEX because a static route on a
232 * non-active interface will have IFINDEX_INTERNAL and thus compare false
233 */
234 static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si)
235 {
236 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
237 && si->type == STATIC_BLACKHOLE)
238 return 1;
239
240 if (nexthop->type == NEXTHOP_TYPE_IPV4
241 && si->type == STATIC_IPV4_GATEWAY
242 && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4))
243 return 1;
244 else if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
245 && si->type == STATIC_IPV4_GATEWAY_IFNAME
246 && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4)
247 && nexthop->ifindex == si->ifindex)
248 return 1;
249 else if (nexthop->type == NEXTHOP_TYPE_IFINDEX
250 && si->type == STATIC_IFNAME
251 && nexthop->ifindex == si->ifindex)
252 return 1;
253 else if (nexthop->type == NEXTHOP_TYPE_IPV6
254 && si->type == STATIC_IPV6_GATEWAY
255 && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6))
256 return 1;
257 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
258 && si->type == STATIC_IPV6_GATEWAY_IFNAME
259 && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6)
260 && nexthop->ifindex == si->ifindex)
261 return 1;
262
263 return 0;
264 }
265
266 /* Uninstall static route from RIB. */
267 void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
268 struct prefix_ipv6 *src_p, struct static_route *si)
269 {
270 struct route_node *rn;
271 struct route_entry *re;
272 struct nexthop *nexthop;
273 struct route_table *table;
274 struct prefix nh_p;
275
276 /* Lookup table. */
277 table = zebra_vrf_table(afi, safi, si->vrf_id);
278 if (!table)
279 return;
280
281 /* Lookup existing route with type and distance. */
282 rn = srcdest_rnode_lookup(table, p, src_p);
283 if (!rn)
284 return;
285
286 RNODE_FOREACH_RE (rn, re) {
287 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
288 continue;
289
290 if (re->type == ZEBRA_ROUTE_STATIC
291 && re->distance == si->distance && re->tag == si->tag)
292 break;
293 }
294
295 if (!re) {
296 route_unlock_node(rn);
297 return;
298 }
299
300 /* Lookup nexthop. */
301 for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
302 if (static_nexthop_same(nexthop, si))
303 break;
304
305 /* Can't find nexthop. */
306 if (!nexthop) {
307 route_unlock_node(rn);
308 return;
309 }
310
311 /* Check nexthop. */
312 if (re->nexthop_num == 1)
313 rib_delnode(rn, re);
314 else {
315 /* Mark this nexthop as inactive and reinstall the route. Then,
316 * delete
317 * the nexthop. There is no need to re-evaluate the route for
318 * this
319 * scenario.
320 */
321 if (IS_ZEBRA_DEBUG_RIB) {
322 char buf[INET6_ADDRSTRLEN];
323 if (IS_ZEBRA_DEBUG_RIB) {
324 inet_ntop(p->family, &p->u.prefix, buf,
325 INET6_ADDRSTRLEN);
326 zlog_debug(
327 "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
328 si->vrf_id, buf, p->prefixlen, rn, re,
329 re->type);
330 }
331 }
332 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
333 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
334 /* If there are other active nexthops, do an update. */
335 if (re->nexthop_active_num > 1) {
336 /* Update route in kernel if it's in fib */
337 if (CHECK_FLAG(re->status,
338 ROUTE_ENTRY_SELECTED_FIB))
339 rib_install_kernel(rn, re, re);
340 /* Update redistribution if it's selected */
341 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
342 redistribute_update(
343 p, (struct prefix *)src_p, re,
344 NULL);
345 } else {
346 /* Remove from redistribute if selected route
347 * becomes inactive */
348 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
349 redistribute_delete(
350 p, (struct prefix *)src_p, re);
351 /* Remove from kernel if fib route becomes
352 * inactive */
353 if (CHECK_FLAG(re->status,
354 ROUTE_ENTRY_SELECTED_FIB))
355 rib_uninstall_kernel(rn, re);
356 }
357 }
358
359 if (afi == AFI_IP) {
360 /* Delete the nexthop and dereg from NHT */
361 nh_p.family = AF_INET;
362 nh_p.prefixlen = IPV4_MAX_BITLEN;
363 nh_p.u.prefix4 = nexthop->gate.ipv4;
364 } else {
365 nh_p.family = AF_INET6;
366 nh_p.prefixlen = IPV6_MAX_BITLEN;
367 nh_p.u.prefix6 = nexthop->gate.ipv6;
368 }
369 route_entry_nexthop_delete(re, nexthop);
370 zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn);
371 nexthop_free(nexthop);
372 }
373 /* Unlock node. */
374 route_unlock_node(rn);
375 }
376
377 int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
378 struct prefix_ipv6 *src_p, union g_addr *gate,
379 const char *ifname, enum static_blackhole_type bh_type,
380 route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
381 struct static_nh_label *snh_label)
382 {
383 struct route_node *rn;
384 struct static_route *si;
385 struct static_route *pp;
386 struct static_route *cp;
387 struct static_route *update = NULL;
388 struct route_table *stable = zvrf->stable[afi][safi];
389
390 if (!stable)
391 return -1;
392
393 if (!gate
394 && (type == STATIC_IPV4_GATEWAY
395 || type == STATIC_IPV4_GATEWAY_IFNAME
396 || type == STATIC_IPV6_GATEWAY
397 || type == STATIC_IPV6_GATEWAY_IFNAME))
398 return -1;
399
400 if (!ifname
401 && (type == STATIC_IFNAME
402 || type == STATIC_IPV4_GATEWAY_IFNAME
403 || type == STATIC_IPV6_GATEWAY_IFNAME))
404 return -1;
405
406 /* Lookup static route prefix. */
407 rn = srcdest_rnode_get(stable, p, src_p);
408
409 /* Do nothing if there is a same static route. */
410 for (si = rn->info; si; si = si->next) {
411 if (type == si->type
412 && (!gate || ((afi == AFI_IP
413 && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
414 || (afi == AFI_IP6
415 && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
416 && (!strcmp (ifname ? ifname : "", si->ifname))) {
417 if ((distance == si->distance) && (tag == si->tag)
418 && !memcmp(&si->snh_label, snh_label,
419 sizeof(struct static_nh_label))
420 && si->bh_type == bh_type) {
421 route_unlock_node(rn);
422 return 0;
423 } else
424 update = si;
425 }
426 }
427
428 /* Distance or tag or label changed, delete existing first. */
429 if (update)
430 static_delete_route(afi, safi, type, p, src_p, gate, ifname,
431 update->tag, update->distance, zvrf,
432 &update->snh_label);
433
434 /* Make new static route structure. */
435 si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route));
436
437 si->type = type;
438 si->distance = distance;
439 si->bh_type = bh_type;
440 si->tag = tag;
441 si->vrf_id = zvrf_id(zvrf);
442 if (ifname)
443 strlcpy(si->ifname, ifname, sizeof(si->ifname));
444 si->ifindex = IFINDEX_INTERNAL;
445
446 switch (type) {
447 case STATIC_IPV4_GATEWAY:
448 case STATIC_IPV4_GATEWAY_IFNAME:
449 si->addr.ipv4 = gate->ipv4;
450 break;
451 case STATIC_IPV6_GATEWAY:
452 case STATIC_IPV6_GATEWAY_IFNAME:
453 si->addr.ipv6 = gate->ipv6;
454 break;
455 case STATIC_IFNAME:
456 break;
457 }
458
459 /* Save labels, if any. */
460 memcpy(&si->snh_label, snh_label, sizeof(struct static_nh_label));
461
462 /* Add new static route information to the tree with sort by
463 distance value and gateway address. */
464 for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) {
465 if (si->distance < cp->distance)
466 break;
467 if (si->distance > cp->distance)
468 continue;
469 if (si->type == STATIC_IPV4_GATEWAY
470 && cp->type == STATIC_IPV4_GATEWAY) {
471 if (ntohl(si->addr.ipv4.s_addr)
472 < ntohl(cp->addr.ipv4.s_addr))
473 break;
474 if (ntohl(si->addr.ipv4.s_addr)
475 > ntohl(cp->addr.ipv4.s_addr))
476 continue;
477 }
478 }
479
480 /* Make linked list. */
481 if (pp)
482 pp->next = si;
483 else
484 rn->info = si;
485 if (cp)
486 cp->prev = si;
487 si->prev = pp;
488 si->next = cp;
489
490 /* check whether interface exists in system & install if it does */
491 if (!ifname)
492 static_install_route(afi, safi, p, src_p, si);
493 else {
494 struct interface *ifp;
495
496 ifp = if_lookup_by_name(ifname, zvrf_id(zvrf));
497 if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
498 si->ifindex = ifp->ifindex;
499 static_install_route(afi, safi, p, src_p, si);
500 }
501 }
502
503 return 1;
504 }
505
506 int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
507 struct prefix_ipv6 *src_p, union g_addr *gate,
508 const char *ifname, route_tag_t tag, u_char distance,
509 struct zebra_vrf *zvrf,
510 struct static_nh_label *snh_label)
511 {
512 struct route_node *rn;
513 struct static_route *si;
514 struct route_table *stable;
515
516 /* Lookup table. */
517 stable = zebra_vrf_static_table(afi, safi, zvrf);
518 if (!stable)
519 return -1;
520
521 /* Lookup static route prefix. */
522 rn = srcdest_rnode_lookup(stable, p, src_p);
523 if (!rn)
524 return 0;
525
526 /* Find same static route is the tree */
527 for (si = rn->info; si; si = si->next)
528 if (type == si->type
529 && (!gate || ((afi == AFI_IP
530 && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
531 || (afi == AFI_IP6
532 && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
533 && (!strcmp(ifname ? ifname : "", si->ifname))
534 && (!tag || (tag == si->tag))
535 && (!snh_label->num_labels
536 || !memcmp(&si->snh_label, snh_label,
537 sizeof(struct static_nh_label))))
538 break;
539
540 /* Can't find static route. */
541 if (!si) {
542 route_unlock_node(rn);
543 return 0;
544 }
545
546 /* Uninstall from rib. */
547 if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL)
548 static_uninstall_route(afi, safi, p, src_p, si);
549
550 /* Unlink static route from linked list. */
551 if (si->prev)
552 si->prev->next = si->next;
553 else
554 rn->info = si->next;
555 if (si->next)
556 si->next->prev = si->prev;
557 route_unlock_node(rn);
558
559 /* Free static route configuration. */
560 XFREE(MTYPE_STATIC_ROUTE, si);
561
562 route_unlock_node(rn);
563
564 return 1;
565 }
566
567 static void static_ifindex_update_af(struct interface *ifp, bool up,
568 afi_t afi, safi_t safi)
569 {
570 struct route_table *stable;
571 struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
572 struct route_node *rn;
573 struct static_route *si;
574 struct prefix *p, *src_pp;
575 struct prefix_ipv6 *src_p;
576
577 stable = zebra_vrf_static_table(afi, safi, zvrf);
578 if (!stable)
579 return;
580
581 for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
582 srcdest_rnode_prefixes(rn, &p, &src_pp);
583 src_p = (struct prefix_ipv6 *)src_pp;
584
585 for (si = rn->info; si; si = si->next) {
586 if (!si->ifname[0])
587 continue;
588 if (up) {
589 if (strcmp(si->ifname, ifp->name))
590 continue;
591 si->ifindex = ifp->ifindex;
592 static_install_route(afi, safi, p, src_p, si);
593 } else {
594 if (si->ifindex != ifp->ifindex)
595 continue;
596 static_uninstall_route(afi, safi, p, src_p,
597 si);
598 si->ifindex = IFINDEX_INTERNAL;
599 }
600 }
601 }
602 }
603
604 /* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
605 void static_ifindex_update(struct interface *ifp, bool up)
606 {
607 static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST);
608 static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST);
609 static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST);
610 static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
611 }