1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2018 Cumulus Networks, Inc.
15 #include "srcdest_table.h"
23 #include "nexthop_group.h"
27 #include "static_vrf.h"
28 #include "static_routes.h"
29 #include "static_zebra.h"
30 #include "static_nht.h"
31 #include "static_vty.h"
32 #include "static_debug.h"
34 DEFINE_MTYPE_STATIC(STATIC
, STATIC_NHT_DATA
, "Static Nexthop tracking data");
35 PREDECL_HASH(static_nht_hash
);
37 struct static_nht_data
{
38 struct static_nht_hash_item itm
;
50 static int static_nht_data_cmp(const struct static_nht_data
*nhtd1
,
51 const struct static_nht_data
*nhtd2
)
53 if (nhtd1
->nh_vrf_id
!= nhtd2
->nh_vrf_id
)
54 return numcmp(nhtd1
->nh_vrf_id
, nhtd2
->nh_vrf_id
);
55 if (nhtd1
->safi
!= nhtd2
->safi
)
56 return numcmp(nhtd1
->safi
, nhtd2
->safi
);
58 return prefix_cmp(&nhtd1
->nh
, &nhtd2
->nh
);
61 static unsigned int static_nht_data_hash(const struct static_nht_data
*nhtd
)
65 key
= prefix_hash_key(&nhtd
->nh
);
66 return jhash_2words(nhtd
->nh_vrf_id
, nhtd
->safi
, key
);
69 DECLARE_HASH(static_nht_hash
, struct static_nht_data
, itm
, static_nht_data_cmp
,
70 static_nht_data_hash
);
72 static struct static_nht_hash_head static_nht_hash
[1];
74 /* Zebra structure to hold current status. */
75 struct zclient
*zclient
;
76 uint32_t zebra_ecmp_count
= MULTIPATH_NUM
;
78 /* Interface addition message from zebra. */
79 static int static_ifp_create(struct interface
*ifp
)
81 static_ifindex_update(ifp
, true);
86 static int static_ifp_destroy(struct interface
*ifp
)
88 static_ifindex_update(ifp
, false);
92 static int interface_address_add(ZAPI_CALLBACK_ARGS
)
94 zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
99 static int interface_address_delete(ZAPI_CALLBACK_ARGS
)
103 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
112 static int static_ifp_up(struct interface
*ifp
)
114 /* Install any static reliant on this interface coming up */
115 static_install_intf_nh(ifp
);
116 static_ifindex_update(ifp
, true);
121 static int static_ifp_down(struct interface
*ifp
)
123 static_ifindex_update(ifp
, false);
128 static int route_notify_owner(ZAPI_CALLBACK_ARGS
)
131 enum zapi_route_notify_owner note
;
135 if (!zapi_route_notify_decode(zclient
->ibuf
, &p
, &table_id
, ¬e
, NULL
,
140 case ZAPI_ROUTE_FAIL_INSTALL
:
141 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_NOT_INSTALLED
);
142 zlog_warn("%s: Route %pFX failed to install for table: %u",
143 __func__
, &p
, table_id
);
145 case ZAPI_ROUTE_BETTER_ADMIN_WON
:
146 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_NOT_INSTALLED
);
148 "%s: Route %pFX over-ridden by better route for table: %u",
149 __func__
, &p
, table_id
);
151 case ZAPI_ROUTE_INSTALLED
:
152 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_INSTALLED
);
154 case ZAPI_ROUTE_REMOVED
:
155 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_NOT_INSTALLED
);
157 case ZAPI_ROUTE_REMOVE_FAIL
:
158 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_INSTALLED
);
159 zlog_warn("%s: Route %pFX failure to remove for table: %u",
160 __func__
, &p
, table_id
);
167 static void zebra_connected(struct zclient
*zclient
)
169 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
171 static_fixup_vrf_ids(vrf_info_lookup(VRF_DEFAULT
));
174 /* API to check whether the configured nexthop address is
175 * one of its local connected address or not.
178 static_nexthop_is_local(vrf_id_t vrfid
, struct prefix
*addr
, int family
)
180 if (family
== AF_INET
) {
181 if (if_address_is_local(&addr
->u
.prefix4
, AF_INET
, vrfid
))
183 } else if (family
== AF_INET6
) {
184 if (if_address_is_local(&addr
->u
.prefix6
, AF_INET6
, vrfid
))
189 static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS
)
191 struct static_nht_data
*nhtd
, lookup
;
192 struct zapi_route nhr
;
193 struct prefix matched
;
196 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &matched
, &nhr
)) {
197 zlog_err("Failure to decode nexthop update message");
201 if (zclient
->bfd_integration
)
202 bfd_nht_update(&matched
, &nhr
);
204 if (matched
.family
== AF_INET6
)
207 if (nhr
.type
== ZEBRA_ROUTE_CONNECT
) {
208 if (static_nexthop_is_local(vrf_id
, &matched
,
213 memset(&lookup
, 0, sizeof(lookup
));
215 lookup
.nh_vrf_id
= vrf_id
;
216 lookup
.safi
= nhr
.safi
;
218 nhtd
= static_nht_hash_find(static_nht_hash
, &lookup
);
221 nhtd
->nh_num
= nhr
.nexthop_num
;
223 static_nht_reset_start(&matched
, afi
, nhr
.safi
,
225 static_nht_update(NULL
, &matched
, nhr
.nexthop_num
, afi
,
226 nhr
.safi
, nhtd
->nh_vrf_id
);
228 zlog_err("No nhtd?");
233 static void static_zebra_capabilities(struct zclient_capabilities
*cap
)
235 mpls_enabled
= cap
->mpls_enabled
;
236 zebra_ecmp_count
= cap
->ecmp
;
239 static struct static_nht_data
*
240 static_nht_hash_getref(const struct static_nht_data
*ref
)
242 struct static_nht_data
*nhtd
;
244 nhtd
= static_nht_hash_find(static_nht_hash
, ref
);
246 nhtd
= XCALLOC(MTYPE_STATIC_NHT_DATA
, sizeof(*nhtd
));
248 prefix_copy(&nhtd
->nh
, &ref
->nh
);
249 nhtd
->nh_vrf_id
= ref
->nh_vrf_id
;
250 nhtd
->safi
= ref
->safi
;
252 static_nht_hash_add(static_nht_hash
, nhtd
);
259 static bool static_nht_hash_decref(struct static_nht_data
**nhtd_p
)
261 struct static_nht_data
*nhtd
= *nhtd_p
;
265 if (--nhtd
->refcount
> 0)
268 static_nht_hash_del(static_nht_hash
, nhtd
);
269 XFREE(MTYPE_STATIC_NHT_DATA
, nhtd
);
273 static void static_nht_hash_clear(void)
275 struct static_nht_data
*nhtd
;
277 while ((nhtd
= static_nht_hash_pop(static_nht_hash
)))
278 XFREE(MTYPE_STATIC_NHT_DATA
, nhtd
);
281 static bool static_zebra_nht_get_prefix(const struct static_nexthop
*nh
,
286 case STATIC_BLACKHOLE
:
287 p
->family
= AF_UNSPEC
;
290 case STATIC_IPV4_GATEWAY
:
291 case STATIC_IPV4_GATEWAY_IFNAME
:
293 p
->prefixlen
= IPV4_MAX_BITLEN
;
294 p
->u
.prefix4
= nh
->addr
.ipv4
;
297 case STATIC_IPV6_GATEWAY
:
298 case STATIC_IPV6_GATEWAY_IFNAME
:
299 p
->family
= AF_INET6
;
300 p
->prefixlen
= IPV6_MAX_BITLEN
;
301 p
->u
.prefix6
= nh
->addr
.ipv6
;
305 assertf(0, "BUG: someone forgot to add nexthop type %u", nh
->type
);
309 void static_zebra_nht_register(struct static_nexthop
*nh
, bool reg
)
311 struct static_path
*pn
= nh
->pn
;
312 struct route_node
*rn
= pn
->rn
;
313 struct static_route_info
*si
= static_route_info_from_rnode(rn
);
314 struct static_nht_data
*nhtd
, lookup
= {};
317 if (!static_zebra_nht_get_prefix(nh
, &lookup
.nh
))
319 lookup
.nh_vrf_id
= nh
->nh_vrf_id
;
320 lookup
.safi
= si
->safi
;
322 if (nh
->nh_registered
) {
323 /* nh->nh_registered means we own a reference on the nhtd */
324 nhtd
= static_nht_hash_find(static_nht_hash
, &lookup
);
326 assertf(nhtd
, "BUG: NH %pFX registered but not in hashtable",
329 nhtd
= static_nht_hash_getref(&lookup
);
331 if (nhtd
->refcount
> 1)
332 DEBUGD(&static_dbg_route
,
333 "Reusing registered nexthop(%pFX) for %pRN %d",
334 &lookup
.nh
, rn
, nhtd
->nh_num
);
336 /* !reg && !nh->nh_registered */
337 zlog_warn("trying to unregister nexthop %pFX twice",
342 nh
->nh_registered
= reg
;
346 /* refresh with existing data */
347 afi_t afi
= prefix_afi(&lookup
.nh
);
349 if (nh
->state
== STATIC_NOT_INSTALLED
)
350 nh
->state
= STATIC_START
;
351 static_nht_update(&rn
->p
, &nhtd
->nh
, nhtd
->nh_num
, afi
,
352 si
->safi
, nh
->nh_vrf_id
);
356 if (nhtd
->registered
)
357 /* have no data, but did send register */
360 cmd
= ZEBRA_NEXTHOP_REGISTER
;
361 DEBUGD(&static_dbg_route
, "Registering nexthop(%pFX) for %pRN",
364 bool was_zebra_registered
;
366 was_zebra_registered
= nhtd
->registered
;
367 if (static_nht_hash_decref(&nhtd
))
368 /* still got references alive */
371 /* NB: nhtd is now NULL. */
372 if (!was_zebra_registered
)
375 cmd
= ZEBRA_NEXTHOP_UNREGISTER
;
376 DEBUGD(&static_dbg_route
,
377 "Unregistering nexthop(%pFX) for %pRN", &lookup
.nh
, rn
);
380 if (zclient_send_rnh(zclient
, cmd
, &lookup
.nh
, si
->safi
, false, false,
381 nh
->nh_vrf_id
) == ZCLIENT_SEND_FAILURE
)
382 zlog_warn("%s: Failure to send nexthop %pFX for %pRN to zebra",
383 __func__
, &lookup
.nh
, rn
);
385 nhtd
->registered
= true;
388 extern void static_zebra_route_add(struct static_path
*pn
, bool install
)
390 struct route_node
*rn
= pn
->rn
;
391 struct static_route_info
*si
= rn
->info
;
392 struct static_nexthop
*nh
;
393 const struct prefix
*p
, *src_pp
;
394 struct zapi_nexthop
*api_nh
;
395 struct zapi_route api
;
399 srcdest_rnode_prefixes(rn
, &p
, &src_pp
);
401 memset(&api
, 0, sizeof(api
));
402 api
.vrf_id
= si
->svrf
->vrf
->vrf_id
;
403 api
.type
= ZEBRA_ROUTE_STATIC
;
405 memcpy(&api
.prefix
, p
, sizeof(api
.prefix
));
408 SET_FLAG(api
.message
, ZAPI_MESSAGE_SRCPFX
);
409 memcpy(&api
.src_prefix
, src_pp
, sizeof(api
.src_prefix
));
411 SET_FLAG(api
.flags
, ZEBRA_FLAG_RR_USE_DISTANCE
);
412 SET_FLAG(api
.flags
, ZEBRA_FLAG_ALLOW_RECURSION
);
413 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
415 SET_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
);
416 api
.distance
= pn
->distance
;
419 SET_FLAG(api
.message
, ZAPI_MESSAGE_TAG
);
422 if (pn
->table_id
!= 0) {
423 SET_FLAG(api
.message
, ZAPI_MESSAGE_TABLEID
);
424 api
.tableid
= pn
->table_id
;
426 frr_each(static_nexthop_list
, &pn
->nexthop_list
, nh
) {
427 /* Don't overrun the nexthop array */
428 if (nh_num
== zebra_ecmp_count
)
431 api_nh
= &api
.nexthops
[nh_num
];
432 if (nh
->nh_vrf_id
== VRF_UNKNOWN
)
434 /* Skip next hop which peer is down. */
438 api_nh
->vrf_id
= nh
->nh_vrf_id
;
440 SET_FLAG(api_nh
->flags
, ZAPI_NEXTHOP_FLAG_ONLINK
);
441 if (nh
->color
!= 0) {
442 SET_FLAG(api
.message
, ZAPI_MESSAGE_SRTE
);
443 api_nh
->srte_color
= nh
->color
;
446 nh
->state
= STATIC_SENT_TO_ZEBRA
;
450 if (nh
->ifindex
== IFINDEX_INTERNAL
)
452 api_nh
->ifindex
= nh
->ifindex
;
453 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
455 case STATIC_IPV4_GATEWAY
:
458 api_nh
->type
= NEXTHOP_TYPE_IPV4
;
459 api_nh
->gate
= nh
->addr
;
461 case STATIC_IPV4_GATEWAY_IFNAME
:
462 if (nh
->ifindex
== IFINDEX_INTERNAL
)
464 api_nh
->ifindex
= nh
->ifindex
;
465 api_nh
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
466 api_nh
->gate
= nh
->addr
;
468 case STATIC_IPV6_GATEWAY
:
471 api_nh
->type
= NEXTHOP_TYPE_IPV6
;
472 api_nh
->gate
= nh
->addr
;
474 case STATIC_IPV6_GATEWAY_IFNAME
:
475 if (nh
->ifindex
== IFINDEX_INTERNAL
)
477 api_nh
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
478 api_nh
->ifindex
= nh
->ifindex
;
479 api_nh
->gate
= nh
->addr
;
481 case STATIC_BLACKHOLE
:
482 api_nh
->type
= NEXTHOP_TYPE_BLACKHOLE
;
483 switch (nh
->bh_type
) {
484 case STATIC_BLACKHOLE_DROP
:
485 case STATIC_BLACKHOLE_NULL
:
486 api_nh
->bh_type
= BLACKHOLE_NULL
;
488 case STATIC_BLACKHOLE_REJECT
:
489 api_nh
->bh_type
= BLACKHOLE_REJECT
;
494 if (nh
->snh_label
.num_labels
) {
497 SET_FLAG(api_nh
->flags
, ZAPI_NEXTHOP_FLAG_LABEL
);
498 api_nh
->label_num
= nh
->snh_label
.num_labels
;
499 for (i
= 0; i
< api_nh
->label_num
; i
++)
500 api_nh
->labels
[i
] = nh
->snh_label
.label
[i
];
505 api
.nexthop_num
= nh_num
;
508 * If we have been given an install but nothing is valid
509 * go ahead and delete the route for double plus fun
511 if (!nh_num
&& install
)
514 zclient_route_send(install
?
515 ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE
,
519 static zclient_handler
*const static_handlers
[] = {
520 [ZEBRA_INTERFACE_ADDRESS_ADD
] = interface_address_add
,
521 [ZEBRA_INTERFACE_ADDRESS_DELETE
] = interface_address_delete
,
522 [ZEBRA_ROUTE_NOTIFY_OWNER
] = route_notify_owner
,
523 [ZEBRA_NEXTHOP_UPDATE
] = static_zebra_nexthop_update
,
526 void static_zebra_init(void)
528 struct zclient_options opt
= { .receive_notify
= true };
530 if_zapi_callbacks(static_ifp_create
, static_ifp_up
,
531 static_ifp_down
, static_ifp_destroy
);
533 zclient
= zclient_new(master
, &opt
, static_handlers
,
534 array_size(static_handlers
));
536 zclient_init(zclient
, ZEBRA_ROUTE_STATIC
, 0, &static_privs
);
537 zclient
->zebra_capabilities
= static_zebra_capabilities
;
538 zclient
->zebra_connected
= zebra_connected
;
540 static_nht_hash_init(static_nht_hash
);
541 static_bfd_initialize(zclient
, master
);
544 /* static_zebra_stop used by tests/lib/test_grpc.cpp */
545 void static_zebra_stop(void)
547 static_nht_hash_clear();
548 static_nht_hash_fini(static_nht_hash
);
552 zclient_stop(zclient
);
553 zclient_free(zclient
);
557 void static_zebra_vrf_register(struct vrf
*vrf
)
559 if (vrf
->vrf_id
== VRF_DEFAULT
)
561 zclient_send_reg_requests(zclient
, vrf
->vrf_id
);
564 void static_zebra_vrf_unregister(struct vrf
*vrf
)
566 if (vrf
->vrf_id
== VRF_DEFAULT
)
568 zclient_send_dereg_requests(zclient
, vrf
->vrf_id
);