]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_static.c
zebra: static: update on ifindex changes
[mirror_frr.git] / zebra / zebra_static.c
1 /*
2 * Static Routing Information code
3 * Copyright (C) 2016 Cumulus Networks
4 * Donald Sharp
5 *
6 * This file is part of Quagga.
7 *
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
11 * later version.
12 *
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.
17 *
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
21 */
22 #include <zebra.h>
23
24 #include <lib/nexthop.h>
25 #include <lib/memory.h>
26 #include <lib/srcdest_table.h>
27 #include <lib/if.h>
28
29 #include "vty.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"
38
39 /* Install static route into rib. */
40 void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
41 struct prefix_ipv6 *src_p, struct static_route *si)
42 {
43 struct route_entry *re;
44 struct route_node *rn;
45 struct route_table *table;
46 struct prefix nh_p;
47 struct nexthop *nexthop = NULL;
48
49 /* Lookup table. */
50 table = zebra_vrf_table(afi, safi, si->vrf_id);
51 if (!table)
52 return;
53
54 memset(&nh_p, 0, sizeof(nh_p));
55
56 /* Lookup existing route */
57 rn = srcdest_rnode_get(table, p, src_p);
58 RNODE_FOREACH_RE(rn, re)
59 {
60 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
61 continue;
62
63 if (re->type == ZEBRA_ROUTE_STATIC
64 && re->distance == si->distance)
65 break;
66 }
67
68 if (re) {
69 /* if tag value changed , update old value in RIB */
70 if (re->tag != si->tag)
71 re->tag = si->tag;
72
73 /* Same distance static route is there. Update it with new
74 nexthop. */
75 route_unlock_node(rn);
76 switch (si->type) {
77 case STATIC_IPV4_GATEWAY:
78 nexthop = route_entry_nexthop_ipv4_add(
79 re, &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);
84 break;
85 case STATIC_IPV4_GATEWAY_IFNAME:
86 nexthop = route_entry_nexthop_ipv4_ifindex_add(
87 re, &si->addr.ipv4, NULL, si->ifindex);
88 break;
89 case STATIC_IFNAME:
90 nexthop = route_entry_nexthop_ifindex_add(re,
91 si->ifindex);
92 break;
93 case STATIC_BLACKHOLE:
94 nexthop = route_entry_nexthop_blackhole_add(re);
95 break;
96 case STATIC_IPV6_GATEWAY:
97 nexthop = route_entry_nexthop_ipv6_add(re,
98 &si->addr.ipv6);
99 nh_p.family = AF_INET6;
100 nh_p.prefixlen = IPV6_MAX_BITLEN;
101 nh_p.u.prefix6 = si->addr.ipv6;
102 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
103 break;
104 case STATIC_IPV6_GATEWAY_IFNAME:
105 nexthop = route_entry_nexthop_ipv6_ifindex_add(
106 re, &si->addr.ipv6, si->ifindex);
107 break;
108 }
109 /* Update label(s), if present. */
110 if (si->snh_label.num_labels)
111 nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC,
112 si->snh_label.num_labels,
113 &si->snh_label.label[0]);
114
115 if (IS_ZEBRA_DEBUG_RIB) {
116 char buf[INET6_ADDRSTRLEN];
117 if (IS_ZEBRA_DEBUG_RIB) {
118 inet_ntop(p->family, &p->u.prefix, buf,
119 INET6_ADDRSTRLEN);
120 zlog_debug(
121 "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
122 si->vrf_id, buf, p->prefixlen, rn, re,
123 re->type);
124 }
125 }
126 /* Schedule route for processing or invoke NHT, as appropriate.
127 */
128 if (si->type == STATIC_IPV4_GATEWAY
129 || si->type == STATIC_IPV6_GATEWAY)
130 zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1,
131 RNH_NEXTHOP_TYPE, &nh_p);
132 else
133 rib_queue_add(rn);
134 } else {
135 /* This is new static route. */
136 re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
137
138 re->type = ZEBRA_ROUTE_STATIC;
139 re->instance = 0;
140 re->distance = si->distance;
141 re->metric = 0;
142 re->mtu = 0;
143 re->vrf_id = si->vrf_id;
144 re->table =
145 si->vrf_id
146 ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id
147 : zebrad.rtm_table_default;
148 re->nexthop_num = 0;
149 re->tag = si->tag;
150
151 switch (si->type) {
152 case STATIC_IPV4_GATEWAY:
153 nexthop = route_entry_nexthop_ipv4_add(
154 re, &si->addr.ipv4, NULL);
155 nh_p.family = AF_INET;
156 nh_p.prefixlen = IPV4_MAX_BITLEN;
157 nh_p.u.prefix4 = si->addr.ipv4;
158 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
159 break;
160 case STATIC_IPV4_GATEWAY_IFNAME:
161 nexthop = route_entry_nexthop_ipv4_ifindex_add(
162 re, &si->addr.ipv4, NULL, si->ifindex);
163 break;
164 case STATIC_IFNAME:
165 nexthop = route_entry_nexthop_ifindex_add(re,
166 si->ifindex);
167 break;
168 case STATIC_BLACKHOLE:
169 nexthop = route_entry_nexthop_blackhole_add(re);
170 break;
171 case STATIC_IPV6_GATEWAY:
172 nexthop = route_entry_nexthop_ipv6_add(re,
173 &si->addr.ipv6);
174 nh_p.family = AF_INET6;
175 nh_p.prefixlen = IPV6_MAX_BITLEN;
176 nh_p.u.prefix6 = si->addr.ipv6;
177 zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
178 break;
179 case STATIC_IPV6_GATEWAY_IFNAME:
180 nexthop = route_entry_nexthop_ipv6_ifindex_add(
181 re, &si->addr.ipv6, si->ifindex);
182 break;
183 }
184 /* Update label(s), if present. */
185 if (si->snh_label.num_labels)
186 nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC,
187 si->snh_label.num_labels,
188 &si->snh_label.label[0]);
189
190 /* Save the flags of this static routes (reject, blackhole) */
191 re->flags = si->flags;
192
193 if (IS_ZEBRA_DEBUG_RIB) {
194 char buf[INET6_ADDRSTRLEN];
195 if (IS_ZEBRA_DEBUG_RIB) {
196 inet_ntop(p->family, &p->u.prefix, buf,
197 INET6_ADDRSTRLEN);
198 zlog_debug(
199 "%u:%s/%d: Inserting route rn %p, re %p (type %d)",
200 si->vrf_id, buf, p->prefixlen, rn, re,
201 re->type);
202 }
203 }
204 /* Link this re to the tree. Schedule for processing or invoke
205 * NHT,
206 * as appropriate.
207 */
208 if (si->type == STATIC_IPV4_GATEWAY
209 || si->type == STATIC_IPV6_GATEWAY) {
210 rib_addnode(rn, re, 0);
211 zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1,
212 RNH_NEXTHOP_TYPE, &nh_p);
213 } else
214 rib_addnode(rn, re, 1);
215 }
216 }
217
218 /* this works correctly with IFNAME<>IFINDEX because a static route on a
219 * non-active interface will have IFINDEX_INTERNAL and thus compare false
220 */
221 static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si)
222 {
223 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
224 && si->type == STATIC_BLACKHOLE)
225 return 1;
226
227 if (nexthop->type == NEXTHOP_TYPE_IPV4
228 && si->type == STATIC_IPV4_GATEWAY
229 && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4))
230 return 1;
231 else if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
232 && si->type == STATIC_IPV4_GATEWAY_IFNAME
233 && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4)
234 && nexthop->ifindex == si->ifindex)
235 return 1;
236 else if (nexthop->type == NEXTHOP_TYPE_IFINDEX
237 && si->type == STATIC_IFNAME
238 && nexthop->ifindex == si->ifindex)
239 return 1;
240 else if (nexthop->type == NEXTHOP_TYPE_IPV6
241 && si->type == STATIC_IPV6_GATEWAY
242 && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6))
243 return 1;
244 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
245 && si->type == STATIC_IPV6_GATEWAY_IFNAME
246 && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6)
247 && nexthop->ifindex == si->ifindex)
248 return 1;
249
250 return 0;
251 }
252
253 /* Uninstall static route from RIB. */
254 void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
255 struct prefix_ipv6 *src_p, struct static_route *si)
256 {
257 struct route_node *rn;
258 struct route_entry *re;
259 struct nexthop *nexthop;
260 struct route_table *table;
261 struct prefix nh_p;
262
263 /* Lookup table. */
264 table = zebra_vrf_table(afi, safi, si->vrf_id);
265 if (!table)
266 return;
267
268 /* Lookup existing route with type and distance. */
269 rn = srcdest_rnode_lookup(table, p, src_p);
270 if (!rn)
271 return;
272
273 RNODE_FOREACH_RE(rn, re)
274 {
275 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
276 continue;
277
278 if (re->type == ZEBRA_ROUTE_STATIC
279 && re->distance == si->distance && re->tag == si->tag)
280 break;
281 }
282
283 if (!re) {
284 route_unlock_node(rn);
285 return;
286 }
287
288 /* Lookup nexthop. */
289 for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
290 if (static_nexthop_same(nexthop, si))
291 break;
292
293 /* Can't find nexthop. */
294 if (!nexthop) {
295 route_unlock_node(rn);
296 return;
297 }
298
299 /* Check nexthop. */
300 if (re->nexthop_num == 1)
301 rib_delnode(rn, re);
302 else {
303 /* Mark this nexthop as inactive and reinstall the route. Then,
304 * delete
305 * the nexthop. There is no need to re-evaluate the route for
306 * this
307 * scenario.
308 */
309 if (IS_ZEBRA_DEBUG_RIB) {
310 char buf[INET6_ADDRSTRLEN];
311 if (IS_ZEBRA_DEBUG_RIB) {
312 inet_ntop(p->family, &p->u.prefix, buf,
313 INET6_ADDRSTRLEN);
314 zlog_debug(
315 "%u:%s/%d: Modifying route rn %p, re %p (type %d)",
316 si->vrf_id, buf, p->prefixlen, rn, re,
317 re->type);
318 }
319 }
320 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
321 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
322 /* If there are other active nexthops, do an update. */
323 if (re->nexthop_active_num > 1) {
324 /* Update route in kernel if it's in fib */
325 if (CHECK_FLAG(re->status,
326 ROUTE_ENTRY_SELECTED_FIB))
327 rib_install_kernel(rn, re, re);
328 /* Update redistribution if it's selected */
329 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
330 redistribute_update(
331 p, (struct prefix *)src_p, re,
332 NULL);
333 } else {
334 /* Remove from redistribute if selected route
335 * becomes inactive */
336 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
337 redistribute_delete(
338 p, (struct prefix *)src_p, re);
339 /* Remove from kernel if fib route becomes
340 * inactive */
341 if (CHECK_FLAG(re->status,
342 ROUTE_ENTRY_SELECTED_FIB))
343 rib_uninstall_kernel(rn, re);
344 }
345 }
346
347 if (afi == AFI_IP) {
348 /* Delete the nexthop and dereg from NHT */
349 nh_p.family = AF_INET;
350 nh_p.prefixlen = IPV4_MAX_BITLEN;
351 nh_p.u.prefix4 = nexthop->gate.ipv4;
352 } else {
353 nh_p.family = AF_INET6;
354 nh_p.prefixlen = IPV6_MAX_BITLEN;
355 nh_p.u.prefix6 = nexthop->gate.ipv6;
356 }
357 route_entry_nexthop_delete(re, nexthop);
358 zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn);
359 nexthop_free(nexthop);
360 }
361 /* Unlock node. */
362 route_unlock_node(rn);
363 }
364
365 int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
366 struct prefix_ipv6 *src_p, union g_addr *gate,
367 const char *ifname, u_char flags,
368 route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
369 struct static_nh_label *snh_label)
370 {
371 struct route_node *rn;
372 struct static_route *si;
373 struct static_route *pp;
374 struct static_route *cp;
375 struct static_route *update = NULL;
376 struct route_table *stable = zvrf->stable[afi][safi];
377
378 if (!stable)
379 return -1;
380
381 if (!gate
382 && (type == STATIC_IPV4_GATEWAY
383 || type == STATIC_IPV4_GATEWAY_IFNAME
384 || type == STATIC_IPV6_GATEWAY
385 || type == STATIC_IPV6_GATEWAY_IFNAME))
386 return -1;
387
388 if (!ifname
389 && (type == STATIC_IFNAME
390 || type == STATIC_IPV4_GATEWAY_IFNAME
391 || type == STATIC_IPV6_GATEWAY_IFNAME))
392 return -1;
393
394 /* Lookup static route prefix. */
395 rn = srcdest_rnode_get(stable, p, src_p);
396
397 /* Do nothing if there is a same static route. */
398 for (si = rn->info; si; si = si->next) {
399 if (type == si->type
400 && (!gate || ((afi == AFI_IP
401 && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
402 || (afi == AFI_IP6
403 && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
404 && (!strcmp (ifname ? ifname : "", si->ifname))) {
405 if ((distance == si->distance) && (tag == si->tag)
406 && !memcmp(&si->snh_label, snh_label,
407 sizeof(struct static_nh_label))
408 && si->flags == flags) {
409 route_unlock_node(rn);
410 return 0;
411 } else
412 update = si;
413 }
414 }
415
416 /* Distance or tag or label changed, delete existing first. */
417 if (update)
418 static_delete_route(afi, safi, type, p, src_p, gate, ifname,
419 update->tag, update->distance, zvrf,
420 &update->snh_label);
421
422 /* Make new static route structure. */
423 si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route));
424
425 si->type = type;
426 si->distance = distance;
427 si->flags = flags;
428 si->tag = tag;
429 si->vrf_id = zvrf_id(zvrf);
430 if (ifname)
431 strlcpy(si->ifname, ifname, sizeof(si->ifname));
432 si->ifindex = IFINDEX_INTERNAL;
433
434 switch (type) {
435 case STATIC_IPV4_GATEWAY:
436 case STATIC_IPV4_GATEWAY_IFNAME:
437 si->addr.ipv4 = gate->ipv4;
438 break;
439 case STATIC_IPV6_GATEWAY:
440 case STATIC_IPV6_GATEWAY_IFNAME:
441 si->addr.ipv6 = gate->ipv6;
442 break;
443 case STATIC_IFNAME:
444 break;
445 }
446
447 /* Save labels, if any. */
448 memcpy(&si->snh_label, snh_label, sizeof(struct static_nh_label));
449
450 /* Add new static route information to the tree with sort by
451 distance value and gateway address. */
452 for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) {
453 if (si->distance < cp->distance)
454 break;
455 if (si->distance > cp->distance)
456 continue;
457 if (si->type == STATIC_IPV4_GATEWAY
458 && cp->type == STATIC_IPV4_GATEWAY) {
459 if (ntohl(si->addr.ipv4.s_addr)
460 < ntohl(cp->addr.ipv4.s_addr))
461 break;
462 if (ntohl(si->addr.ipv4.s_addr)
463 > ntohl(cp->addr.ipv4.s_addr))
464 continue;
465 }
466 }
467
468 /* Make linked list. */
469 if (pp)
470 pp->next = si;
471 else
472 rn->info = si;
473 if (cp)
474 cp->prev = si;
475 si->prev = pp;
476 si->next = cp;
477
478 /* check whether interface exists in system & install if it does */
479 if (!ifname)
480 static_install_route(afi, safi, p, src_p, si);
481 else {
482 struct interface *ifp;
483
484 ifp = if_lookup_by_name(ifname, zvrf_id(zvrf));
485 if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
486 si->ifindex = ifp->ifindex;
487 static_install_route(afi, safi, p, src_p, si);
488 }
489 }
490
491 return 1;
492 }
493
494 int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
495 struct prefix_ipv6 *src_p, union g_addr *gate,
496 const char *ifname, route_tag_t tag, u_char distance,
497 struct zebra_vrf *zvrf,
498 struct static_nh_label *snh_label)
499 {
500 struct route_node *rn;
501 struct static_route *si;
502 struct route_table *stable;
503
504 /* Lookup table. */
505 stable = zebra_vrf_static_table(afi, safi, zvrf);
506 if (!stable)
507 return -1;
508
509 /* Lookup static route prefix. */
510 rn = srcdest_rnode_lookup(stable, p, src_p);
511 if (!rn)
512 return 0;
513
514 /* Find same static route is the tree */
515 for (si = rn->info; si; si = si->next)
516 if (type == si->type
517 && (!gate || ((afi == AFI_IP
518 && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
519 || (afi == AFI_IP6
520 && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
521 && (!strcmp(ifname ? ifname : "", si->ifname))
522 && (!tag || (tag == si->tag))
523 && (!snh_label->num_labels
524 || !memcmp(&si->snh_label, snh_label,
525 sizeof(struct static_nh_label))))
526 break;
527
528 /* Can't find static route. */
529 if (!si) {
530 route_unlock_node(rn);
531 return 0;
532 }
533
534 /* Uninstall from rib. */
535 if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL)
536 static_uninstall_route(afi, safi, p, src_p, si);
537
538 /* Unlink static route from linked list. */
539 if (si->prev)
540 si->prev->next = si->next;
541 else
542 rn->info = si->next;
543 if (si->next)
544 si->next->prev = si->prev;
545 route_unlock_node(rn);
546
547 /* Free static route configuration. */
548 XFREE(MTYPE_STATIC_ROUTE, si);
549
550 route_unlock_node(rn);
551
552 return 1;
553 }
554
555 static void static_ifindex_update_af(struct interface *ifp, bool up,
556 afi_t afi, safi_t safi)
557 {
558 struct route_table *stable;
559 struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
560 struct route_node *rn;
561 struct static_route *si;
562 struct prefix *p, *src_pp;
563 struct prefix_ipv6 *src_p;
564
565 stable = zebra_vrf_static_table(afi, safi, zvrf);
566 if (!stable)
567 return;
568
569 for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
570 srcdest_rnode_prefixes(rn, &p, &src_pp);
571 src_p = (struct prefix_ipv6 *)src_pp;
572
573 for (si = rn->info; si; si = si->next) {
574 if (!si->ifname[0])
575 continue;
576 if (up) {
577 if (strcmp(si->ifname, ifp->name))
578 continue;
579 si->ifindex = ifp->ifindex;
580 static_install_route(afi, safi, p, src_p, si);
581 } else {
582 if (si->ifindex != ifp->ifindex)
583 continue;
584 static_uninstall_route(afi, safi, p, src_p,
585 si);
586 si->ifindex = IFINDEX_INTERNAL;
587 }
588 }
589 }
590 }
591
592 /* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
593 void static_ifindex_update(struct interface *ifp, bool up)
594 {
595 static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST);
596 static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST);
597 static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST);
598 static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
599 }