2 * Static Routing Information code
3 * Copyright (C) 2016 Cumulus Networks
6 * This file is part of Quagga.
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
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.
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
25 #include <lib/nexthop.h>
26 #include <lib/memory.h>
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"
36 /* Install static route into rib. */
38 static_install_route (afi_t afi
, safi_t safi
, struct prefix
*p
, struct static_route
*si
)
41 struct route_node
*rn
;
42 struct route_table
*table
;
46 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
50 /* Lookup existing route */
51 rn
= route_node_get (table
, p
);
52 RNODE_FOREACH_RIB (rn
, rib
)
54 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
57 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
)
63 /* if tag value changed , update old value in RIB */
64 if (rib
->tag
!= si
->tag
)
67 /* Same distance static route is there. Update it with new
69 route_unlock_node (rn
);
72 case STATIC_IPV4_GATEWAY
:
73 rib_nexthop_ipv4_add (rib
, &si
->addr
.ipv4
, NULL
);
74 nh_p
.family
= AF_INET
;
75 nh_p
.prefixlen
= IPV4_MAX_BITLEN
;
76 nh_p
.u
.prefix4
= si
->addr
.ipv4
;
77 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
80 rib_nexthop_ifindex_add (rib
, si
->ifindex
);
82 case STATIC_IPV4_BLACKHOLE
:
83 rib_nexthop_blackhole_add (rib
);
85 case STATIC_IPV6_GATEWAY
:
86 rib_nexthop_ipv6_add (rib
, &si
->addr
.ipv6
);
87 nh_p
.family
= AF_INET6
;
88 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
89 nh_p
.u
.prefix6
= si
->addr
.ipv6
;
90 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
92 case STATIC_IPV6_GATEWAY_IFINDEX
:
93 rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
, si
->ifindex
);
97 if (IS_ZEBRA_DEBUG_RIB
)
99 char buf
[INET6_ADDRSTRLEN
];
100 if (IS_ZEBRA_DEBUG_RIB
)
102 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, INET6_ADDRSTRLEN
);
103 zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
104 si
->vrf_id
, buf
, p
->prefixlen
, rn
, rib
, rib
->type
);
107 /* Schedule route for processing or invoke NHT, as appropriate. */
108 if (si
->type
== STATIC_IPV4_GATEWAY
||
109 si
->type
== STATIC_IPV6_GATEWAY
)
110 zebra_evaluate_rnh(si
->vrf_id
, nh_p
.family
, 1, RNH_NEXTHOP_TYPE
, &nh_p
);
116 /* This is new static route. */
117 rib
= XCALLOC (MTYPE_RIB
, sizeof (struct rib
));
119 rib
->type
= ZEBRA_ROUTE_STATIC
;
121 rib
->distance
= si
->distance
;
124 rib
->vrf_id
= si
->vrf_id
;
125 rib
->table
= si
->vrf_id
? (zebra_vrf_lookup(si
->vrf_id
))->table_id
: zebrad
.rtm_table_default
;
126 rib
->nexthop_num
= 0;
131 case STATIC_IPV4_GATEWAY
:
132 rib_nexthop_ipv4_add (rib
, &si
->addr
.ipv4
, NULL
);
133 nh_p
.family
= AF_INET
;
134 nh_p
.prefixlen
= IPV4_MAX_BITLEN
;
135 nh_p
.u
.prefix4
= si
->addr
.ipv4
;
136 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
139 rib_nexthop_ifindex_add (rib
, si
->ifindex
);
141 case STATIC_IPV4_BLACKHOLE
:
142 rib_nexthop_blackhole_add (rib
);
144 case STATIC_IPV6_GATEWAY
:
145 rib_nexthop_ipv6_add (rib
, &si
->addr
.ipv6
);
146 nh_p
.family
= AF_INET6
;
147 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
148 nh_p
.u
.prefix6
= si
->addr
.ipv6
;
149 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
151 case STATIC_IPV6_GATEWAY_IFINDEX
:
152 rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
, si
->ifindex
);
156 /* Save the flags of this static routes (reject, blackhole) */
157 rib
->flags
= si
->flags
;
159 if (IS_ZEBRA_DEBUG_RIB
)
161 char buf
[INET6_ADDRSTRLEN
];
162 if (IS_ZEBRA_DEBUG_RIB
)
164 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, INET6_ADDRSTRLEN
);
165 zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d)",
166 si
->vrf_id
, buf
, p
->prefixlen
, rn
, rib
, rib
->type
);
169 /* Link this rib to the tree. Schedule for processing or invoke NHT,
172 if (si
->type
== STATIC_IPV4_GATEWAY
||
173 si
->type
== STATIC_IPV6_GATEWAY
)
175 rib_addnode (rn
, rib
, 0);
176 zebra_evaluate_rnh(si
->vrf_id
, nh_p
.family
, 1, RNH_NEXTHOP_TYPE
, &nh_p
);
179 rib_addnode (rn
, rib
, 1);
183 static_nexthop_same (struct nexthop
*nexthop
, struct static_route
*si
)
185 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
186 && si
->type
== STATIC_IPV4_GATEWAY
187 && IPV4_ADDR_SAME (&nexthop
->gate
.ipv4
, &si
->addr
.ipv4
))
189 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
190 && si
->type
== STATIC_IFINDEX
191 && nexthop
->ifindex
== si
->ifindex
)
193 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
194 && si
->type
== STATIC_IPV4_BLACKHOLE
)
196 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
197 && si
->type
== STATIC_IPV6_GATEWAY
198 && IPV6_ADDR_SAME (&nexthop
->gate
.ipv6
, &si
->addr
.ipv6
))
200 if (nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
201 && si
->type
== STATIC_IPV6_GATEWAY_IFINDEX
202 && IPV6_ADDR_SAME (&nexthop
->gate
.ipv6
, &si
->addr
.ipv6
)
203 && nexthop
->ifindex
== si
->ifindex
)
208 /* Uninstall static route from RIB. */
210 static_uninstall_route (afi_t afi
, safi_t safi
, struct prefix
*p
, struct static_route
*si
)
212 struct route_node
*rn
;
214 struct nexthop
*nexthop
;
215 struct route_table
*table
;
219 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
223 /* Lookup existing route with type and distance. */
224 rn
= route_node_lookup (table
, p
);
228 RNODE_FOREACH_RIB (rn
, rib
)
230 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
233 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
&&
240 route_unlock_node (rn
);
244 /* Lookup nexthop. */
245 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
246 if (static_nexthop_same (nexthop
, si
))
249 /* Can't find nexthop. */
252 route_unlock_node (rn
);
257 if (rib
->nexthop_num
== 1)
258 rib_delnode (rn
, rib
);
261 /* Mark this nexthop as inactive and reinstall the route. Then, delete
262 * the nexthop. There is no need to re-evaluate the route for this
265 if (IS_ZEBRA_DEBUG_RIB
)
267 char buf
[INET6_ADDRSTRLEN
];
268 if (IS_ZEBRA_DEBUG_RIB
)
270 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, INET6_ADDRSTRLEN
);
271 zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
272 si
->vrf_id
, buf
, p
->prefixlen
, rn
, rib
, rib
->type
);
275 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
276 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))
278 /* If there are other active nexthops, do an update. */
279 if (rib
->nexthop_active_num
> 1)
281 rib_install_kernel (rn
, rib
, 1);
282 redistribute_update (&rn
->p
, rib
, NULL
);
286 redistribute_delete (&rn
->p
, rib
);
287 rib_uninstall_kernel (rn
, rib
);
293 /* Delete the nexthop and dereg from NHT */
294 nh_p
.family
= AF_INET
;
295 nh_p
.prefixlen
= IPV4_MAX_BITLEN
;
296 nh_p
.u
.prefix4
= nexthop
->gate
.ipv4
;
300 nh_p
.family
= AF_INET6
;
301 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
302 nh_p
.u
.prefix6
= nexthop
->gate
.ipv6
;
304 rib_nexthop_delete (rib
, nexthop
);
305 zebra_deregister_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
306 nexthop_free (nexthop
);
309 route_unlock_node (rn
);
313 static_add_ipv4 (safi_t safi
, struct prefix
*p
, struct in_addr
*gate
, ifindex_t ifindex
,
314 const char *ifname
, u_char flags
, u_short tag
,
315 u_char distance
, struct zebra_vrf
*zvrf
)
318 struct route_node
*rn
;
319 struct static_route
*si
;
320 struct static_route
*pp
;
321 struct static_route
*cp
;
322 struct static_route
*update
= NULL
;
323 struct route_table
*stable
= zvrf
->stable
[AFI_IP
][safi
];
328 /* Lookup static route prefix. */
329 rn
= route_node_get (stable
, p
);
333 type
= STATIC_IPV4_GATEWAY
;
335 type
= STATIC_IFINDEX
;
337 type
= STATIC_IPV4_BLACKHOLE
;
339 /* Do nothing if there is a same static route. */
340 for (si
= rn
->info
; si
; si
= si
->next
)
343 && (! gate
|| IPV4_ADDR_SAME (gate
, &si
->addr
.ipv4
))
344 && (! ifindex
|| ifindex
== si
->ifindex
))
346 if ((distance
== si
->distance
) && (tag
== si
->tag
))
348 route_unlock_node (rn
);
356 /* Distance or tag changed. */
358 static_delete_ipv4 (safi
, p
, gate
, ifindex
, update
->tag
, update
->distance
, zvrf
);
360 /* Make new static route structure. */
361 si
= XCALLOC (MTYPE_STATIC_ROUTE
, sizeof (struct static_route
));
364 si
->distance
= distance
;
367 si
->vrf_id
= zvrf
->vrf_id
;
368 si
->ifindex
= ifindex
;
370 strcpy(si
->ifname
, ifname
);
373 si
->addr
.ipv4
= *gate
;
375 /* Add new static route information to the tree with sort by
376 distance value and gateway address. */
377 for (pp
= NULL
, cp
= rn
->info
; cp
; pp
= cp
, cp
= cp
->next
)
379 if (si
->distance
< cp
->distance
)
381 if (si
->distance
> cp
->distance
)
383 if (si
->type
== STATIC_IPV4_GATEWAY
&& cp
->type
== STATIC_IPV4_GATEWAY
)
385 if (ntohl (si
->addr
.ipv4
.s_addr
) < ntohl (cp
->addr
.ipv4
.s_addr
))
387 if (ntohl (si
->addr
.ipv4
.s_addr
) > ntohl (cp
->addr
.ipv4
.s_addr
))
392 /* Make linked list. */
402 /* Install into rib. */
403 static_install_route (AFI_IP
, safi
, p
, si
);
409 static_delete_ipv4 (safi_t safi
, struct prefix
*p
, struct in_addr
*gate
, ifindex_t ifindex
,
410 u_short tag
, u_char distance
, struct zebra_vrf
*zvrf
)
413 struct route_node
*rn
;
414 struct static_route
*si
;
415 struct route_table
*stable
;
418 stable
= zebra_vrf_static_table (AFI_IP
, safi
, zvrf
);
422 /* Lookup static route prefix. */
423 rn
= route_node_lookup (stable
, p
);
429 type
= STATIC_IPV4_GATEWAY
;
431 type
= STATIC_IFINDEX
;
433 type
= STATIC_IPV4_BLACKHOLE
;
435 /* Find same static route is the tree */
436 for (si
= rn
->info
; si
; si
= si
->next
)
438 && (! gate
|| IPV4_ADDR_SAME (gate
, &si
->addr
.ipv4
))
439 && (! ifindex
|| ifindex
== si
->ifindex
)
440 && (! tag
|| (tag
== si
->tag
)))
443 /* Can't find static route. */
446 route_unlock_node (rn
);
450 /* Install into rib. */
451 static_uninstall_route (AFI_IP
, safi
, p
, si
);
453 /* Unlink static route from linked list. */
455 si
->prev
->next
= si
->next
;
459 si
->next
->prev
= si
->prev
;
460 route_unlock_node (rn
);
462 /* Free static route configuration. */
463 XFREE (MTYPE_STATIC_ROUTE
, si
);
465 route_unlock_node (rn
);
470 /* Add static route into static route configuration. */
472 static_add_ipv6 (struct prefix
*p
, u_char type
, struct in6_addr
*gate
,
473 ifindex_t ifindex
, const char *ifname
, u_char flags
,
474 u_short tag
, u_char distance
, struct zebra_vrf
*zvrf
)
476 struct route_node
*rn
;
477 struct static_route
*si
;
478 struct static_route
*pp
;
479 struct static_route
*cp
;
480 struct static_route
*update
= NULL
;
481 struct route_table
*stable
= zvrf
->stable
[AFI_IP6
][SAFI_UNICAST
];
487 (type
== STATIC_IPV6_GATEWAY
|| type
== STATIC_IPV6_GATEWAY_IFINDEX
))
491 (type
== STATIC_IPV6_GATEWAY_IFINDEX
|| type
== STATIC_IFINDEX
))
494 /* Lookup static route prefix. */
495 rn
= route_node_get (stable
, p
);
497 /* Do nothing if there is a same static route. */
498 for (si
= rn
->info
; si
; si
= si
->next
)
501 && (! gate
|| IPV6_ADDR_SAME (gate
, &si
->addr
.ipv6
))
502 && (! ifindex
|| ifindex
== si
->ifindex
))
504 if ((distance
== si
->distance
) && (tag
== si
->tag
))
506 route_unlock_node (rn
);
514 /* Distance or tag changed. */
516 static_delete_ipv6 (p
, type
, gate
, ifindex
, update
->tag
, update
->distance
, zvrf
);
518 /* Make new static route structure. */
519 si
= XCALLOC (MTYPE_STATIC_ROUTE
, sizeof (struct static_route
));
522 si
->distance
= distance
;
525 si
->vrf_id
= zvrf
->vrf_id
;
526 si
->ifindex
= ifindex
;
528 strcpy (si
->ifname
, ifname
);
532 case STATIC_IPV6_GATEWAY
:
533 si
->addr
.ipv6
= *gate
;
535 case STATIC_IPV6_GATEWAY_IFINDEX
:
536 si
->addr
.ipv6
= *gate
;
540 /* Add new static route information to the tree with sort by
541 distance value and gateway address. */
542 for (pp
= NULL
, cp
= rn
->info
; cp
; pp
= cp
, cp
= cp
->next
)
544 if (si
->distance
< cp
->distance
)
546 if (si
->distance
> cp
->distance
)
550 /* Make linked list. */
560 /* Install into rib. */
561 static_install_route (AFI_IP6
, SAFI_UNICAST
, p
, si
);
566 /* Delete static route from static route configuration. */
568 static_delete_ipv6 (struct prefix
*p
, u_char type
, struct in6_addr
*gate
,
569 ifindex_t ifindex
, u_short tag
, u_char distance
,
570 struct zebra_vrf
*zvrf
)
572 struct route_node
*rn
;
573 struct static_route
*si
;
574 struct route_table
*stable
;
577 stable
= zebra_vrf_static_table (AFI_IP6
, SAFI_UNICAST
, zvrf
);
581 /* Lookup static route prefix. */
582 rn
= route_node_lookup (stable
, p
);
586 /* Find same static route is the tree */
587 for (si
= rn
->info
; si
; si
= si
->next
)
588 if (distance
== si
->distance
590 && (! gate
|| IPV6_ADDR_SAME (gate
, &si
->addr
.ipv6
))
591 && (! ifindex
|| ifindex
== si
->ifindex
)
592 && (! tag
|| (tag
== si
->tag
)))
595 /* Can't find static route. */
598 route_unlock_node (rn
);
602 /* Install into rib. */
603 static_uninstall_route (AFI_IP6
, SAFI_UNICAST
, p
, si
);
605 /* Unlink static route from linked list. */
607 si
->prev
->next
= si
->next
;
611 si
->next
->prev
= si
->prev
;
613 /* Free static route configuration. */
614 XFREE (MTYPE_STATIC_ROUTE
, si
);