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>
27 #include <lib/srcdest_table.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"
39 /* Install static route into rib. */
41 static_install_route (afi_t afi
, safi_t safi
, struct prefix
*p
,
42 struct prefix_ipv6
*src_p
, struct static_route
*si
)
45 struct route_node
*rn
;
46 struct route_table
*table
;
48 struct nexthop
*nexthop
= NULL
;
51 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
55 memset (&nh_p
, 0, sizeof (nh_p
));
57 /* Lookup existing route */
58 rn
= srcdest_rnode_get (table
, p
, src_p
);
59 RNODE_FOREACH_RIB (rn
, rib
)
61 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
64 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
)
70 /* if tag value changed , update old value in RIB */
71 if (rib
->tag
!= si
->tag
)
74 /* Same distance static route is there. Update it with new
76 route_unlock_node (rn
);
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
);
87 nexthop
= rib_nexthop_ifindex_add (rib
, si
->ifindex
);
89 case STATIC_BLACKHOLE
:
90 nexthop
= rib_nexthop_blackhole_add (rib
);
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
);
99 case STATIC_IPV6_GATEWAY_IFINDEX
:
100 nexthop
= rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
,
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]);
109 if (IS_ZEBRA_DEBUG_RIB
)
111 char buf
[INET6_ADDRSTRLEN
];
112 if (IS_ZEBRA_DEBUG_RIB
)
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
);
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
);
128 /* This is new static route. */
129 rib
= XCALLOC (MTYPE_RIB
, sizeof (struct rib
));
131 rib
->type
= ZEBRA_ROUTE_STATIC
;
133 rib
->distance
= si
->distance
;
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;
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
);
151 nexthop
= rib_nexthop_ifindex_add (rib
, si
->ifindex
);
153 case STATIC_BLACKHOLE
:
154 nexthop
= rib_nexthop_blackhole_add (rib
);
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
);
163 case STATIC_IPV6_GATEWAY_IFINDEX
:
164 nexthop
= rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
,
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]);
173 /* Save the flags of this static routes (reject, blackhole) */
174 rib
->flags
= si
->flags
;
176 if (IS_ZEBRA_DEBUG_RIB
)
178 char buf
[INET6_ADDRSTRLEN
];
179 if (IS_ZEBRA_DEBUG_RIB
)
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
);
186 /* Link this rib to the tree. Schedule for processing or invoke NHT,
189 if (si
->type
== STATIC_IPV4_GATEWAY
||
190 si
->type
== STATIC_IPV6_GATEWAY
)
192 rib_addnode (rn
, rib
, 0);
193 zebra_evaluate_rnh(si
->vrf_id
, nh_p
.family
, 1, RNH_NEXTHOP_TYPE
, &nh_p
);
196 rib_addnode (rn
, rib
, 1);
201 static_nexthop_same (struct nexthop
*nexthop
, struct static_route
*si
)
203 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
204 && si
->type
== STATIC_BLACKHOLE
)
207 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
208 && si
->type
== STATIC_IPV4_GATEWAY
209 && IPV4_ADDR_SAME (&nexthop
->gate
.ipv4
, &si
->addr
.ipv4
))
211 else if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
212 && si
->type
== STATIC_IFINDEX
213 && nexthop
->ifindex
== si
->ifindex
)
215 else if (nexthop
->type
== NEXTHOP_TYPE_IPV6
216 && si
->type
== STATIC_IPV6_GATEWAY
217 && IPV6_ADDR_SAME (&nexthop
->gate
.ipv6
, &si
->addr
.ipv6
))
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
)
228 /* Uninstall static route from RIB. */
230 static_uninstall_route (afi_t afi
, safi_t safi
, struct prefix
*p
,
231 struct prefix_ipv6
*src_p
, struct static_route
*si
)
233 struct route_node
*rn
;
235 struct nexthop
*nexthop
;
236 struct route_table
*table
;
240 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
244 /* Lookup existing route with type and distance. */
245 rn
= srcdest_rnode_lookup (table
, p
, src_p
);
249 RNODE_FOREACH_RIB (rn
, rib
)
251 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
254 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
&&
261 route_unlock_node (rn
);
265 /* Lookup nexthop. */
266 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
267 if (static_nexthop_same (nexthop
, si
))
270 /* Can't find nexthop. */
273 route_unlock_node (rn
);
278 if (rib
->nexthop_num
== 1)
279 rib_delnode (rn
, rib
);
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
286 if (IS_ZEBRA_DEBUG_RIB
)
288 char buf
[INET6_ADDRSTRLEN
];
289 if (IS_ZEBRA_DEBUG_RIB
)
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
);
296 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
297 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))
299 /* If there are other active nexthops, do an update. */
300 if (rib
->nexthop_active_num
> 1)
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
);
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
);
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
;
329 nh_p
.family
= AF_INET6
;
330 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
331 nh_p
.u
.prefix6
= nexthop
->gate
.ipv6
;
333 rib_nexthop_delete (rib
, nexthop
);
334 zebra_deregister_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
335 nexthop_free (nexthop
);
338 route_unlock_node (rn
);
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
)
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
];
360 (type
== STATIC_IPV4_GATEWAY
||
361 type
== STATIC_IPV6_GATEWAY
||
362 type
== STATIC_IPV6_GATEWAY_IFINDEX
))
366 (type
== STATIC_IFINDEX
||
367 type
== STATIC_IPV6_GATEWAY_IFINDEX
))
370 /* Lookup static route prefix. */
371 rn
= srcdest_rnode_get (stable
, p
, src_p
);
373 /* Do nothing if there is a same static route. */
374 for (si
= rn
->info
; si
; si
= si
->next
)
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
))
382 if ((distance
== si
->distance
) && (tag
== si
->tag
) &&
383 !memcmp (&si
->snh_label
, snh_label
, sizeof (struct static_nh_label
)) &&
386 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
, update
->tag
,
397 update
->distance
, zvrf
, &update
->snh_label
);
399 /* Make new static route structure. */
400 si
= XCALLOC (MTYPE_STATIC_ROUTE
, sizeof (struct static_route
));
403 si
->distance
= distance
;
406 si
->vrf_id
= zvrf_id (zvrf
);
407 si
->ifindex
= ifindex
;
409 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
)
433 if (si
->distance
< cp
->distance
)
435 if (si
->distance
> cp
->distance
)
437 if (si
->type
== STATIC_IPV4_GATEWAY
&& cp
->type
== STATIC_IPV4_GATEWAY
)
439 if (ntohl (si
->addr
.ipv4
.s_addr
) < ntohl (cp
->addr
.ipv4
.s_addr
))
441 if (ntohl (si
->addr
.ipv4
.s_addr
) > ntohl (cp
->addr
.ipv4
.s_addr
))
446 /* Make linked list. */
456 /* Install into rib. */
457 static_install_route (afi
, safi
, p
, src_p
, si
);
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
)
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
)
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
))))
495 /* Can't find static route. */
498 route_unlock_node (rn
);
502 /* Install into rib. */
503 static_uninstall_route (afi
, safi
, p
, src_p
, si
);
505 /* Unlink static route from linked list. */
507 si
->prev
->next
= si
->next
;
511 si
->next
->prev
= si
->prev
;
512 route_unlock_node (rn
);
514 /* Free static route configuration. */
515 XFREE (MTYPE_STATIC_ROUTE
, si
);
517 route_unlock_node (rn
);