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