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 /* Zebra structure to hold current status. */
48 struct zclient
*zclient
;
49 static struct hash
*static_nht_hash
;
51 /* Inteface addition message from zebra. */
52 static int static_ifp_create(struct interface
*ifp
)
54 static_ifindex_update(ifp
, true);
59 static int static_ifp_destroy(struct interface
*ifp
)
61 static_ifindex_update(ifp
, false);
65 static int interface_address_add(ZAPI_CALLBACK_ARGS
)
67 zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
72 static int interface_address_delete(ZAPI_CALLBACK_ARGS
)
76 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
85 static int static_ifp_up(struct interface
*ifp
)
88 struct static_vrf
*svrf
= static_vrf_lookup_by_id(ifp
->vrf_id
);
90 static_fixup_vrf_ids(svrf
);
93 /* Install any static reliant on this interface coming up */
94 static_install_intf_nh(ifp
);
95 static_ifindex_update(ifp
, true);
100 static int static_ifp_down(struct interface
*ifp
)
102 static_ifindex_update(ifp
, false);
107 static int route_notify_owner(ZAPI_CALLBACK_ARGS
)
110 enum zapi_route_notify_owner note
;
113 if (!zapi_route_notify_decode(zclient
->ibuf
, &p
, &table_id
, ¬e
,
118 case ZAPI_ROUTE_FAIL_INSTALL
:
119 static_nht_mark_state(&p
, vrf_id
, STATIC_NOT_INSTALLED
);
120 zlog_warn("%s: Route %pFX failed to install for table: %u",
121 __func__
, &p
, table_id
);
123 case ZAPI_ROUTE_BETTER_ADMIN_WON
:
124 static_nht_mark_state(&p
, vrf_id
, STATIC_NOT_INSTALLED
);
126 "%s: Route %pFX over-ridden by better route for table: %u",
127 __func__
, &p
, table_id
);
129 case ZAPI_ROUTE_INSTALLED
:
130 static_nht_mark_state(&p
, vrf_id
, STATIC_INSTALLED
);
132 case ZAPI_ROUTE_REMOVED
:
133 static_nht_mark_state(&p
, vrf_id
, STATIC_NOT_INSTALLED
);
135 case ZAPI_ROUTE_REMOVE_FAIL
:
136 static_nht_mark_state(&p
, vrf_id
, STATIC_INSTALLED
);
137 zlog_warn("%s: Route %pFX failure to remove for table: %u",
138 __func__
, &p
, table_id
);
144 static void zebra_connected(struct zclient
*zclient
)
146 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
149 struct static_nht_data
{
158 /* API to check whether the configured nexthop address is
159 * one of its local connected address or not.
162 static_nexthop_is_local(vrf_id_t vrfid
, struct prefix
*addr
, int family
)
164 if (family
== AF_INET
) {
165 if (if_address_is_local(&addr
->u
.prefix4
, AF_INET
, vrfid
))
167 } else if (family
== AF_INET6
) {
168 if (if_address_is_local(&addr
->u
.prefix6
, AF_INET6
, vrfid
))
173 static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS
)
175 struct static_nht_data
*nhtd
, lookup
;
176 struct zapi_route nhr
;
179 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
180 zlog_err("Failure to decode nexthop update message");
184 if (nhr
.prefix
.family
== AF_INET6
)
187 if (nhr
.type
== ZEBRA_ROUTE_CONNECT
) {
188 if (static_nexthop_is_local(vrf_id
, &nhr
.prefix
,
193 memset(&lookup
, 0, sizeof(lookup
));
194 lookup
.nh
= &nhr
.prefix
;
195 lookup
.nh_vrf_id
= vrf_id
;
197 nhtd
= hash_lookup(static_nht_hash
, &lookup
);
200 nhtd
->nh_num
= nhr
.nexthop_num
;
202 static_nht_reset_start(&nhr
.prefix
, afi
, nhtd
->nh_vrf_id
);
203 static_nht_update(NULL
, &nhr
.prefix
, nhr
.nexthop_num
, afi
,
206 zlog_err("No nhtd?");
211 static void static_zebra_capabilities(struct zclient_capabilities
*cap
)
213 mpls_enabled
= cap
->mpls_enabled
;
216 static unsigned int static_nht_hash_key(const void *data
)
218 const struct static_nht_data
*nhtd
= data
;
219 unsigned int key
= 0;
221 key
= prefix_hash_key(nhtd
->nh
);
222 return jhash_1word(nhtd
->nh_vrf_id
, key
);
225 static bool static_nht_hash_cmp(const void *d1
, const void *d2
)
227 const struct static_nht_data
*nhtd1
= d1
;
228 const struct static_nht_data
*nhtd2
= d2
;
230 if (nhtd1
->nh_vrf_id
!= nhtd2
->nh_vrf_id
)
233 return prefix_same(nhtd1
->nh
, nhtd2
->nh
);
236 static void *static_nht_hash_alloc(void *data
)
238 struct static_nht_data
*copy
= data
;
239 struct static_nht_data
*new;
241 new = XMALLOC(MTYPE_TMP
, sizeof(*new));
243 new->nh
= prefix_new();
244 prefix_copy(new->nh
, copy
->nh
);
247 new->nh_vrf_id
= copy
->nh_vrf_id
;
252 static void static_nht_hash_free(void *data
)
254 struct static_nht_data
*nhtd
= data
;
256 prefix_free(&nhtd
->nh
);
257 XFREE(MTYPE_TMP
, nhtd
);
260 void static_zebra_nht_register(struct static_nexthop
*nh
, bool reg
)
262 struct static_path
*pn
= nh
->pn
;
263 struct route_node
*rn
= pn
->rn
;
264 struct static_nht_data
*nhtd
, lookup
;
270 ZEBRA_NEXTHOP_REGISTER
: ZEBRA_NEXTHOP_UNREGISTER
;
272 if (nh
->nh_registered
&& reg
)
275 if (!nh
->nh_registered
&& !reg
)
278 memset(&p
, 0, sizeof(p
));
281 case STATIC_BLACKHOLE
:
283 case STATIC_IPV4_GATEWAY
:
284 case STATIC_IPV4_GATEWAY_IFNAME
:
286 p
.prefixlen
= IPV4_MAX_BITLEN
;
287 p
.u
.prefix4
= nh
->addr
.ipv4
;
290 case STATIC_IPV6_GATEWAY
:
291 case STATIC_IPV6_GATEWAY_IFNAME
:
293 p
.prefixlen
= IPV6_MAX_BITLEN
;
294 p
.u
.prefix6
= nh
->addr
.ipv6
;
299 memset(&lookup
, 0, sizeof(lookup
));
301 lookup
.nh_vrf_id
= nh
->nh_vrf_id
;
303 nh
->nh_registered
= reg
;
306 nhtd
= hash_get(static_nht_hash
, &lookup
,
307 static_nht_hash_alloc
);
310 DEBUGD(&static_dbg_route
,
311 "Registered nexthop(%pFX) for %pRN %d", &p
, rn
,
313 if (nhtd
->refcount
> 1 && nhtd
->nh_num
) {
314 static_nht_update(&rn
->p
, nhtd
->nh
, nhtd
->nh_num
, afi
,
319 nhtd
= hash_lookup(static_nht_hash
, &lookup
);
324 if (nhtd
->refcount
>= 1)
327 hash_release(static_nht_hash
, nhtd
);
328 static_nht_hash_free(nhtd
);
331 if (zclient_send_rnh(zclient
, cmd
, &p
, false, false, nh
->nh_vrf_id
)
332 == ZCLIENT_SEND_FAILURE
)
333 zlog_warn("%s: Failure to send nexthop to zebra", __func__
);
336 * When nexthop gets updated via configuration then use the
337 * already registered NH and resend the route to zebra
339 int static_zebra_nh_update(struct static_nexthop
*nh
)
341 struct static_path
*pn
= nh
->pn
;
342 struct route_node
*rn
= pn
->rn
;
343 struct static_nht_data
*nhtd
, lookup
= {};
344 struct prefix p
= {};
347 if (!nh
->nh_registered
)
352 case STATIC_BLACKHOLE
:
354 case STATIC_IPV4_GATEWAY
:
355 case STATIC_IPV4_GATEWAY_IFNAME
:
357 p
.prefixlen
= IPV4_MAX_BITLEN
;
358 p
.u
.prefix4
= nh
->addr
.ipv4
;
361 case STATIC_IPV6_GATEWAY
:
362 case STATIC_IPV6_GATEWAY_IFNAME
:
364 p
.prefixlen
= IPV6_MAX_BITLEN
;
365 p
.u
.prefix6
= nh
->addr
.ipv6
;
371 lookup
.nh_vrf_id
= nh
->nh_vrf_id
;
373 nhtd
= hash_lookup(static_nht_hash
, &lookup
);
374 if (nhtd
&& nhtd
->nh_num
) {
375 nh
->state
= STATIC_START
;
376 static_nht_update(&rn
->p
, nhtd
->nh
, nhtd
->nh_num
, afi
,
383 extern void static_zebra_route_add(struct static_path
*pn
, bool install
)
385 struct route_node
*rn
= pn
->rn
;
386 struct static_route_info
*si
= rn
->info
;
387 struct static_nexthop
*nh
;
388 const struct prefix
*p
, *src_pp
;
389 struct zapi_nexthop
*api_nh
;
390 struct zapi_route api
;
394 srcdest_rnode_prefixes(rn
, &p
, &src_pp
);
396 memset(&api
, 0, sizeof(api
));
397 api
.vrf_id
= si
->svrf
->vrf
->vrf_id
;
398 api
.type
= ZEBRA_ROUTE_STATIC
;
400 memcpy(&api
.prefix
, p
, sizeof(api
.prefix
));
403 SET_FLAG(api
.message
, ZAPI_MESSAGE_SRCPFX
);
404 memcpy(&api
.src_prefix
, src_pp
, sizeof(api
.src_prefix
));
406 SET_FLAG(api
.flags
, ZEBRA_FLAG_RR_USE_DISTANCE
);
407 SET_FLAG(api
.flags
, ZEBRA_FLAG_ALLOW_RECURSION
);
408 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
410 SET_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
);
411 api
.distance
= pn
->distance
;
414 SET_FLAG(api
.message
, ZAPI_MESSAGE_TAG
);
417 if (pn
->table_id
!= 0) {
418 SET_FLAG(api
.message
, ZAPI_MESSAGE_TABLEID
);
419 api
.tableid
= pn
->table_id
;
421 frr_each(static_nexthop_list
, &pn
->nexthop_list
, nh
) {
422 api_nh
= &api
.nexthops
[nh_num
];
423 if (nh
->nh_vrf_id
== VRF_UNKNOWN
)
426 api_nh
->vrf_id
= nh
->nh_vrf_id
;
428 SET_FLAG(api_nh
->flags
, ZAPI_NEXTHOP_FLAG_ONLINK
);
429 if (nh
->color
!= 0) {
430 SET_FLAG(api
.message
, ZAPI_MESSAGE_SRTE
);
431 api_nh
->srte_color
= nh
->color
;
434 nh
->state
= STATIC_SENT_TO_ZEBRA
;
438 if (nh
->ifindex
== IFINDEX_INTERNAL
)
440 api_nh
->ifindex
= nh
->ifindex
;
441 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
443 case STATIC_IPV4_GATEWAY
:
446 api_nh
->type
= NEXTHOP_TYPE_IPV4
;
447 api_nh
->gate
= nh
->addr
;
449 case STATIC_IPV4_GATEWAY_IFNAME
:
450 if (nh
->ifindex
== IFINDEX_INTERNAL
)
452 api_nh
->ifindex
= nh
->ifindex
;
453 api_nh
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
454 api_nh
->gate
= nh
->addr
;
456 case STATIC_IPV6_GATEWAY
:
459 api_nh
->type
= NEXTHOP_TYPE_IPV6
;
460 api_nh
->gate
= nh
->addr
;
462 case STATIC_IPV6_GATEWAY_IFNAME
:
463 if (nh
->ifindex
== IFINDEX_INTERNAL
)
465 api_nh
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
466 api_nh
->ifindex
= nh
->ifindex
;
467 api_nh
->gate
= nh
->addr
;
469 case STATIC_BLACKHOLE
:
470 api_nh
->type
= NEXTHOP_TYPE_BLACKHOLE
;
471 switch (nh
->bh_type
) {
472 case STATIC_BLACKHOLE_DROP
:
473 case STATIC_BLACKHOLE_NULL
:
474 api_nh
->bh_type
= BLACKHOLE_NULL
;
476 case STATIC_BLACKHOLE_REJECT
:
477 api_nh
->bh_type
= BLACKHOLE_REJECT
;
482 if (nh
->snh_label
.num_labels
) {
485 SET_FLAG(api_nh
->flags
, ZAPI_NEXTHOP_FLAG_LABEL
);
486 api_nh
->label_num
= nh
->snh_label
.num_labels
;
487 for (i
= 0; i
< api_nh
->label_num
; i
++)
488 api_nh
->labels
[i
] = nh
->snh_label
.label
[i
];
493 api
.nexthop_num
= nh_num
;
496 * If we have been given an install but nothing is valid
497 * go ahead and delete the route for double plus fun
499 if (!nh_num
&& install
)
502 zclient_route_send(install
?
503 ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE
,
507 static zclient_handler
*const static_handlers
[] = {
508 [ZEBRA_INTERFACE_ADDRESS_ADD
] = interface_address_add
,
509 [ZEBRA_INTERFACE_ADDRESS_DELETE
] = interface_address_delete
,
510 [ZEBRA_ROUTE_NOTIFY_OWNER
] = route_notify_owner
,
511 [ZEBRA_NEXTHOP_UPDATE
] = static_zebra_nexthop_update
,
514 void static_zebra_init(void)
516 struct zclient_options opt
= { .receive_notify
= true };
518 if_zapi_callbacks(static_ifp_create
, static_ifp_up
,
519 static_ifp_down
, static_ifp_destroy
);
521 zclient
= zclient_new(master
, &opt
, static_handlers
,
522 array_size(static_handlers
));
524 zclient_init(zclient
, ZEBRA_ROUTE_STATIC
, 0, &static_privs
);
525 zclient
->zebra_capabilities
= static_zebra_capabilities
;
526 zclient
->zebra_connected
= zebra_connected
;
528 static_nht_hash
= hash_create(static_nht_hash_key
,
530 "Static Nexthop Tracking hash");
533 /* static_zebra_stop used by tests/lib/test_grpc.cpp */
534 void static_zebra_stop(void)
538 zclient_stop(zclient
);
539 zclient_free(zclient
);
543 void static_zebra_vrf_register(struct vrf
*vrf
)
545 if (vrf
->vrf_id
== VRF_DEFAULT
)
547 zclient_send_reg_requests(zclient
, vrf
->vrf_id
);
550 void static_zebra_vrf_unregister(struct vrf
*vrf
)
552 if (vrf
->vrf_id
== VRF_DEFAULT
)
554 zclient_send_dereg_requests(zclient
, vrf
->vrf_id
);