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