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"
35 #include "zebra/zebra_memory.h"
37 /* Install static route into rib. */
39 static_install_route (afi_t afi
, safi_t safi
, struct prefix
*p
, struct static_route
*si
)
42 struct route_node
*rn
;
43 struct route_table
*table
;
45 struct nexthop
*nexthop
= NULL
;
48 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
52 /* Lookup existing route */
53 rn
= route_node_get (table
, p
);
54 RNODE_FOREACH_RIB (rn
, rib
)
56 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
59 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
)
65 /* if tag value changed , update old value in RIB */
66 if (rib
->tag
!= si
->tag
)
69 /* Same distance static route is there. Update it with new
71 route_unlock_node (rn
);
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
);
82 nexthop
= rib_nexthop_ifindex_add (rib
, si
->ifindex
);
84 case STATIC_BLACKHOLE
:
85 nexthop
= rib_nexthop_blackhole_add (rib
);
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
);
94 case STATIC_IPV6_GATEWAY_IFINDEX
:
95 nexthop
= rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
,
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]);
104 if (IS_ZEBRA_DEBUG_RIB
)
106 char buf
[INET6_ADDRSTRLEN
];
107 if (IS_ZEBRA_DEBUG_RIB
)
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
);
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
);
123 /* This is new static route. */
124 rib
= XCALLOC (MTYPE_RIB
, sizeof (struct rib
));
126 rib
->type
= ZEBRA_ROUTE_STATIC
;
128 rib
->distance
= si
->distance
;
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;
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
);
146 nexthop
= rib_nexthop_ifindex_add (rib
, si
->ifindex
);
148 case STATIC_BLACKHOLE
:
149 nexthop
= rib_nexthop_blackhole_add (rib
);
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
);
158 case STATIC_IPV6_GATEWAY_IFINDEX
:
159 nexthop
= rib_nexthop_ipv6_ifindex_add (rib
, &si
->addr
.ipv6
,
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]);
168 /* Save the flags of this static routes (reject, blackhole) */
169 rib
->flags
= si
->flags
;
171 if (IS_ZEBRA_DEBUG_RIB
)
173 char buf
[INET6_ADDRSTRLEN
];
174 if (IS_ZEBRA_DEBUG_RIB
)
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
);
181 /* Link this rib to the tree. Schedule for processing or invoke NHT,
184 if (si
->type
== STATIC_IPV4_GATEWAY
||
185 si
->type
== STATIC_IPV6_GATEWAY
)
187 rib_addnode (rn
, rib
, 0);
188 zebra_evaluate_rnh(si
->vrf_id
, nh_p
.family
, 1, RNH_NEXTHOP_TYPE
, &nh_p
);
191 rib_addnode (rn
, rib
, 1);
196 static_nexthop_label_same (struct nexthop
*nexthop
,
197 struct static_nh_label
*snh_label
)
201 if ((snh_label
->num_labels
== 0 && nexthop
->nh_label
) ||
202 (snh_label
->num_labels
!= 0 && !nexthop
->nh_label
))
205 if (snh_label
->num_labels
!= 0)
206 if (snh_label
->num_labels
!= nexthop
->nh_label
->num_labels
)
209 for (i
= 0; i
< snh_label
->num_labels
; i
++)
210 if (snh_label
->label
[i
] != nexthop
->nh_label
->label
[i
])
217 static_nexthop_same (struct nexthop
*nexthop
, struct static_route
*si
)
221 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
222 && si
->type
== STATIC_BLACKHOLE
)
225 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
226 && si
->type
== STATIC_IPV4_GATEWAY
227 && IPV4_ADDR_SAME (&nexthop
->gate
.ipv4
, &si
->addr
.ipv4
))
229 else if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
230 && si
->type
== STATIC_IFINDEX
231 && nexthop
->ifindex
== si
->ifindex
)
233 else if (nexthop
->type
== NEXTHOP_TYPE_IPV6
234 && si
->type
== STATIC_IPV6_GATEWAY
235 && IPV6_ADDR_SAME (&nexthop
->gate
.ipv6
, &si
->addr
.ipv6
))
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
)
246 /* Check match on label(s), if any */
247 return static_nexthop_label_same (nexthop
, &si
->snh_label
);
250 /* Uninstall static route from RIB. */
252 static_uninstall_route (afi_t afi
, safi_t safi
, struct prefix
*p
, struct static_route
*si
)
254 struct route_node
*rn
;
256 struct nexthop
*nexthop
;
257 struct route_table
*table
;
261 table
= zebra_vrf_table (afi
, safi
, si
->vrf_id
);
265 /* Lookup existing route with type and distance. */
266 rn
= route_node_lookup (table
, p
);
270 RNODE_FOREACH_RIB (rn
, rib
)
272 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
275 if (rib
->type
== ZEBRA_ROUTE_STATIC
&& rib
->distance
== si
->distance
&&
282 route_unlock_node (rn
);
286 /* Lookup nexthop. */
287 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
288 if (static_nexthop_same (nexthop
, si
))
291 /* Can't find nexthop. */
294 route_unlock_node (rn
);
299 if (rib
->nexthop_num
== 1)
300 rib_delnode (rn
, rib
);
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
307 if (IS_ZEBRA_DEBUG_RIB
)
309 char buf
[INET6_ADDRSTRLEN
];
310 if (IS_ZEBRA_DEBUG_RIB
)
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
);
317 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
);
318 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))
320 /* If there are other active nexthops, do an update. */
321 if (rib
->nexthop_active_num
> 1)
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
);
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
);
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
;
350 nh_p
.family
= AF_INET6
;
351 nh_p
.prefixlen
= IPV6_MAX_BITLEN
;
352 nh_p
.u
.prefix6
= nexthop
->gate
.ipv6
;
354 rib_nexthop_delete (rib
, nexthop
);
355 zebra_deregister_rnh_static_nh(si
->vrf_id
, &nh_p
, rn
);
356 nexthop_free (nexthop
);
359 route_unlock_node (rn
);
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
)
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
];
380 (type
== STATIC_IPV4_GATEWAY
||
381 type
== STATIC_IPV6_GATEWAY
||
382 type
== STATIC_IPV6_GATEWAY_IFINDEX
))
386 (type
== STATIC_IFINDEX
||
387 type
== STATIC_IPV6_GATEWAY_IFINDEX
))
390 /* Lookup static route prefix. */
391 rn
= route_node_get (stable
, p
);
393 /* Do nothing if there is a same static route. */
394 for (si
= rn
->info
; si
; si
= si
->next
)
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
))
402 if ((distance
== si
->distance
) && (tag
== si
->tag
) &&
403 !memcmp (&si
->snh_label
, snh_label
, sizeof (struct static_nh_label
)))
405 route_unlock_node (rn
);
413 /* Distance or tag or label changed, delete existing first. */
415 static_delete_route (afi
, safi
, type
, p
, gate
, ifindex
, update
->tag
,
416 update
->distance
, zvrf
, &update
->snh_label
);
418 /* Make new static route structure. */
419 si
= XCALLOC (MTYPE_STATIC_ROUTE
, sizeof (struct static_route
));
422 si
->distance
= distance
;
425 si
->vrf_id
= zvrf_id (zvrf
);
426 si
->ifindex
= ifindex
;
428 strcpy(si
->ifname
, ifname
);
432 case STATIC_IPV4_GATEWAY
:
433 si
->addr
.ipv4
= gate
->ipv4
;
435 case STATIC_IPV6_GATEWAY
:
436 si
->addr
.ipv6
= gate
->ipv6
;
438 case STATIC_IPV6_GATEWAY_IFINDEX
:
439 si
->addr
.ipv6
= gate
->ipv6
;
445 /* Save labels, if any. */
446 memcpy (&si
->snh_label
, snh_label
, sizeof (struct static_nh_label
));
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
)
452 if (si
->distance
< cp
->distance
)
454 if (si
->distance
> cp
->distance
)
456 if (si
->type
== STATIC_IPV4_GATEWAY
&& cp
->type
== STATIC_IPV4_GATEWAY
)
458 if (ntohl (si
->addr
.ipv4
.s_addr
) < ntohl (cp
->addr
.ipv4
.s_addr
))
460 if (ntohl (si
->addr
.ipv4
.s_addr
) > ntohl (cp
->addr
.ipv4
.s_addr
))
465 /* Make linked list. */
475 /* Install into rib. */
476 static_install_route (afi
, safi
, p
, si
);
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
)
487 struct route_node
*rn
;
488 struct static_route
*si
;
489 struct route_table
*stable
;
492 stable
= zebra_vrf_static_table (afi
, safi
, zvrf
);
496 /* Lookup static route prefix. */
497 rn
= route_node_lookup (stable
, p
);
501 /* Find same static route is the tree */
502 for (si
= rn
->info
; si
; si
= si
->next
)
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
))))
513 /* Can't find static route. */
516 route_unlock_node (rn
);
520 /* Install into rib. */
521 static_uninstall_route (afi
, safi
, p
, si
);
523 /* Unlink static route from linked list. */
525 si
->prev
->next
= si
->next
;
529 si
->next
->prev
= si
->prev
;
530 route_unlock_node (rn
);
532 /* Free static route configuration. */
533 XFREE (MTYPE_STATIC_ROUTE
, si
);
535 route_unlock_node (rn
);