3 * Copyright (C) 2018 Cumulus Networks, Inc.
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)
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
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
28 #include "srcdest_table.h"
36 #include "nexthop_group.h"
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"
45 #include "static_debug.h"
47 DEFINE_MTYPE_STATIC(STATIC
, STATIC_NHT_DATA
, "Static Nexthop tracking data");
48 PREDECL_HASH(static_nht_hash
);
50 struct static_nht_data
{
51 struct static_nht_hash_item itm
;
62 static int static_nht_data_cmp(const struct static_nht_data
*nhtd1
,
63 const struct static_nht_data
*nhtd2
)
65 if (nhtd1
->nh_vrf_id
!= nhtd2
->nh_vrf_id
)
66 return numcmp(nhtd1
->nh_vrf_id
, nhtd2
->nh_vrf_id
);
67 if (nhtd1
->safi
!= nhtd2
->safi
)
68 return numcmp(nhtd1
->safi
, nhtd2
->safi
);
70 return prefix_cmp(&nhtd1
->nh
, &nhtd2
->nh
);
73 static unsigned int static_nht_data_hash(const struct static_nht_data
*nhtd
)
77 key
= prefix_hash_key(&nhtd
->nh
);
78 return jhash_2words(nhtd
->nh_vrf_id
, nhtd
->safi
, key
);
81 DECLARE_HASH(static_nht_hash
, struct static_nht_data
, itm
, static_nht_data_cmp
,
82 static_nht_data_hash
);
84 static struct static_nht_hash_head static_nht_hash
[1];
86 /* Zebra structure to hold current status. */
87 struct zclient
*zclient
;
88 uint32_t zebra_ecmp_count
= MULTIPATH_NUM
;
90 /* Inteface addition message from zebra. */
91 static int static_ifp_create(struct interface
*ifp
)
93 static_ifindex_update(ifp
, true);
98 static int static_ifp_destroy(struct interface
*ifp
)
100 static_ifindex_update(ifp
, false);
104 static int interface_address_add(ZAPI_CALLBACK_ARGS
)
106 zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
111 static int interface_address_delete(ZAPI_CALLBACK_ARGS
)
115 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
124 static int static_ifp_up(struct interface
*ifp
)
126 /* Install any static reliant on this interface coming up */
127 static_install_intf_nh(ifp
);
128 static_ifindex_update(ifp
, true);
133 static int static_ifp_down(struct interface
*ifp
)
135 static_ifindex_update(ifp
, false);
140 static int route_notify_owner(ZAPI_CALLBACK_ARGS
)
143 enum zapi_route_notify_owner note
;
147 if (!zapi_route_notify_decode(zclient
->ibuf
, &p
, &table_id
, ¬e
, NULL
,
152 case ZAPI_ROUTE_FAIL_INSTALL
:
153 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_NOT_INSTALLED
);
154 zlog_warn("%s: Route %pFX failed to install for table: %u",
155 __func__
, &p
, table_id
);
157 case ZAPI_ROUTE_BETTER_ADMIN_WON
:
158 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_NOT_INSTALLED
);
160 "%s: Route %pFX over-ridden by better route for table: %u",
161 __func__
, &p
, table_id
);
163 case ZAPI_ROUTE_INSTALLED
:
164 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_INSTALLED
);
166 case ZAPI_ROUTE_REMOVED
:
167 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_NOT_INSTALLED
);
169 case ZAPI_ROUTE_REMOVE_FAIL
:
170 static_nht_mark_state(&p
, safi
, vrf_id
, STATIC_INSTALLED
);
171 zlog_warn("%s: Route %pFX failure to remove for table: %u",
172 __func__
, &p
, table_id
);
178 static void zebra_connected(struct zclient
*zclient
)
180 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
183 /* API to check whether the configured nexthop address is
184 * one of its local connected address or not.
187 static_nexthop_is_local(vrf_id_t vrfid
, struct prefix
*addr
, int family
)
189 if (family
== AF_INET
) {
190 if (if_address_is_local(&addr
->u
.prefix4
, AF_INET
, vrfid
))
192 } else if (family
== AF_INET6
) {
193 if (if_address_is_local(&addr
->u
.prefix6
, AF_INET6
, vrfid
))
198 static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS
)
200 struct static_nht_data
*nhtd
, lookup
;
201 struct zapi_route nhr
;
202 struct prefix matched
;
205 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &matched
, &nhr
)) {
206 zlog_err("Failure to decode nexthop update message");
210 if (matched
.family
== AF_INET6
)
213 if (nhr
.type
== ZEBRA_ROUTE_CONNECT
) {
214 if (static_nexthop_is_local(vrf_id
, &matched
,
219 memset(&lookup
, 0, sizeof(lookup
));
221 lookup
.nh_vrf_id
= vrf_id
;
222 lookup
.safi
= nhr
.safi
;
224 nhtd
= static_nht_hash_find(static_nht_hash
, &lookup
);
227 nhtd
->nh_num
= nhr
.nexthop_num
;
229 static_nht_reset_start(&matched
, afi
, nhr
.safi
,
231 static_nht_update(NULL
, &matched
, nhr
.nexthop_num
, afi
,
232 nhr
.safi
, nhtd
->nh_vrf_id
);
234 zlog_err("No nhtd?");
239 static void static_zebra_capabilities(struct zclient_capabilities
*cap
)
241 mpls_enabled
= cap
->mpls_enabled
;
242 zebra_ecmp_count
= cap
->ecmp
;
245 static struct static_nht_data
*
246 static_nht_hash_getref(const struct static_nht_data
*ref
)
248 struct static_nht_data
*nhtd
;
250 nhtd
= static_nht_hash_find(static_nht_hash
, ref
);
252 nhtd
= XCALLOC(MTYPE_STATIC_NHT_DATA
, sizeof(*nhtd
));
254 prefix_copy(&nhtd
->nh
, &ref
->nh
);
255 nhtd
->nh_vrf_id
= ref
->nh_vrf_id
;
256 nhtd
->safi
= ref
->safi
;
258 static_nht_hash_add(static_nht_hash
, nhtd
);
265 static bool static_nht_hash_decref(struct static_nht_data
*nhtd
)
267 if (--nhtd
->refcount
> 0)
270 static_nht_hash_del(static_nht_hash
, nhtd
);
271 XFREE(MTYPE_STATIC_NHT_DATA
, nhtd
);
275 static void static_nht_hash_clear(void)
277 struct static_nht_data
*nhtd
;
279 while ((nhtd
= static_nht_hash_pop(static_nht_hash
)))
280 XFREE(MTYPE_STATIC_NHT_DATA
, nhtd
);
283 void static_zebra_nht_register(struct static_nexthop
*nh
, bool reg
)
285 struct static_path
*pn
= nh
->pn
;
286 struct route_node
*rn
= pn
->rn
;
287 struct static_route_info
*si
= static_route_info_from_rnode(rn
);
288 struct static_nht_data lookup
;
294 ZEBRA_NEXTHOP_REGISTER
: ZEBRA_NEXTHOP_UNREGISTER
;
296 if (nh
->nh_registered
&& reg
)
299 if (!nh
->nh_registered
&& !reg
)
302 memset(&p
, 0, sizeof(p
));
305 case STATIC_BLACKHOLE
:
307 case STATIC_IPV4_GATEWAY
:
308 case STATIC_IPV4_GATEWAY_IFNAME
:
310 p
.prefixlen
= IPV4_MAX_BITLEN
;
311 p
.u
.prefix4
= nh
->addr
.ipv4
;
314 case STATIC_IPV6_GATEWAY
:
315 case STATIC_IPV6_GATEWAY_IFNAME
:
317 p
.prefixlen
= IPV6_MAX_BITLEN
;
318 p
.u
.prefix6
= nh
->addr
.ipv6
;
323 memset(&lookup
, 0, sizeof(lookup
));
325 lookup
.nh_vrf_id
= nh
->nh_vrf_id
;
326 lookup
.safi
= si
->safi
;
328 nh
->nh_registered
= reg
;
331 struct static_nht_data
*nhtd
;
333 nhtd
= static_nht_hash_getref(&lookup
);
335 if (nhtd
->refcount
> 1) {
336 DEBUGD(&static_dbg_route
,
337 "Already registered nexthop(%pFX) for %pRN %d",
338 &p
, rn
, nhtd
->nh_num
);
340 static_nht_update(&rn
->p
, &nhtd
->nh
,
341 nhtd
->nh_num
, afi
, si
->safi
,
346 struct static_nht_data
*nhtd
;
348 nhtd
= static_nht_hash_find(static_nht_hash
, &lookup
);
351 if (static_nht_hash_decref(nhtd
))
355 DEBUGD(&static_dbg_route
, "%s nexthop(%pFX) for %pRN",
356 reg
? "Registering" : "Unregistering", &p
, rn
);
358 if (zclient_send_rnh(zclient
, cmd
, &p
, si
->safi
, false, false,
359 nh
->nh_vrf_id
) == ZCLIENT_SEND_FAILURE
)
360 zlog_warn("%s: Failure to send nexthop to zebra", __func__
);
363 * When nexthop gets updated via configuration then use the
364 * already registered NH and resend the route to zebra
366 int static_zebra_nh_update(struct static_nexthop
*nh
)
368 struct static_path
*pn
= nh
->pn
;
369 struct route_node
*rn
= pn
->rn
;
370 struct static_route_info
*si
= static_route_info_from_rnode(rn
);
371 struct static_nht_data
*nhtd
, lookup
= {};
372 struct prefix p
= {};
375 if (!nh
->nh_registered
)
380 case STATIC_BLACKHOLE
:
382 case STATIC_IPV4_GATEWAY
:
383 case STATIC_IPV4_GATEWAY_IFNAME
:
385 p
.prefixlen
= IPV4_MAX_BITLEN
;
386 p
.u
.prefix4
= nh
->addr
.ipv4
;
389 case STATIC_IPV6_GATEWAY
:
390 case STATIC_IPV6_GATEWAY_IFNAME
:
392 p
.prefixlen
= IPV6_MAX_BITLEN
;
393 p
.u
.prefix6
= nh
->addr
.ipv6
;
399 lookup
.nh_vrf_id
= nh
->nh_vrf_id
;
400 lookup
.safi
= si
->safi
;
402 nhtd
= static_nht_hash_find(static_nht_hash
, &lookup
);
403 if (nhtd
&& nhtd
->nh_num
) {
404 nh
->state
= STATIC_START
;
405 static_nht_update(&rn
->p
, &nhtd
->nh
, nhtd
->nh_num
, afi
,
406 si
->safi
, nh
->nh_vrf_id
);
412 extern void static_zebra_route_add(struct static_path
*pn
, bool install
)
414 struct route_node
*rn
= pn
->rn
;
415 struct static_route_info
*si
= rn
->info
;
416 struct static_nexthop
*nh
;
417 const struct prefix
*p
, *src_pp
;
418 struct zapi_nexthop
*api_nh
;
419 struct zapi_route api
;
423 srcdest_rnode_prefixes(rn
, &p
, &src_pp
);
425 memset(&api
, 0, sizeof(api
));
426 api
.vrf_id
= si
->svrf
->vrf
->vrf_id
;
427 api
.type
= ZEBRA_ROUTE_STATIC
;
429 memcpy(&api
.prefix
, p
, sizeof(api
.prefix
));
432 SET_FLAG(api
.message
, ZAPI_MESSAGE_SRCPFX
);
433 memcpy(&api
.src_prefix
, src_pp
, sizeof(api
.src_prefix
));
435 SET_FLAG(api
.flags
, ZEBRA_FLAG_RR_USE_DISTANCE
);
436 SET_FLAG(api
.flags
, ZEBRA_FLAG_ALLOW_RECURSION
);
437 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
439 SET_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
);
440 api
.distance
= pn
->distance
;
443 SET_FLAG(api
.message
, ZAPI_MESSAGE_TAG
);
446 if (pn
->table_id
!= 0) {
447 SET_FLAG(api
.message
, ZAPI_MESSAGE_TABLEID
);
448 api
.tableid
= pn
->table_id
;
450 frr_each(static_nexthop_list
, &pn
->nexthop_list
, nh
) {
451 /* Don't overrun the nexthop array */
452 if (nh_num
== zebra_ecmp_count
)
455 api_nh
= &api
.nexthops
[nh_num
];
456 if (nh
->nh_vrf_id
== VRF_UNKNOWN
)
459 api_nh
->vrf_id
= nh
->nh_vrf_id
;
461 SET_FLAG(api_nh
->flags
, ZAPI_NEXTHOP_FLAG_ONLINK
);
462 if (nh
->color
!= 0) {
463 SET_FLAG(api
.message
, ZAPI_MESSAGE_SRTE
);
464 api_nh
->srte_color
= nh
->color
;
467 nh
->state
= STATIC_SENT_TO_ZEBRA
;
471 if (nh
->ifindex
== IFINDEX_INTERNAL
)
473 api_nh
->ifindex
= nh
->ifindex
;
474 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
476 case STATIC_IPV4_GATEWAY
:
479 api_nh
->type
= NEXTHOP_TYPE_IPV4
;
480 api_nh
->gate
= nh
->addr
;
482 case STATIC_IPV4_GATEWAY_IFNAME
:
483 if (nh
->ifindex
== IFINDEX_INTERNAL
)
485 api_nh
->ifindex
= nh
->ifindex
;
486 api_nh
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
487 api_nh
->gate
= nh
->addr
;
489 case STATIC_IPV6_GATEWAY
:
492 api_nh
->type
= NEXTHOP_TYPE_IPV6
;
493 api_nh
->gate
= nh
->addr
;
495 case STATIC_IPV6_GATEWAY_IFNAME
:
496 if (nh
->ifindex
== IFINDEX_INTERNAL
)
498 api_nh
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
499 api_nh
->ifindex
= nh
->ifindex
;
500 api_nh
->gate
= nh
->addr
;
502 case STATIC_BLACKHOLE
:
503 api_nh
->type
= NEXTHOP_TYPE_BLACKHOLE
;
504 switch (nh
->bh_type
) {
505 case STATIC_BLACKHOLE_DROP
:
506 case STATIC_BLACKHOLE_NULL
:
507 api_nh
->bh_type
= BLACKHOLE_NULL
;
509 case STATIC_BLACKHOLE_REJECT
:
510 api_nh
->bh_type
= BLACKHOLE_REJECT
;
515 if (nh
->snh_label
.num_labels
) {
518 SET_FLAG(api_nh
->flags
, ZAPI_NEXTHOP_FLAG_LABEL
);
519 api_nh
->label_num
= nh
->snh_label
.num_labels
;
520 for (i
= 0; i
< api_nh
->label_num
; i
++)
521 api_nh
->labels
[i
] = nh
->snh_label
.label
[i
];
526 api
.nexthop_num
= nh_num
;
529 * If we have been given an install but nothing is valid
530 * go ahead and delete the route for double plus fun
532 if (!nh_num
&& install
)
535 zclient_route_send(install
?
536 ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE
,
540 static zclient_handler
*const static_handlers
[] = {
541 [ZEBRA_INTERFACE_ADDRESS_ADD
] = interface_address_add
,
542 [ZEBRA_INTERFACE_ADDRESS_DELETE
] = interface_address_delete
,
543 [ZEBRA_ROUTE_NOTIFY_OWNER
] = route_notify_owner
,
544 [ZEBRA_NEXTHOP_UPDATE
] = static_zebra_nexthop_update
,
547 void static_zebra_init(void)
549 struct zclient_options opt
= { .receive_notify
= true };
551 if_zapi_callbacks(static_ifp_create
, static_ifp_up
,
552 static_ifp_down
, static_ifp_destroy
);
554 zclient
= zclient_new(master
, &opt
, static_handlers
,
555 array_size(static_handlers
));
557 zclient_init(zclient
, ZEBRA_ROUTE_STATIC
, 0, &static_privs
);
558 zclient
->zebra_capabilities
= static_zebra_capabilities
;
559 zclient
->zebra_connected
= zebra_connected
;
561 static_nht_hash_init(static_nht_hash
);
564 /* static_zebra_stop used by tests/lib/test_grpc.cpp */
565 void static_zebra_stop(void)
567 static_nht_hash_clear();
568 static_nht_hash_fini(static_nht_hash
);
572 zclient_stop(zclient
);
573 zclient_free(zclient
);
577 void static_zebra_vrf_register(struct vrf
*vrf
)
579 if (vrf
->vrf_id
== VRF_DEFAULT
)
581 zclient_send_reg_requests(zclient
, vrf
->vrf_id
);
584 void static_zebra_vrf_unregister(struct vrf
*vrf
)
586 if (vrf
->vrf_id
== VRF_DEFAULT
)
588 zclient_send_dereg_requests(zclient
, vrf
->vrf_id
);