]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_static.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / zebra / zebra_static.c
CommitLineData
28f6dde8
DS
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 *
896014f4
DL
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
28f6dde8
DS
21 */
22#include <zebra.h>
23
24#include <lib/nexthop.h>
25#include <lib/memory.h>
c423229b 26#include <lib/srcdest_table.h>
28f6dde8 27
82f97584 28#include "vty.h"
28f6dde8
DS
29#include "zebra/debug.h"
30#include "zebra/rib.h"
31#include "zebra/zserv.h"
32#include "zebra/zebra_vrf.h"
33#include "zebra/zebra_static.h"
34#include "zebra/zebra_rnh.h"
35#include "zebra/redistribute.h"
4a1ab8e4 36#include "zebra/zebra_memory.h"
28f6dde8
DS
37
38/* Install static route into rib. */
39void
c423229b
CF
40static_install_route (afi_t afi, safi_t safi, struct prefix *p,
41 struct prefix_ipv6 *src_p, struct static_route *si)
28f6dde8
DS
42{
43 struct rib *rib;
44 struct route_node *rn;
45 struct route_table *table;
46 struct prefix nh_p;
c0f4be83 47 struct nexthop *nexthop = NULL;
28f6dde8
DS
48
49 /* Lookup table. */
50 table = zebra_vrf_table (afi, safi, si->vrf_id);
51 if (! table)
52 return;
53
4b2792b5
DS
54 memset (&nh_p, 0, sizeof (nh_p));
55
28f6dde8 56 /* Lookup existing route */
c423229b 57 rn = srcdest_rnode_get (table, p, src_p);
28f6dde8
DS
58 RNODE_FOREACH_RIB (rn, rib)
59 {
60 if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
61 continue;
62
63 if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
64 break;
65 }
66
67 if (rib)
68 {
69 /* if tag value changed , update old value in RIB */
70 if (rib->tag != si->tag)
71 rib->tag = si->tag;
72
73 /* Same distance static route is there. Update it with new
74 nexthop. */
75 route_unlock_node (rn);
76 switch (si->type)
77 {
78 case STATIC_IPV4_GATEWAY:
c0f4be83 79 nexthop = rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
28f6dde8
DS
80 nh_p.family = AF_INET;
81 nh_p.prefixlen = IPV4_MAX_BITLEN;
82 nh_p.u.prefix4 = si->addr.ipv4;
83 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
84 break;
85 case STATIC_IFINDEX:
c0f4be83 86 nexthop = rib_nexthop_ifindex_add (rib, si->ifindex);
28f6dde8 87 break;
882261e1 88 case STATIC_BLACKHOLE:
c0f4be83 89 nexthop = rib_nexthop_blackhole_add (rib);
28f6dde8
DS
90 break;
91 case STATIC_IPV6_GATEWAY:
c0f4be83 92 nexthop = rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
28f6dde8
DS
93 nh_p.family = AF_INET6;
94 nh_p.prefixlen = IPV6_MAX_BITLEN;
95 nh_p.u.prefix6 = si->addr.ipv6;
96 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
97 break;
98 case STATIC_IPV6_GATEWAY_IFINDEX:
c0f4be83 99 nexthop = rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6,
100 si->ifindex);
28f6dde8
DS
101 break;
102 }
c0f4be83 103 /* Update label(s), if present. */
104 if (si->snh_label.num_labels)
ce549947 105 nexthop_add_labels (nexthop, ZEBRA_LSP_STATIC, si->snh_label.num_labels,
c0f4be83 106 &si->snh_label.label[0]);
28f6dde8
DS
107
108 if (IS_ZEBRA_DEBUG_RIB)
109 {
110 char buf[INET6_ADDRSTRLEN];
111 if (IS_ZEBRA_DEBUG_RIB)
112 {
113 inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
114 zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
115 si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
116 }
117 }
118 /* Schedule route for processing or invoke NHT, as appropriate. */
119 if (si->type == STATIC_IPV4_GATEWAY ||
120 si->type == STATIC_IPV6_GATEWAY)
121 zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p);
122 else
123 rib_queue_add (rn);
124 }
125 else
126 {
127 /* This is new static route. */
128 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
129
130 rib->type = ZEBRA_ROUTE_STATIC;
131 rib->instance = 0;
132 rib->distance = si->distance;
133 rib->metric = 0;
134 rib->mtu = 0;
135 rib->vrf_id = si->vrf_id;
5f3d1bdf 136 rib->table = si->vrf_id ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id : zebrad.rtm_table_default;
28f6dde8
DS
137 rib->nexthop_num = 0;
138 rib->tag = si->tag;
139
140 switch (si->type)
141 {
142 case STATIC_IPV4_GATEWAY:
c0f4be83 143 nexthop = rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
28f6dde8
DS
144 nh_p.family = AF_INET;
145 nh_p.prefixlen = IPV4_MAX_BITLEN;
146 nh_p.u.prefix4 = si->addr.ipv4;
147 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
148 break;
149 case STATIC_IFINDEX:
c0f4be83 150 nexthop = rib_nexthop_ifindex_add (rib, si->ifindex);
28f6dde8 151 break;
882261e1 152 case STATIC_BLACKHOLE:
c0f4be83 153 nexthop = rib_nexthop_blackhole_add (rib);
28f6dde8
DS
154 break;
155 case STATIC_IPV6_GATEWAY:
c0f4be83 156 nexthop = rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
28f6dde8
DS
157 nh_p.family = AF_INET6;
158 nh_p.prefixlen = IPV6_MAX_BITLEN;
159 nh_p.u.prefix6 = si->addr.ipv6;
160 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
161 break;
162 case STATIC_IPV6_GATEWAY_IFINDEX:
c0f4be83 163 nexthop = rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6,
164 si->ifindex);
28f6dde8
DS
165 break;
166 }
c0f4be83 167 /* Update label(s), if present. */
168 if (si->snh_label.num_labels)
ce549947 169 nexthop_add_labels (nexthop, ZEBRA_LSP_STATIC, si->snh_label.num_labels,
c0f4be83 170 &si->snh_label.label[0]);
28f6dde8
DS
171
172 /* Save the flags of this static routes (reject, blackhole) */
173 rib->flags = si->flags;
174
175 if (IS_ZEBRA_DEBUG_RIB)
176 {
177 char buf[INET6_ADDRSTRLEN];
178 if (IS_ZEBRA_DEBUG_RIB)
179 {
180 inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
181 zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d)",
182 si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
183 }
184 }
185 /* Link this rib to the tree. Schedule for processing or invoke NHT,
186 * as appropriate.
187 */
188 if (si->type == STATIC_IPV4_GATEWAY ||
189 si->type == STATIC_IPV6_GATEWAY)
190 {
191 rib_addnode (rn, rib, 0);
192 zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p);
193 }
194 else
195 rib_addnode (rn, rib, 1);
196 }
197}
a22f3f5d 198
28f6dde8
DS
199static int
200static_nexthop_same (struct nexthop *nexthop, struct static_route *si)
201{
c0f4be83 202 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
882261e1 203 && si->type == STATIC_BLACKHOLE)
c0f4be83 204 return 1;
205
28f6dde8
DS
206 if (nexthop->type == NEXTHOP_TYPE_IPV4
207 && si->type == STATIC_IPV4_GATEWAY
208 && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4))
9c934a18 209 return 1;
c0f4be83 210 else if (nexthop->type == NEXTHOP_TYPE_IFINDEX
28f6dde8
DS
211 && si->type == STATIC_IFINDEX
212 && nexthop->ifindex == si->ifindex)
9c934a18 213 return 1;
c0f4be83 214 else if (nexthop->type == NEXTHOP_TYPE_IPV6
28f6dde8
DS
215 && si->type == STATIC_IPV6_GATEWAY
216 && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6))
9c934a18 217 return 1;
c0f4be83 218 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
28f6dde8
DS
219 && si->type == STATIC_IPV6_GATEWAY_IFINDEX
220 && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)
221 && nexthop->ifindex == si->ifindex)
9c934a18 222 return 1;
c0f4be83 223
28f6dde8
DS
224 return 0;
225}
226
227/* Uninstall static route from RIB. */
228void
c423229b
CF
229static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p,
230 struct prefix_ipv6 *src_p, struct static_route *si)
28f6dde8
DS
231{
232 struct route_node *rn;
233 struct rib *rib;
234 struct nexthop *nexthop;
235 struct route_table *table;
236 struct prefix nh_p;
237
238 /* Lookup table. */
239 table = zebra_vrf_table (afi, safi, si->vrf_id);
240 if (! table)
241 return;
242
243 /* Lookup existing route with type and distance. */
c423229b 244 rn = srcdest_rnode_lookup (table, p, src_p);
28f6dde8
DS
245 if (! rn)
246 return;
247
248 RNODE_FOREACH_RIB (rn, rib)
249 {
250 if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
251 continue;
252
253 if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance &&
254 rib->tag == si->tag)
255 break;
256 }
257
258 if (! rib)
259 {
260 route_unlock_node (rn);
261 return;
262 }
263
264 /* Lookup nexthop. */
265 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
266 if (static_nexthop_same (nexthop, si))
267 break;
268
269 /* Can't find nexthop. */
270 if (! nexthop)
271 {
272 route_unlock_node (rn);
273 return;
274 }
275
276 /* Check nexthop. */
277 if (rib->nexthop_num == 1)
278 rib_delnode (rn, rib);
279 else
280 {
281 /* Mark this nexthop as inactive and reinstall the route. Then, delete
282 * the nexthop. There is no need to re-evaluate the route for this
283 * scenario.
284 */
285 if (IS_ZEBRA_DEBUG_RIB)
286 {
287 char buf[INET6_ADDRSTRLEN];
288 if (IS_ZEBRA_DEBUG_RIB)
289 {
290 inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
291 zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
292 si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
293 }
294 }
295 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
296 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
297 {
298 /* If there are other active nexthops, do an update. */
299 if (rib->nexthop_active_num > 1)
300 {
446bb95e
TT
301 /* Update route in kernel if it's in fib */
302 if (CHECK_FLAG(rib->status, RIB_ENTRY_SELECTED_FIB))
949ae9ba 303 rib_install_kernel (rn, rib, rib);
446bb95e
TT
304 /* Update redistribution if it's selected */
305 if (CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED))
c423229b 306 redistribute_update (p, (struct prefix*)src_p, rib, NULL);
28f6dde8
DS
307 }
308 else
309 {
446bb95e
TT
310 /* Remove from redistribute if selected route becomes inactive */
311 if (CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED))
c423229b 312 redistribute_delete (p, (struct prefix*)src_p, rib);
446bb95e
TT
313 /* Remove from kernel if fib route becomes inactive */
314 if (CHECK_FLAG(rib->status, RIB_ENTRY_SELECTED_FIB))
28f6dde8
DS
315 rib_uninstall_kernel (rn, rib);
316 }
317 }
318
319 if (afi == AFI_IP)
320 {
321 /* Delete the nexthop and dereg from NHT */
322 nh_p.family = AF_INET;
323 nh_p.prefixlen = IPV4_MAX_BITLEN;
324 nh_p.u.prefix4 = nexthop->gate.ipv4;
325 }
326 else
327 {
328 nh_p.family = AF_INET6;
329 nh_p.prefixlen = IPV6_MAX_BITLEN;
330 nh_p.u.prefix6 = nexthop->gate.ipv6;
331 }
332 rib_nexthop_delete (rib, nexthop);
333 zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn);
334 nexthop_free (nexthop);
335 }
336 /* Unlock node. */
337 route_unlock_node (rn);
338}
339
340int
3a3d00f1 341static_add_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
c423229b 342 struct prefix_ipv6 *src_p,
3a3d00f1 343 union g_addr *gate, ifindex_t ifindex,
dc9ffce8 344 const char *ifname, u_char flags, route_tag_t tag,
a22f3f5d 345 u_char distance, struct zebra_vrf *zvrf,
346 struct static_nh_label *snh_label)
28f6dde8 347{
28f6dde8
DS
348 struct route_node *rn;
349 struct static_route *si;
350 struct static_route *pp;
351 struct static_route *cp;
352 struct static_route *update = NULL;
3a3d00f1 353 struct route_table *stable = zvrf->stable[afi][safi];
28f6dde8
DS
354
355 if (! stable)
356 return -1;
357
3a3d00f1
DS
358 if (!gate &&
359 (type == STATIC_IPV4_GATEWAY ||
360 type == STATIC_IPV6_GATEWAY ||
361 type == STATIC_IPV6_GATEWAY_IFINDEX))
362 return -1;
363
364 if (!ifindex &&
365 (type == STATIC_IFINDEX ||
366 type == STATIC_IPV6_GATEWAY_IFINDEX))
367 return -1;
368
28f6dde8 369 /* Lookup static route prefix. */
c423229b 370 rn = srcdest_rnode_get (stable, p, src_p);
28f6dde8 371
28f6dde8
DS
372 /* Do nothing if there is a same static route. */
373 for (si = rn->info; si; si = si->next)
374 {
375 if (type == si->type
3a3d00f1
DS
376 && (! gate ||
377 ((afi == AFI_IP && IPV4_ADDR_SAME (gate, &si->addr.ipv4)) ||
378 (afi == AFI_IP6 && IPV6_ADDR_SAME (gate, &si->addr.ipv6))))
28f6dde8
DS
379 && (! ifindex || ifindex == si->ifindex))
380 {
a22f3f5d 381 if ((distance == si->distance) && (tag == si->tag) &&
45cc0c76
QY
382 !memcmp (&si->snh_label, snh_label, sizeof (struct static_nh_label)) &&
383 si->flags == flags)
28f6dde8
DS
384 {
385 route_unlock_node (rn);
386 return 0;
387 }
388 else
389 update = si;
390 }
391 }
392
a22f3f5d 393 /* Distance or tag or label changed, delete existing first. */
28f6dde8 394 if (update)
c423229b 395 static_delete_route (afi, safi, type, p, src_p, gate, ifindex, update->tag,
a22f3f5d 396 update->distance, zvrf, &update->snh_label);
28f6dde8
DS
397
398 /* Make new static route structure. */
399 si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
400
401 si->type = type;
402 si->distance = distance;
403 si->flags = flags;
404 si->tag = tag;
661512bf 405 si->vrf_id = zvrf_id (zvrf);
28f6dde8
DS
406 si->ifindex = ifindex;
407 if (si->ifindex)
408 strcpy(si->ifname, ifname);
409
3a3d00f1
DS
410 switch (type)
411 {
412 case STATIC_IPV4_GATEWAY:
413 si->addr.ipv4 = gate->ipv4;
414 break;
415 case STATIC_IPV6_GATEWAY:
416 si->addr.ipv6 = gate->ipv6;
417 break;
418 case STATIC_IPV6_GATEWAY_IFINDEX:
419 si->addr.ipv6 = gate->ipv6;
420 break;
421 case STATIC_IFINDEX:
422 break;
423 }
28f6dde8 424
a22f3f5d 425 /* Save labels, if any. */
426 memcpy (&si->snh_label, snh_label, sizeof (struct static_nh_label));
427
28f6dde8
DS
428 /* Add new static route information to the tree with sort by
429 distance value and gateway address. */
430 for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
431 {
432 if (si->distance < cp->distance)
433 break;
434 if (si->distance > cp->distance)
435 continue;
436 if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
437 {
438 if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr))
439 break;
440 if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr))
441 continue;
442 }
443 }
444
445 /* Make linked list. */
446 if (pp)
447 pp->next = si;
448 else
449 rn->info = si;
450 if (cp)
451 cp->prev = si;
452 si->prev = pp;
453 si->next = cp;
454
455 /* Install into rib. */
c423229b 456 static_install_route (afi, safi, p, src_p, si);
28f6dde8
DS
457
458 return 1;
459}
460
461int
c7cfcb75 462static_delete_route (afi_t afi, safi_t safi, u_char type, struct prefix *p,
c423229b 463 struct prefix_ipv6 *src_p,
c7cfcb75 464 union g_addr *gate, ifindex_t ifindex,
dc9ffce8 465 route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
a22f3f5d 466 struct static_nh_label *snh_label)
28f6dde8 467{
28f6dde8
DS
468 struct route_node *rn;
469 struct static_route *si;
470 struct route_table *stable;
471
472 /* Lookup table. */
c7cfcb75 473 stable = zebra_vrf_static_table (afi, safi, zvrf);
28f6dde8
DS
474 if (! stable)
475 return -1;
476
477 /* Lookup static route prefix. */
c423229b 478 rn = srcdest_rnode_lookup (stable, p, src_p);
28f6dde8
DS
479 if (! rn)
480 return 0;
481
28f6dde8
DS
482 /* Find same static route is the tree */
483 for (si = rn->info; si; si = si->next)
484 if (type == si->type
c7cfcb75
DS
485 && (! gate || (
486 (afi == AFI_IP && IPV4_ADDR_SAME (gate, &si->addr.ipv4)) ||
487 (afi == AFI_IP6 && IPV6_ADDR_SAME (gate, &si->addr.ipv6))))
28f6dde8 488 && (! ifindex || ifindex == si->ifindex)
a22f3f5d 489 && (! tag || (tag == si->tag))
490 && (! snh_label->num_labels ||
491 !memcmp (&si->snh_label, snh_label, sizeof (struct static_nh_label))))
28f6dde8
DS
492 break;
493
494 /* Can't find static route. */
495 if (! si)
496 {
497 route_unlock_node (rn);
498 return 0;
499 }
500
501 /* Install into rib. */
c423229b 502 static_uninstall_route (afi, safi, p, src_p, si);
28f6dde8
DS
503
504 /* Unlink static route from linked list. */
505 if (si->prev)
506 si->prev->next = si->next;
507 else
508 rn->info = si->next;
509 if (si->next)
510 si->next->prev = si->prev;
511 route_unlock_node (rn);
512
513 /* Free static route configuration. */
514 XFREE (MTYPE_STATIC_ROUTE, si);
515
516 route_unlock_node (rn);
517
518 return 1;
519}