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. */
39 void static_install_route(afi_t afi
, safi_t safi
, struct prefix
*p
,
40 struct prefix_ipv6
*src_p
, struct static_route
*si
)
42 struct route_entry
*re
;
43 struct route_node
*rn
;
44 struct route_table
*table
;
46 struct nexthop
*nexthop
= NULL
;
49 table
= zebra_vrf_table(afi
, safi
, si
->vrf_id
);
53 memset(&nh_p
, 0, sizeof(nh_p
));
55 /* Lookup existing route */
56 rn
= srcdest_rnode_get(table
, p
, src_p
);
57 RNODE_FOREACH_RE(rn
, re
)
59 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_REMOVED
))
62 if (re
->type
== ZEBRA_ROUTE_STATIC
63 && re
->distance
== si
->distance
)
68 /* if tag value changed , update old value in RIB */
69 if (re
->tag
!= si
->tag
)
72 /* Same distance static route is there. Update it with new
74 route_unlock_node(rn
);
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
);
85 nexthop
= route_entry_nexthop_ifindex_add(re
,
88 case STATIC_BLACKHOLE
:
89 nexthop
= route_entry_nexthop_blackhole_add(re
);
91 case STATIC_IPV6_GATEWAY
:
92 nexthop
= route_entry_nexthop_ipv6_add(re
,
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
);
99 case STATIC_IPV6_GATEWAY_IFINDEX
:
100 nexthop
= route_entry_nexthop_ipv6_ifindex_add(
101 re
, &si
->addr
.ipv6
, si
->ifindex
);
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]);
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
,
116 "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
117 si
->vrf_id
, buf
, p
->prefixlen
, rn
, re
,
121 /* Schedule route for processing or invoke NHT, as appropriate.
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
);
130 /* This is new static route. */
131 re
= XCALLOC(MTYPE_RE
, sizeof(struct route_entry
));
133 re
->type
= ZEBRA_ROUTE_STATIC
;
135 re
->distance
= si
->distance
;
138 re
->vrf_id
= si
->vrf_id
;
141 ? (zebra_vrf_lookup_by_id(si
->vrf_id
))->table_id
142 : zebrad
.rtm_table_default
;
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
);
156 nexthop
= route_entry_nexthop_ifindex_add(re
,
159 case STATIC_BLACKHOLE
:
160 nexthop
= route_entry_nexthop_blackhole_add(re
);
162 case STATIC_IPV6_GATEWAY
:
163 nexthop
= route_entry_nexthop_ipv6_add(re
,
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
);
170 case STATIC_IPV6_GATEWAY_IFINDEX
:
171 nexthop
= route_entry_nexthop_ipv6_ifindex_add(
172 re
, &si
->addr
.ipv6
, si
->ifindex
);
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]);
181 /* Save the flags of this static routes (reject, blackhole) */
182 re
->flags
= si
->flags
;
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
,
190 "%u:%s/%d: Inserting route rn %p, re %p (type %d)",
191 si
->vrf_id
, buf
, p
->prefixlen
, rn
, re
,
195 /* Link this re to the tree. Schedule for processing or invoke
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
);
205 rib_addnode(rn
, re
, 1);
209 static int static_nexthop_same(struct nexthop
*nexthop
, struct static_route
*si
)
211 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
212 && si
->type
== STATIC_BLACKHOLE
)
215 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
216 && si
->type
== STATIC_IPV4_GATEWAY
217 && IPV4_ADDR_SAME(&nexthop
->gate
.ipv4
, &si
->addr
.ipv4
))
219 else if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
220 && si
->type
== STATIC_IFINDEX
221 && nexthop
->ifindex
== si
->ifindex
)
223 else if (nexthop
->type
== NEXTHOP_TYPE_IPV6
224 && si
->type
== STATIC_IPV6_GATEWAY
225 && IPV6_ADDR_SAME(&nexthop
->gate
.ipv6
, &si
->addr
.ipv6
))
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
)
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
)
240 struct route_node
*rn
;
241 struct route_entry
*re
;
242 struct nexthop
*nexthop
;
243 struct route_table
*table
;
247 table
= zebra_vrf_table(afi
, safi
, si
->vrf_id
);
251 /* Lookup existing route with type and distance. */
252 rn
= srcdest_rnode_lookup(table
, p
, src_p
);
256 RNODE_FOREACH_RE(rn
, re
)
258 if (CHECK_FLAG(re
->status
, ROUTE_ENTRY_REMOVED
))
261 if (re
->type
== ZEBRA_ROUTE_STATIC
262 && re
->distance
== si
->distance
&& re
->tag
== si
->tag
)
267 route_unlock_node(rn
);
271 /* Lookup nexthop. */
272 for (nexthop
= re
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
273 if (static_nexthop_same(nexthop
, si
))
276 /* Can't find nexthop. */
278 route_unlock_node(rn
);
283 if (re
->nexthop_num
== 1)
286 /* Mark this nexthop as inactive and reinstall the route. Then,
288 * the nexthop. There is no need to re-evaluate the route for
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
,
298 "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
299 si
->vrf_id
, buf
, p
->prefixlen
, rn
, re
,
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
))
314 p
, (struct prefix
*)src_p
, re
,
317 /* Remove from redistribute if selected route
318 * becomes inactive */
319 if (CHECK_FLAG(re
->flags
, ZEBRA_FLAG_SELECTED
))
321 p
, (struct prefix
*)src_p
, re
);
322 /* Remove from kernel if fib route becomes
324 if (CHECK_FLAG(re
->status
,
325 ROUTE_ENTRY_SELECTED_FIB
))
326 rib_uninstall_kernel(rn
, re
);
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
;
336 nh_p
.family
= AF_INET6
;
337 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
338 nh_p
.u
.prefix6
= nexthop
->gate
.ipv6
;
340 route_entry_nexthop_delete(re
, nexthop
);
341 zebra_deregister_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
342 nexthop_free(nexthop
);
345 route_unlock_node(rn
);
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
)
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
];
364 if (!gate
&& (type
== STATIC_IPV4_GATEWAY
|| type
== STATIC_IPV6_GATEWAY
365 || type
== STATIC_IPV6_GATEWAY_IFINDEX
))
369 && (type
== STATIC_IFINDEX
|| type
== STATIC_IPV6_GATEWAY_IFINDEX
))
372 /* Lookup static route prefix. */
373 rn
= srcdest_rnode_get(stable
, p
, src_p
);
375 /* Do nothing if there is a same static route. */
376 for (si
= rn
->info
; si
; si
= si
->next
) {
378 && (!gate
|| ((afi
== AFI_IP
379 && IPV4_ADDR_SAME(gate
, &si
->addr
.ipv4
))
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
);
394 /* Distance or tag or label changed, delete existing first. */
396 static_delete_route(afi
, safi
, type
, p
, src_p
, gate
, ifindex
,
397 update
->tag
, update
->distance
, zvrf
,
400 /* Make new static route structure. */
401 si
= XCALLOC(MTYPE_STATIC_ROUTE
, sizeof(struct static_route
));
404 si
->distance
= distance
;
407 si
->vrf_id
= zvrf_id(zvrf
);
408 si
->ifindex
= ifindex
;
410 strcpy(si
->ifname
, ifname
);
413 case STATIC_IPV4_GATEWAY
:
414 si
->addr
.ipv4
= gate
->ipv4
;
416 case STATIC_IPV6_GATEWAY
:
417 si
->addr
.ipv6
= gate
->ipv6
;
419 case STATIC_IPV6_GATEWAY_IFINDEX
:
420 si
->addr
.ipv6
= gate
->ipv6
;
426 /* Save labels, if any. */
427 memcpy(&si
->snh_label
, snh_label
, sizeof(struct static_nh_label
));
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
)
434 if (si
->distance
> cp
->distance
)
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
))
441 if (ntohl(si
->addr
.ipv4
.s_addr
)
442 > ntohl(cp
->addr
.ipv4
.s_addr
))
447 /* Make linked list. */
457 /* Install into rib. */
458 static_install_route(afi
, safi
, p
, src_p
, si
);
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
)
469 struct route_node
*rn
;
470 struct static_route
*si
;
471 struct route_table
*stable
;
474 stable
= zebra_vrf_static_table(afi
, safi
, zvrf
);
478 /* Lookup static route prefix. */
479 rn
= srcdest_rnode_lookup(stable
, p
, src_p
);
483 /* Find same static route is the tree */
484 for (si
= rn
->info
; si
; si
= si
->next
)
486 && (!gate
|| ((afi
== AFI_IP
487 && IPV4_ADDR_SAME(gate
, &si
->addr
.ipv4
))
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
))))
497 /* Can't find static route. */
499 route_unlock_node(rn
);
503 /* Install into rib. */
504 static_uninstall_route(afi
, safi
, p
, src_p
, si
);
506 /* Unlink static route from linked list. */
508 si
->prev
->next
= si
->next
;
512 si
->next
->prev
= si
->prev
;
513 route_unlock_node(rn
);
515 /* Free static route configuration. */
516 XFREE(MTYPE_STATIC_ROUTE
, si
);
518 route_unlock_node(rn
);