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