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