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