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 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
24 #include <lib/nexthop.h>
25 #include <lib/memory.h>
26 #include <lib/srcdest_table.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"
38 /* Install static route into rib. */
40 static_install_route (afi_t afi
, safi_t safi
, struct prefix
*p
,
41 struct prefix_ipv6
*src_p
, struct static_route
*si
)
44 struct route_node
*rn
;
45 struct route_table
*table
;
47 struct nexthop
*nexthop
= NULL
;
50 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
54 memset (&nh_p
, 0, sizeof (nh_p
));
56 /* Lookup existing route */
57 rn
= srcdest_rnode_get (table
, p
, src_p
);
58 RNODE_FOREACH_RIB (rn
, rib
)
60 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
63 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
)
69 /* if tag value changed , update old value in RIB */
70 if (rib
->tag
!= si
->tag
)
73 /* Same distance static route is there. Update it with new
75 route_unlock_node (rn
);
78 case STATIC_IPV4_GATEWAY
:
79 nexthop
= rib_nexthop_ipv4_add (rib
, &si
->addr
.ipv4
, NULL
);
80 nh_p
.family
= AF_INET
;
81 nh_p
.prefixlen
= IPV4_MAX_BITLEN
;
82 nh_p
.u
.prefix4
= si
->addr
.ipv4
;
83 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
86 nexthop
= rib_nexthop_ifindex_add (rib
, si
->ifindex
);
88 case STATIC_BLACKHOLE
:
89 nexthop
= rib_nexthop_blackhole_add (rib
);
91 case STATIC_IPV6_GATEWAY
:
92 nexthop
= rib_nexthop_ipv6_add (rib
, &si
->addr
.ipv6
);
93 nh_p
.family
= AF_INET6
;
94 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
95 nh_p
.u
.prefix6
= si
->addr
.ipv6
;
96 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
98 case STATIC_IPV6_GATEWAY_IFINDEX
:
99 nexthop
= rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
,
103 /* Update label(s), if present. */
104 if (si
->snh_label
.num_labels
)
105 nexthop_add_labels (nexthop
, ZEBRA_LSP_STATIC
, si
->snh_label
.num_labels
,
106 &si
->snh_label
.label
[0]);
108 if (IS_ZEBRA_DEBUG_RIB
)
110 char buf
[INET6_ADDRSTRLEN
];
111 if (IS_ZEBRA_DEBUG_RIB
)
113 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, INET6_ADDRSTRLEN
);
114 zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
115 si
->vrf_id
, buf
, p
->prefixlen
, rn
, rib
, rib
->type
);
118 /* Schedule route for processing or invoke NHT, as appropriate. */
119 if (si
->type
== STATIC_IPV4_GATEWAY
||
120 si
->type
== STATIC_IPV6_GATEWAY
)
121 zebra_evaluate_rnh(si
->vrf_id
, nh_p
.family
, 1, RNH_NEXTHOP_TYPE
, &nh_p
);
127 /* This is new static route. */
128 rib
= XCALLOC (MTYPE_RIB
, sizeof (struct rib
));
130 rib
->type
= ZEBRA_ROUTE_STATIC
;
132 rib
->distance
= si
->distance
;
135 rib
->vrf_id
= si
->vrf_id
;
136 rib
->table
= si
->vrf_id
? (zebra_vrf_lookup_by_id(si
->vrf_id
))->table_id
: zebrad
.rtm_table_default
;
137 rib
->nexthop_num
= 0;
142 case STATIC_IPV4_GATEWAY
:
143 nexthop
= rib_nexthop_ipv4_add (rib
, &si
->addr
.ipv4
, NULL
);
144 nh_p
.family
= AF_INET
;
145 nh_p
.prefixlen
= IPV4_MAX_BITLEN
;
146 nh_p
.u
.prefix4
= si
->addr
.ipv4
;
147 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
150 nexthop
= rib_nexthop_ifindex_add (rib
, si
->ifindex
);
152 case STATIC_BLACKHOLE
:
153 nexthop
= rib_nexthop_blackhole_add (rib
);
155 case STATIC_IPV6_GATEWAY
:
156 nexthop
= rib_nexthop_ipv6_add (rib
, &si
->addr
.ipv6
);
157 nh_p
.family
= AF_INET6
;
158 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
159 nh_p
.u
.prefix6
= si
->addr
.ipv6
;
160 zebra_register_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
162 case STATIC_IPV6_GATEWAY_IFINDEX
:
163 nexthop
= rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
,
167 /* Update label(s), if present. */
168 if (si
->snh_label
.num_labels
)
169 nexthop_add_labels (nexthop
, ZEBRA_LSP_STATIC
, si
->snh_label
.num_labels
,
170 &si
->snh_label
.label
[0]);
172 /* Save the flags of this static routes (reject, blackhole) */
173 rib
->flags
= si
->flags
;
175 if (IS_ZEBRA_DEBUG_RIB
)
177 char buf
[INET6_ADDRSTRLEN
];
178 if (IS_ZEBRA_DEBUG_RIB
)
180 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, INET6_ADDRSTRLEN
);
181 zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d)",
182 si
->vrf_id
, buf
, p
->prefixlen
, rn
, rib
, rib
->type
);
185 /* Link this rib to the tree. Schedule for processing or invoke NHT,
188 if (si
->type
== STATIC_IPV4_GATEWAY
||
189 si
->type
== STATIC_IPV6_GATEWAY
)
191 rib_addnode (rn
, rib
, 0);
192 zebra_evaluate_rnh(si
->vrf_id
, nh_p
.family
, 1, RNH_NEXTHOP_TYPE
, &nh_p
);
195 rib_addnode (rn
, rib
, 1);
200 static_nexthop_same (struct nexthop
*nexthop
, struct static_route
*si
)
202 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
203 && si
->type
== STATIC_BLACKHOLE
)
206 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
207 && si
->type
== STATIC_IPV4_GATEWAY
208 && IPV4_ADDR_SAME (&nexthop
->gate
.ipv4
, &si
->addr
.ipv4
))
210 else if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
211 && si
->type
== STATIC_IFINDEX
212 && nexthop
->ifindex
== si
->ifindex
)
214 else if (nexthop
->type
== NEXTHOP_TYPE_IPV6
215 && si
->type
== STATIC_IPV6_GATEWAY
216 && IPV6_ADDR_SAME (&nexthop
->gate
.ipv6
, &si
->addr
.ipv6
))
218 else if (nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
219 && si
->type
== STATIC_IPV6_GATEWAY_IFINDEX
220 && IPV6_ADDR_SAME (&nexthop
->gate
.ipv6
, &si
->addr
.ipv6
)
221 && nexthop
->ifindex
== si
->ifindex
)
227 /* Uninstall static route from RIB. */
229 static_uninstall_route (afi_t afi
, safi_t safi
, struct prefix
*p
,
230 struct prefix_ipv6
*src_p
, struct static_route
*si
)
232 struct route_node
*rn
;
234 struct nexthop
*nexthop
;
235 struct route_table
*table
;
239 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
243 /* Lookup existing route with type and distance. */
244 rn
= srcdest_rnode_lookup (table
, p
, src_p
);
248 RNODE_FOREACH_RIB (rn
, rib
)
250 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
253 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
&&
260 route_unlock_node (rn
);
264 /* Lookup nexthop. */
265 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
266 if (static_nexthop_same (nexthop
, si
))
269 /* Can't find nexthop. */
272 route_unlock_node (rn
);
277 if (rib
->nexthop_num
== 1)
278 rib_delnode (rn
, rib
);
281 /* Mark this nexthop as inactive and reinstall the route. Then, delete
282 * the nexthop. There is no need to re-evaluate the route for this
285 if (IS_ZEBRA_DEBUG_RIB
)
287 char buf
[INET6_ADDRSTRLEN
];
288 if (IS_ZEBRA_DEBUG_RIB
)
290 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, INET6_ADDRSTRLEN
);
291 zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
292 si
->vrf_id
, buf
, p
->prefixlen
, rn
, rib
, rib
->type
);
295 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
296 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))
298 /* If there are other active nexthops, do an update. */
299 if (rib
->nexthop_active_num
> 1)
301 /* Update route in kernel if it's in fib */
302 if (CHECK_FLAG(rib
->status
, RIB_ENTRY_SELECTED_FIB
))
303 rib_install_kernel (rn
, rib
, rib
);
304 /* Update redistribution if it's selected */
305 if (CHECK_FLAG(rib
->flags
, ZEBRA_FLAG_SELECTED
))
306 redistribute_update (p
, (struct prefix
*)src_p
, rib
, NULL
);
310 /* Remove from redistribute if selected route becomes inactive */
311 if (CHECK_FLAG(rib
->flags
, ZEBRA_FLAG_SELECTED
))
312 redistribute_delete (p
, (struct prefix
*)src_p
, rib
);
313 /* Remove from kernel if fib route becomes inactive */
314 if (CHECK_FLAG(rib
->status
, RIB_ENTRY_SELECTED_FIB
))
315 rib_uninstall_kernel (rn
, rib
);
321 /* Delete the nexthop and dereg from NHT */
322 nh_p
.family
= AF_INET
;
323 nh_p
.prefixlen
= IPV4_MAX_BITLEN
;
324 nh_p
.u
.prefix4
= nexthop
->gate
.ipv4
;
328 nh_p
.family
= AF_INET6
;
329 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
330 nh_p
.u
.prefix6
= nexthop
->gate
.ipv6
;
332 rib_nexthop_delete (rib
, nexthop
);
333 zebra_deregister_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
334 nexthop_free (nexthop
);
337 route_unlock_node (rn
);
341 static_add_route (afi_t afi
, safi_t safi
, u_char type
, struct prefix
*p
,
342 struct prefix_ipv6
*src_p
,
343 union g_addr
*gate
, ifindex_t ifindex
,
344 const char *ifname
, u_char flags
, route_tag_t tag
,
345 u_char distance
, struct zebra_vrf
*zvrf
,
346 struct static_nh_label
*snh_label
)
348 struct route_node
*rn
;
349 struct static_route
*si
;
350 struct static_route
*pp
;
351 struct static_route
*cp
;
352 struct static_route
*update
= NULL
;
353 struct route_table
*stable
= zvrf
->stable
[afi
][safi
];
359 (type
== STATIC_IPV4_GATEWAY
||
360 type
== STATIC_IPV6_GATEWAY
||
361 type
== STATIC_IPV6_GATEWAY_IFINDEX
))
365 (type
== STATIC_IFINDEX
||
366 type
== STATIC_IPV6_GATEWAY_IFINDEX
))
369 /* Lookup static route prefix. */
370 rn
= srcdest_rnode_get (stable
, p
, src_p
);
372 /* Do nothing if there is a same static route. */
373 for (si
= rn
->info
; si
; si
= si
->next
)
377 ((afi
== AFI_IP
&& IPV4_ADDR_SAME (gate
, &si
->addr
.ipv4
)) ||
378 (afi
== AFI_IP6
&& IPV6_ADDR_SAME (gate
, &si
->addr
.ipv6
))))
379 && (! ifindex
|| ifindex
== si
->ifindex
))
381 if ((distance
== si
->distance
) && (tag
== si
->tag
) &&
382 !memcmp (&si
->snh_label
, snh_label
, sizeof (struct static_nh_label
)) &&
385 route_unlock_node (rn
);
393 /* Distance or tag or label changed, delete existing first. */
395 static_delete_route (afi
, safi
, type
, p
, src_p
, gate
, ifindex
, update
->tag
,
396 update
->distance
, zvrf
, &update
->snh_label
);
398 /* Make new static route structure. */
399 si
= XCALLOC (MTYPE_STATIC_ROUTE
, sizeof (struct static_route
));
402 si
->distance
= distance
;
405 si
->vrf_id
= zvrf_id (zvrf
);
406 si
->ifindex
= ifindex
;
408 strcpy(si
->ifname
, ifname
);
412 case STATIC_IPV4_GATEWAY
:
413 si
->addr
.ipv4
= gate
->ipv4
;
415 case STATIC_IPV6_GATEWAY
:
416 si
->addr
.ipv6
= gate
->ipv6
;
418 case STATIC_IPV6_GATEWAY_IFINDEX
:
419 si
->addr
.ipv6
= gate
->ipv6
;
425 /* Save labels, if any. */
426 memcpy (&si
->snh_label
, snh_label
, sizeof (struct static_nh_label
));
428 /* Add new static route information to the tree with sort by
429 distance value and gateway address. */
430 for (pp
= NULL
, cp
= rn
->info
; cp
; pp
= cp
, cp
= cp
->next
)
432 if (si
->distance
< cp
->distance
)
434 if (si
->distance
> cp
->distance
)
436 if (si
->type
== STATIC_IPV4_GATEWAY
&& cp
->type
== STATIC_IPV4_GATEWAY
)
438 if (ntohl (si
->addr
.ipv4
.s_addr
) < ntohl (cp
->addr
.ipv4
.s_addr
))
440 if (ntohl (si
->addr
.ipv4
.s_addr
) > ntohl (cp
->addr
.ipv4
.s_addr
))
445 /* Make linked list. */
455 /* Install into rib. */
456 static_install_route (afi
, safi
, p
, src_p
, si
);
462 static_delete_route (afi_t afi
, safi_t safi
, u_char type
, struct prefix
*p
,
463 struct prefix_ipv6
*src_p
,
464 union g_addr
*gate
, ifindex_t ifindex
,
465 route_tag_t tag
, u_char distance
, struct zebra_vrf
*zvrf
,
466 struct static_nh_label
*snh_label
)
468 struct route_node
*rn
;
469 struct static_route
*si
;
470 struct route_table
*stable
;
473 stable
= zebra_vrf_static_table (afi
, safi
, zvrf
);
477 /* Lookup static route prefix. */
478 rn
= srcdest_rnode_lookup (stable
, p
, src_p
);
482 /* Find same static route is the tree */
483 for (si
= rn
->info
; si
; si
= si
->next
)
486 (afi
== AFI_IP
&& IPV4_ADDR_SAME (gate
, &si
->addr
.ipv4
)) ||
487 (afi
== AFI_IP6
&& IPV6_ADDR_SAME (gate
, &si
->addr
.ipv6
))))
488 && (! ifindex
|| ifindex
== si
->ifindex
)
489 && (! tag
|| (tag
== si
->tag
))
490 && (! snh_label
->num_labels
||
491 !memcmp (&si
->snh_label
, snh_label
, sizeof (struct static_nh_label
))))
494 /* Can't find static route. */
497 route_unlock_node (rn
);
501 /* Install into rib. */
502 static_uninstall_route (afi
, safi
, p
, src_p
, si
);
504 /* Unlink static route from linked list. */
506 si
->prev
->next
= si
->next
;
510 si
->next
->prev
= si
->prev
;
511 route_unlock_node (rn
);
513 /* Free static route configuration. */
514 XFREE (MTYPE_STATIC_ROUTE
, si
);
516 route_unlock_node (rn
);