]> git.proxmox.com Git - mirror_frr.git/blame - staticd/static_zebra.c
Merge pull request #10376 from patrasar/master_pimv6_vtysh
[mirror_frr.git] / staticd / static_zebra.c
CommitLineData
7e24fdf3
DS
1/*
2 * Zebra connect code.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
8d5cbee9
DS
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
7e24fdf3 10 *
8d5cbee9
DS
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
7e24fdf3
DS
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <zebra.h>
21
22#include "thread.h"
23#include "command.h"
24#include "network.h"
25#include "prefix.h"
26#include "routemap.h"
27#include "table.h"
28#include "srcdest_table.h"
29#include "stream.h"
30#include "memory.h"
31#include "zclient.h"
32#include "filter.h"
33#include "plist.h"
34#include "log.h"
35#include "nexthop.h"
36#include "nexthop_group.h"
74f0a94e 37#include "hash.h"
f591b309 38#include "jhash.h"
7e24fdf3
DS
39
40#include "static_vrf.h"
41#include "static_routes.h"
42#include "static_zebra.h"
43#include "static_nht.h"
44#include "static_vty.h"
b2f6ab67 45#include "static_debug.h"
6f5db0b1 46
7e24fdf3
DS
47/* Zebra structure to hold current status. */
48struct zclient *zclient;
74f0a94e 49static struct hash *static_nht_hash;
7e24fdf3 50
7e24fdf3 51/* Inteface addition message from zebra. */
ef7bd2a3 52static int static_ifp_create(struct interface *ifp)
7e24fdf3 53{
7e24fdf3 54 static_ifindex_update(ifp, true);
ef7bd2a3 55
7e24fdf3
DS
56 return 0;
57}
58
3c3c3252 59static int static_ifp_destroy(struct interface *ifp)
7e24fdf3 60{
7e24fdf3
DS
61 static_ifindex_update(ifp, false);
62 return 0;
63}
64
121f9dee 65static int interface_address_add(ZAPI_CALLBACK_ARGS)
7e24fdf3 66{
121f9dee 67 zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
7e24fdf3
DS
68
69 return 0;
70}
71
121f9dee 72static int interface_address_delete(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
73{
74 struct connected *c;
75
121f9dee 76 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
7e24fdf3
DS
77
78 if (!c)
79 return 0;
80
721c0857 81 connected_free(&c);
7e24fdf3
DS
82 return 0;
83}
84
ddbf3e60 85static int static_ifp_up(struct interface *ifp)
7e24fdf3 86{
ddbf3e60
DS
87 /* Install any static reliant on this interface coming up */
88 static_install_intf_nh(ifp);
89 static_ifindex_update(ifp, true);
90
7e24fdf3
DS
91 return 0;
92}
93
b0b69e59 94static int static_ifp_down(struct interface *ifp)
7e24fdf3 95{
b0b69e59 96 static_ifindex_update(ifp, false);
7e24fdf3
DS
97
98 return 0;
99}
100
121f9dee 101static int route_notify_owner(ZAPI_CALLBACK_ARGS)
7e24fdf3
DS
102{
103 struct prefix p;
104 enum zapi_route_notify_owner note;
105 uint32_t table_id;
7e24fdf3 106
77b38a4a
S
107 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note,
108 NULL, NULL))
7e24fdf3
DS
109 return -1;
110
111 switch (note) {
112 case ZAPI_ROUTE_FAIL_INSTALL:
9fafbd15 113 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
2dbe669b
DA
114 zlog_warn("%s: Route %pFX failed to install for table: %u",
115 __func__, &p, table_id);
7e24fdf3
DS
116 break;
117 case ZAPI_ROUTE_BETTER_ADMIN_WON:
9fafbd15 118 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
15569c58 119 zlog_warn(
2dbe669b
DA
120 "%s: Route %pFX over-ridden by better route for table: %u",
121 __func__, &p, table_id);
7e24fdf3
DS
122 break;
123 case ZAPI_ROUTE_INSTALLED:
9fafbd15 124 static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
7e24fdf3
DS
125 break;
126 case ZAPI_ROUTE_REMOVED:
9fafbd15 127 static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED);
7e24fdf3
DS
128 break;
129 case ZAPI_ROUTE_REMOVE_FAIL:
9fafbd15 130 static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED);
2dbe669b
DA
131 zlog_warn("%s: Route %pFX failure to remove for table: %u",
132 __func__, &p, table_id);
7e24fdf3
DS
133 break;
134 }
135
136 return 0;
137}
138static void zebra_connected(struct zclient *zclient)
139{
140 zclient_send_reg_requests(zclient, VRF_DEFAULT);
141}
142
74f0a94e
DS
143struct static_nht_data {
144 struct prefix *nh;
f591b309
DS
145
146 vrf_id_t nh_vrf_id;
147
74f0a94e
DS
148 uint32_t refcount;
149 uint8_t nh_num;
150};
7e24fdf3 151
b1ab2876 152/* API to check whether the configured nexthop address is
153 * one of its local connected address or not.
154 */
155static bool
156static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family)
157{
158 if (family == AF_INET) {
1e9044be 159 if (if_address_is_local(&addr->u.prefix4, AF_INET, vrfid))
b1ab2876 160 return true;
161 } else if (family == AF_INET6) {
1e9044be 162 if (if_address_is_local(&addr->u.prefix6, AF_INET6, vrfid))
b1ab2876 163 return true;
164 }
165 return false;
166}
121f9dee 167static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
7e24fdf3 168{
74f0a94e 169 struct static_nht_data *nhtd, lookup;
7e24fdf3
DS
170 struct zapi_route nhr;
171 afi_t afi = AFI_IP;
172
173 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
6c83dded 174 zlog_err("Failure to decode nexthop update message");
7e24fdf3
DS
175 return 1;
176 }
177
178 if (nhr.prefix.family == AF_INET6)
179 afi = AFI_IP6;
180
b1ab2876 181 if (nhr.type == ZEBRA_ROUTE_CONNECT) {
182 if (static_nexthop_is_local(vrf_id, &nhr.prefix,
183 nhr.prefix.family))
184 nhr.nexthop_num = 0;
185 }
186
74f0a94e
DS
187 memset(&lookup, 0, sizeof(lookup));
188 lookup.nh = &nhr.prefix;
f591b309 189 lookup.nh_vrf_id = vrf_id;
74f0a94e
DS
190
191 nhtd = hash_lookup(static_nht_hash, &lookup);
f591b309
DS
192
193 if (nhtd) {
74f0a94e
DS
194 nhtd->nh_num = nhr.nexthop_num;
195
9fafbd15 196 static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id);
27da3044 197 static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi,
f591b309
DS
198 nhtd->nh_vrf_id);
199 } else
200 zlog_err("No nhtd?");
74f0a94e 201
7e24fdf3
DS
202 return 1;
203}
204
205static void static_zebra_capabilities(struct zclient_capabilities *cap)
206{
207 mpls_enabled = cap->mpls_enabled;
abc246e1 208 zebra_ecmp_count = cap->ecmp;
7e24fdf3
DS
209}
210
d8b87afe 211static unsigned int static_nht_hash_key(const void *data)
74f0a94e 212{
d8b87afe 213 const struct static_nht_data *nhtd = data;
f591b309 214 unsigned int key = 0;
74f0a94e 215
f591b309
DS
216 key = prefix_hash_key(nhtd->nh);
217 return jhash_1word(nhtd->nh_vrf_id, key);
74f0a94e
DS
218}
219
74df8d6d 220static bool static_nht_hash_cmp(const void *d1, const void *d2)
74f0a94e
DS
221{
222 const struct static_nht_data *nhtd1 = d1;
223 const struct static_nht_data *nhtd2 = d2;
224
f591b309 225 if (nhtd1->nh_vrf_id != nhtd2->nh_vrf_id)
74df8d6d 226 return false;
f591b309 227
74f0a94e
DS
228 return prefix_same(nhtd1->nh, nhtd2->nh);
229}
230
231static void *static_nht_hash_alloc(void *data)
232{
233 struct static_nht_data *copy = data;
234 struct static_nht_data *new;
235
236 new = XMALLOC(MTYPE_TMP, sizeof(*new));
237
238 new->nh = prefix_new();
239 prefix_copy(new->nh, copy->nh);
240 new->refcount = 0;
241 new->nh_num = 0;
f591b309 242 new->nh_vrf_id = copy->nh_vrf_id;
74f0a94e
DS
243
244 return new;
245}
246
247static void static_nht_hash_free(void *data)
248{
249 struct static_nht_data *nhtd = data;
250
63265b5c 251 prefix_free(&nhtd->nh);
74f0a94e
DS
252 XFREE(MTYPE_TMP, nhtd);
253}
254
4067e951 255void static_zebra_nht_register(struct static_nexthop *nh, bool reg)
7e24fdf3 256{
4067e951
IR
257 struct static_path *pn = nh->pn;
258 struct route_node *rn = pn->rn;
74f0a94e 259 struct static_nht_data *nhtd, lookup;
7e24fdf3
DS
260 uint32_t cmd;
261 struct prefix p;
74f0a94e 262 afi_t afi = AFI_IP;
7e24fdf3
DS
263
264 cmd = (reg) ?
265 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
266
88fa5104 267 if (nh->nh_registered && reg)
7e24fdf3
DS
268 return;
269
88fa5104 270 if (!nh->nh_registered && !reg)
7e24fdf3
DS
271 return;
272
273 memset(&p, 0, sizeof(p));
88fa5104 274 switch (nh->type) {
7e24fdf3
DS
275 case STATIC_IFNAME:
276 case STATIC_BLACKHOLE:
7e24fdf3
DS
277 return;
278 case STATIC_IPV4_GATEWAY:
88a90016 279 case STATIC_IPV4_GATEWAY_IFNAME:
7e24fdf3
DS
280 p.family = AF_INET;
281 p.prefixlen = IPV4_MAX_BITLEN;
88fa5104 282 p.u.prefix4 = nh->addr.ipv4;
74f0a94e 283 afi = AFI_IP;
7e24fdf3
DS
284 break;
285 case STATIC_IPV6_GATEWAY:
88a90016 286 case STATIC_IPV6_GATEWAY_IFNAME:
7e24fdf3
DS
287 p.family = AF_INET6;
288 p.prefixlen = IPV6_MAX_BITLEN;
88fa5104 289 p.u.prefix6 = nh->addr.ipv6;
74f0a94e 290 afi = AFI_IP6;
7e24fdf3
DS
291 break;
292 }
293
74f0a94e
DS
294 memset(&lookup, 0, sizeof(lookup));
295 lookup.nh = &p;
88fa5104 296 lookup.nh_vrf_id = nh->nh_vrf_id;
74f0a94e 297
88fa5104 298 nh->nh_registered = reg;
74f0a94e
DS
299
300 if (reg) {
301 nhtd = hash_get(static_nht_hash, &lookup,
302 static_nht_hash_alloc);
303 nhtd->refcount++;
304
b2f6ab67 305 DEBUGD(&static_dbg_route,
306 "Registered nexthop(%pFX) for %pRN %d", &p, rn,
307 nhtd->nh_num);
6f5db0b1 308 if (nhtd->refcount > 1 && nhtd->nh_num) {
88fa5104 309 static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi,
310 nh->nh_vrf_id);
74f0a94e
DS
311 return;
312 }
313 } else {
314 nhtd = hash_lookup(static_nht_hash, &lookup);
315 if (!nhtd)
316 return;
317
318 nhtd->refcount--;
319 if (nhtd->refcount >= 1)
320 return;
321
322 hash_release(static_nht_hash, nhtd);
323 static_nht_hash_free(nhtd);
324 }
325
ed6cec97 326 if (zclient_send_rnh(zclient, cmd, &p, false, false, nh->nh_vrf_id)
7cfdb485 327 == ZCLIENT_SEND_FAILURE)
15569c58 328 zlog_warn("%s: Failure to send nexthop to zebra", __func__);
7e24fdf3 329}
88fa5104 330/*
331 * When nexthop gets updated via configuration then use the
332 * already registered NH and resend the route to zebra
333 */
4067e951 334int static_zebra_nh_update(struct static_nexthop *nh)
88fa5104 335{
4067e951
IR
336 struct static_path *pn = nh->pn;
337 struct route_node *rn = pn->rn;
88fa5104 338 struct static_nht_data *nhtd, lookup = {};
339 struct prefix p = {};
340 afi_t afi = AFI_IP;
341
342 if (!nh->nh_registered)
343 return 0;
344
345 switch (nh->type) {
346 case STATIC_IFNAME:
347 case STATIC_BLACKHOLE:
348 return 0;
349 case STATIC_IPV4_GATEWAY:
350 case STATIC_IPV4_GATEWAY_IFNAME:
351 p.family = AF_INET;
352 p.prefixlen = IPV4_MAX_BITLEN;
353 p.u.prefix4 = nh->addr.ipv4;
354 afi = AFI_IP;
355 break;
356 case STATIC_IPV6_GATEWAY:
357 case STATIC_IPV6_GATEWAY_IFNAME:
358 p.family = AF_INET6;
359 p.prefixlen = IPV6_MAX_BITLEN;
360 p.u.prefix6 = nh->addr.ipv6;
361 afi = AFI_IP6;
362 break;
363 }
364
365 lookup.nh = &p;
366 lookup.nh_vrf_id = nh->nh_vrf_id;
367
368 nhtd = hash_lookup(static_nht_hash, &lookup);
369 if (nhtd && nhtd->nh_num) {
370 nh->state = STATIC_START;
371 static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi,
372 nh->nh_vrf_id);
373 return 1;
374 }
375 return 0;
376}
7e24fdf3 377
4067e951 378extern void static_zebra_route_add(struct static_path *pn, bool install)
7e24fdf3 379{
4067e951
IR
380 struct route_node *rn = pn->rn;
381 struct static_route_info *si = rn->info;
88fa5104 382 struct static_nexthop *nh;
7e24fdf3
DS
383 const struct prefix *p, *src_pp;
384 struct zapi_nexthop *api_nh;
385 struct zapi_route api;
386 uint32_t nh_num = 0;
387
388 p = src_pp = NULL;
389 srcdest_rnode_prefixes(rn, &p, &src_pp);
390
391 memset(&api, 0, sizeof(api));
4067e951 392 api.vrf_id = si->svrf->vrf->vrf_id;
7e24fdf3 393 api.type = ZEBRA_ROUTE_STATIC;
4067e951 394 api.safi = si->safi;
7e24fdf3
DS
395 memcpy(&api.prefix, p, sizeof(api.prefix));
396
397 if (src_pp) {
398 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
399 memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
400 }
8bc8de2c 401 SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
6b193087 402 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
7e24fdf3 403 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
88fa5104 404 if (pn->distance) {
8bc8de2c 405 SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
88fa5104 406 api.distance = pn->distance;
8bc8de2c 407 }
88fa5104 408 if (pn->tag) {
8bc8de2c 409 SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
88fa5104 410 api.tag = pn->tag;
8bc8de2c 411 }
88fa5104 412 if (pn->table_id != 0) {
31d4a8e5 413 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
88fa5104 414 api.tableid = pn->table_id;
31d4a8e5 415 }
88fa5104 416 frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
1f7ab1a2
MS
417 /* Don't overrun the nexthop array */
418 if (nh_num == zebra_ecmp_count)
419 break;
420
7e24fdf3 421 api_nh = &api.nexthops[nh_num];
88fa5104 422 if (nh->nh_vrf_id == VRF_UNKNOWN)
95cdbe5d
DS
423 continue;
424
88fa5104 425 api_nh->vrf_id = nh->nh_vrf_id;
426 if (nh->onlink)
68a02e06 427 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
065276ae
SM
428 if (nh->color != 0) {
429 SET_FLAG(api.message, ZAPI_MESSAGE_SRTE);
430 api_nh->srte_color = nh->color;
431 }
fe85601c 432
88fa5104 433 nh->state = STATIC_SENT_TO_ZEBRA;
9fafbd15 434
88fa5104 435 switch (nh->type) {
7e24fdf3 436 case STATIC_IFNAME:
88fa5104 437 if (nh->ifindex == IFINDEX_INTERNAL)
7e24fdf3 438 continue;
88fa5104 439 api_nh->ifindex = nh->ifindex;
7e24fdf3
DS
440 api_nh->type = NEXTHOP_TYPE_IFINDEX;
441 break;
442 case STATIC_IPV4_GATEWAY:
88fa5104 443 if (!nh->nh_valid)
7e24fdf3
DS
444 continue;
445 api_nh->type = NEXTHOP_TYPE_IPV4;
88fa5104 446 api_nh->gate = nh->addr;
7e24fdf3
DS
447 break;
448 case STATIC_IPV4_GATEWAY_IFNAME:
88fa5104 449 if (nh->ifindex == IFINDEX_INTERNAL)
7e24fdf3 450 continue;
88fa5104 451 api_nh->ifindex = nh->ifindex;
7e24fdf3 452 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
88fa5104 453 api_nh->gate = nh->addr;
7e24fdf3
DS
454 break;
455 case STATIC_IPV6_GATEWAY:
88fa5104 456 if (!nh->nh_valid)
7e24fdf3
DS
457 continue;
458 api_nh->type = NEXTHOP_TYPE_IPV6;
88fa5104 459 api_nh->gate = nh->addr;
7e24fdf3
DS
460 break;
461 case STATIC_IPV6_GATEWAY_IFNAME:
88fa5104 462 if (nh->ifindex == IFINDEX_INTERNAL)
7e24fdf3
DS
463 continue;
464 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
88fa5104 465 api_nh->ifindex = nh->ifindex;
466 api_nh->gate = nh->addr;
7e24fdf3
DS
467 break;
468 case STATIC_BLACKHOLE:
469 api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
88fa5104 470 switch (nh->bh_type) {
7e24fdf3
DS
471 case STATIC_BLACKHOLE_DROP:
472 case STATIC_BLACKHOLE_NULL:
473 api_nh->bh_type = BLACKHOLE_NULL;
474 break;
475 case STATIC_BLACKHOLE_REJECT:
476 api_nh->bh_type = BLACKHOLE_REJECT;
477 }
478 break;
479 }
480
88fa5104 481 if (nh->snh_label.num_labels) {
7e24fdf3
DS
482 int i;
483
68a02e06 484 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
88fa5104 485 api_nh->label_num = nh->snh_label.num_labels;
7e24fdf3 486 for (i = 0; i < api_nh->label_num; i++)
88fa5104 487 api_nh->labels[i] = nh->snh_label.label[i];
7e24fdf3
DS
488 }
489 nh_num++;
490 }
491
492 api.nexthop_num = nh_num;
493
494 /*
495 * If we have been given an install but nothing is valid
496 * go ahead and delete the route for double plus fun
497 */
498 if (!nh_num && install)
499 install = false;
500
501 zclient_route_send(install ?
502 ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
503 zclient, &api);
504}
138c5a74 505
a243d1db
DL
506static zclient_handler *const static_handlers[] = {
507 [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
508 [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
509 [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner,
510 [ZEBRA_NEXTHOP_UPDATE] = static_zebra_nexthop_update,
511};
512
7e24fdf3
DS
513void static_zebra_init(void)
514{
515 struct zclient_options opt = { .receive_notify = true };
516
138c5a74
DS
517 if_zapi_callbacks(static_ifp_create, static_ifp_up,
518 static_ifp_down, static_ifp_destroy);
519
a243d1db
DL
520 zclient = zclient_new(master, &opt, static_handlers,
521 array_size(static_handlers));
7e24fdf3
DS
522
523 zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
524 zclient->zebra_capabilities = static_zebra_capabilities;
525 zclient->zebra_connected = zebra_connected;
74f0a94e
DS
526
527 static_nht_hash = hash_create(static_nht_hash_key,
528 static_nht_hash_cmp,
529 "Static Nexthop Tracking hash");
7e24fdf3 530}
fceb6174 531
deca28a3
CH
532/* static_zebra_stop used by tests/lib/test_grpc.cpp */
533void static_zebra_stop(void)
534{
535 if (!zclient)
536 return;
537 zclient_stop(zclient);
538 zclient_free(zclient);
539 zclient = NULL;
540}
541
fceb6174
PG
542void static_zebra_vrf_register(struct vrf *vrf)
543{
544 if (vrf->vrf_id == VRF_DEFAULT)
545 return;
546 zclient_send_reg_requests(zclient, vrf->vrf_id);
547}
548
549void static_zebra_vrf_unregister(struct vrf *vrf)
550{
551 if (vrf->vrf_id == VRF_DEFAULT)
552 return;
553 zclient_send_dereg_requests(zclient, vrf->vrf_id);
554}