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