3 * Copyright (C) Cumulus Networks, Inc.
6 * This file is part of FRR.
8 * FRR 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
13 * FRR 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.
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
32 #include "nexthop_group.h"
34 #include "sharp_globals.h"
35 #include "sharp_nht.h"
36 #include "sharp_zebra.h"
38 /* Zebra structure to hold current status. */
39 struct zclient
*zclient
= NULL
;
41 /* For registering threads. */
42 extern struct thread_master
*master
;
45 extern struct zebra_privs_t sharp_privs
;
47 DEFINE_MTYPE_STATIC(SHARPD
, ZC
, "Test zclients");
49 /* Struct to hold list of test zclients */
50 struct sharp_zclient
{
51 struct sharp_zclient
*prev
;
52 struct sharp_zclient
*next
;
53 struct zclient
*client
;
56 /* Head of test zclient list */
57 static struct sharp_zclient
*sharp_clients_head
;
59 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS
);
61 /* Utility to add a test zclient struct to the list */
62 static void add_zclient(struct zclient
*client
)
64 struct sharp_zclient
*node
;
66 node
= XCALLOC(MTYPE_ZC
, sizeof(struct sharp_zclient
));
68 node
->client
= client
;
70 node
->next
= sharp_clients_head
;
71 if (sharp_clients_head
)
72 sharp_clients_head
->prev
= node
;
73 sharp_clients_head
= node
;
76 /* Interface addition message from zebra. */
77 static int sharp_ifp_create(struct interface
*ifp
)
82 static int sharp_ifp_destroy(struct interface
*ifp
)
87 static int interface_address_add(ZAPI_CALLBACK_ARGS
)
89 zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
94 static int interface_address_delete(ZAPI_CALLBACK_ARGS
)
98 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
107 static int sharp_ifp_up(struct interface
*ifp
)
112 static int sharp_ifp_down(struct interface
*ifp
)
117 int sharp_install_lsps_helper(bool install_p
, bool update_p
,
118 const struct prefix
*p
, uint8_t type
,
119 int instance
, uint32_t in_label
,
120 const struct nexthop_group
*nhg
,
121 const struct nexthop_group
*backup_nhg
)
123 struct zapi_labels zl
= {};
124 struct zapi_nexthop
*znh
;
125 const struct nexthop
*nh
;
128 zl
.type
= ZEBRA_LSP_SHARP
;
129 zl
.local_label
= in_label
;
132 SET_FLAG(zl
.message
, ZAPI_LABELS_FTN
);
133 prefix_copy(&zl
.route
.prefix
, p
);
134 zl
.route
.type
= type
;
135 zl
.route
.instance
= instance
;
138 /* List of nexthops is optional for delete */
141 for (ALL_NEXTHOPS_PTR(nhg
, nh
)) {
142 znh
= &zl
.nexthops
[i
];
144 /* Must have labels to be useful */
145 if (nh
->nh_label
== NULL
||
146 nh
->nh_label
->num_labels
== 0)
149 if (nh
->type
== NEXTHOP_TYPE_IFINDEX
||
150 nh
->type
== NEXTHOP_TYPE_BLACKHOLE
)
151 /* Hmm - can't really deal with these types */
154 ret
= zapi_nexthop_from_nexthop(znh
, nh
);
159 if (i
>= MULTIPATH_NUM
)
164 /* Whoops - no nexthops isn't very useful for install */
165 if (i
== 0 && install_p
)
170 /* Add optional backup nexthop info. Since these are used by index,
171 * we can't just skip over an invalid backup nexthop: we will
172 * invalidate the entire operation.
174 if (backup_nhg
!= NULL
) {
176 for (ALL_NEXTHOPS_PTR(backup_nhg
, nh
)) {
177 znh
= &zl
.backup_nexthops
[i
];
179 /* Must have labels to be useful */
180 if (nh
->nh_label
== NULL
||
181 nh
->nh_label
->num_labels
== 0)
184 if (nh
->type
== NEXTHOP_TYPE_IFINDEX
||
185 nh
->type
== NEXTHOP_TYPE_BLACKHOLE
)
186 /* Hmm - can't really deal with these types */
189 ret
= zapi_nexthop_from_nexthop(znh
, nh
);
194 if (i
>= MULTIPATH_NUM
)
199 SET_FLAG(zl
.message
, ZAPI_LABELS_HAS_BACKUPS
);
201 zl
.backup_nexthop_num
= i
;
207 cmd
= ZEBRA_MPLS_LABELS_REPLACE
;
209 cmd
= ZEBRA_MPLS_LABELS_ADD
;
211 cmd
= ZEBRA_MPLS_LABELS_DELETE
;
214 ret
= zebra_send_mpls_labels(zclient
, cmd
, &zl
);
219 void sharp_install_routes_helper(struct prefix
*p
, vrf_id_t vrf_id
,
220 uint8_t instance
, uint32_t nhgid
,
221 const struct nexthop_group
*nhg
,
222 const struct nexthop_group
*backup_nhg
,
228 zlog_debug("Inserting %u routes", routes
);
230 if (p
->family
== AF_INET
) {
232 temp
= ntohl(p
->u
.prefix4
.s_addr
);
234 temp
= ntohl(p
->u
.val32
[3]);
236 /* Only use backup route/nexthops if present */
237 if (backup_nhg
&& (backup_nhg
->nexthop
== NULL
))
240 monotime(&sg
.r
.t_start
);
241 for (i
= 0; i
< routes
; i
++) {
242 route_add(p
, vrf_id
, (uint8_t)instance
, nhgid
, nhg
, backup_nhg
);
244 p
->u
.prefix4
.s_addr
= htonl(++temp
);
246 p
->u
.val32
[3] = htonl(++temp
);
250 void sharp_remove_routes_helper(struct prefix
*p
, vrf_id_t vrf_id
,
251 uint8_t instance
, uint32_t routes
)
256 zlog_debug("Removing %u routes", routes
);
258 if (p
->family
== AF_INET
) {
260 temp
= ntohl(p
->u
.prefix4
.s_addr
);
262 temp
= ntohl(p
->u
.val32
[3]);
264 monotime(&sg
.r
.t_start
);
265 for (i
= 0; i
< routes
; i
++) {
266 route_delete(p
, vrf_id
, (uint8_t)instance
);
268 p
->u
.prefix4
.s_addr
= htonl(++temp
);
270 p
->u
.val32
[3] = htonl(++temp
);
274 static void handle_repeated(bool installed
)
276 struct prefix p
= sg
.r
.orig_prefix
;
279 if (sg
.r
.repeat
<= 0)
283 sg
.r
.removed_routes
= 0;
284 sharp_remove_routes_helper(&p
, sg
.r
.vrf_id
,
285 sg
.r
.inst
, sg
.r
.total_routes
);
289 sg
.r
.installed_routes
= 0;
290 sharp_install_routes_helper(&p
, sg
.r
.vrf_id
, sg
.r
.inst
,
291 sg
.r
.nhgid
, &sg
.r
.nhop_group
,
292 &sg
.r
.backup_nhop_group
,
297 static int route_notify_owner(ZAPI_CALLBACK_ARGS
)
301 enum zapi_route_notify_owner note
;
304 if (!zapi_route_notify_decode(zclient
->ibuf
, &p
, &table
, ¬e
,
309 case ZAPI_ROUTE_INSTALLED
:
310 sg
.r
.installed_routes
++;
311 if (sg
.r
.total_routes
== sg
.r
.installed_routes
) {
312 monotime(&sg
.r
.t_end
);
313 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
314 zlog_debug("Installed All Items %jd.%ld",
315 (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
316 handle_repeated(true);
319 case ZAPI_ROUTE_FAIL_INSTALL
:
320 zlog_debug("Failed install of route");
322 case ZAPI_ROUTE_BETTER_ADMIN_WON
:
323 zlog_debug("Better Admin Distance won over us");
325 case ZAPI_ROUTE_REMOVED
:
326 sg
.r
.removed_routes
++;
327 if (sg
.r
.total_routes
== sg
.r
.removed_routes
) {
328 monotime(&sg
.r
.t_end
);
329 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
330 zlog_debug("Removed all Items %jd.%ld",
331 (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
332 handle_repeated(false);
335 case ZAPI_ROUTE_REMOVE_FAIL
:
336 zlog_debug("Route removal Failure");
342 static void zebra_connected(struct zclient
*zclient
)
344 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
347 * Do not actually turn this on yet
348 * This is just the start of the infrastructure needed here
349 * This can be fixed at a later time.
351 * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
352 * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
356 void vrf_label_add(vrf_id_t vrf_id
, afi_t afi
, mpls_label_t label
)
358 zclient_send_vrf_label(zclient
, vrf_id
, afi
, label
, ZEBRA_LSP_SHARP
);
361 void nhg_add(uint32_t id
, const struct nexthop_group
*nhg
,
362 const struct nexthop_group
*backup_nhg
)
364 struct zapi_nhg api_nhg
= {};
365 struct zapi_nexthop
*api_nh
;
369 for (ALL_NEXTHOPS_PTR(nhg
, nh
)) {
370 if (api_nhg
.nexthop_num
>= MULTIPATH_NUM
) {
372 "%s: number of nexthops greater than max multipath size, truncating",
377 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
379 zapi_nexthop_from_nexthop(api_nh
, nh
);
380 api_nhg
.nexthop_num
++;
384 for (ALL_NEXTHOPS_PTR(backup_nhg
, nh
)) {
385 if (api_nhg
.backup_nexthop_num
>= MULTIPATH_NUM
) {
387 "%s: number of backup nexthops greater than max multipath size, truncating",
391 api_nh
= &api_nhg
.backup_nexthops
392 [api_nhg
.backup_nexthop_num
];
394 zapi_backup_nexthop_from_nexthop(api_nh
, nh
);
395 api_nhg
.backup_nexthop_num
++;
399 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
402 void nhg_del(uint32_t id
)
404 struct zapi_nhg api_nhg
= {};
408 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
411 void route_add(const struct prefix
*p
, vrf_id_t vrf_id
, uint8_t instance
,
412 uint32_t nhgid
, const struct nexthop_group
*nhg
,
413 const struct nexthop_group
*backup_nhg
)
415 struct zapi_route api
;
416 struct zapi_nexthop
*api_nh
;
420 memset(&api
, 0, sizeof(api
));
422 api
.type
= ZEBRA_ROUTE_SHARP
;
423 api
.instance
= instance
;
424 api
.safi
= SAFI_UNICAST
;
425 memcpy(&api
.prefix
, p
, sizeof(*p
));
427 SET_FLAG(api
.flags
, ZEBRA_FLAG_ALLOW_RECURSION
);
428 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
430 /* Only send via ID if nhgroup has been successfully installed */
431 if (nhgid
&& sharp_nhgroup_id_is_installed(nhgid
)) {
432 SET_FLAG(api
.message
, ZAPI_MESSAGE_NHG
);
435 for (ALL_NEXTHOPS_PTR(nhg
, nh
)) {
436 api_nh
= &api
.nexthops
[i
];
438 zapi_nexthop_from_nexthop(api_nh
, nh
);
445 /* Include backup nexthops, if present */
446 if (backup_nhg
&& backup_nhg
->nexthop
) {
447 SET_FLAG(api
.message
, ZAPI_MESSAGE_BACKUP_NEXTHOPS
);
450 for (ALL_NEXTHOPS_PTR(backup_nhg
, nh
)) {
451 api_nh
= &api
.backup_nexthops
[i
];
453 zapi_backup_nexthop_from_nexthop(api_nh
, nh
);
458 api
.backup_nexthop_num
= i
;
461 zclient_route_send(ZEBRA_ROUTE_ADD
, zclient
, &api
);
464 void route_delete(struct prefix
*p
, vrf_id_t vrf_id
, uint8_t instance
)
466 struct zapi_route api
;
468 memset(&api
, 0, sizeof(api
));
470 api
.type
= ZEBRA_ROUTE_SHARP
;
471 api
.safi
= SAFI_UNICAST
;
472 api
.instance
= instance
;
473 memcpy(&api
.prefix
, p
, sizeof(*p
));
474 zclient_route_send(ZEBRA_ROUTE_DELETE
, zclient
, &api
);
479 void sharp_zebra_nexthop_watch(struct prefix
*p
, vrf_id_t vrf_id
, bool import
,
480 bool watch
, bool connected
)
485 command
= ZEBRA_NEXTHOP_REGISTER
;
488 command
= ZEBRA_NEXTHOP_UNREGISTER
;
490 command
= ZEBRA_IMPORT_ROUTE_REGISTER
;
493 command
= ZEBRA_IMPORT_ROUTE_UNREGISTER
;
496 if (zclient_send_rnh(zclient
, command
, p
, connected
, vrf_id
) < 0)
497 zlog_warn("%s: Failure to send nexthop to zebra", __func__
);
500 static int sharp_debug_nexthops(struct zapi_route
*api
)
503 char buf
[PREFIX_STRLEN
];
505 if (api
->nexthop_num
== 0) {
511 for (i
= 0; i
< api
->nexthop_num
; i
++) {
512 struct zapi_nexthop
*znh
= &api
->nexthops
[i
];
515 case NEXTHOP_TYPE_IPV4_IFINDEX
:
516 case NEXTHOP_TYPE_IPV4
:
518 " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
519 inet_ntop(AF_INET
, &znh
->gate
.ipv4
.s_addr
, buf
,
521 znh
->type
, znh
->ifindex
, znh
->vrf_id
,
524 case NEXTHOP_TYPE_IPV6_IFINDEX
:
525 case NEXTHOP_TYPE_IPV6
:
527 " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
528 inet_ntop(AF_INET6
, &znh
->gate
.ipv6
, buf
,
530 znh
->type
, znh
->ifindex
, znh
->vrf_id
,
533 case NEXTHOP_TYPE_IFINDEX
:
534 zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d",
535 znh
->type
, znh
->ifindex
);
537 case NEXTHOP_TYPE_BLACKHOLE
:
538 zlog_debug(" Nexthop blackhole");
545 static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS
)
547 struct sharp_nh_tracker
*nht
;
548 struct zapi_route nhr
;
550 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
551 zlog_err("%s: Decode of update failed", __func__
);
555 zlog_debug("Received update for %pFX", &nhr
.prefix
);
557 nht
= sharp_nh_tracker_get(&nhr
.prefix
);
558 nht
->nhop_num
= nhr
.nexthop_num
;
561 sharp_debug_nexthops(&nhr
);
566 static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS
)
568 struct zapi_route api
;
570 if (zapi_route_decode(zclient
->ibuf
, &api
) < 0)
571 zlog_warn("%s: Decode of redistribute failed: %d", __func__
,
572 ZEBRA_REDISTRIBUTE_ROUTE_ADD
);
574 zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd
),
575 &api
.prefix
, zebra_route_string(api
.type
));
577 sharp_debug_nexthops(&api
);
582 /* Add a zclient with a specified session id, for testing. */
583 int sharp_zclient_create(uint32_t session_id
)
585 struct zclient
*client
;
586 struct sharp_zclient
*node
;
588 /* Check for duplicates */
589 for (node
= sharp_clients_head
; node
!= NULL
; node
= node
->next
) {
590 if (node
->client
->session_id
== session_id
)
594 client
= zclient_new(master
, &zclient_options_default
);
596 client
->session_id
= session_id
;
598 zclient_init(client
, ZEBRA_ROUTE_SHARP
, 0, &sharp_privs
);
600 /* Register handlers for messages we expect this session to see */
601 client
->opaque_msg_handler
= sharp_opaque_handler
;
603 /* Enqueue on the list of test clients */
609 /* Delete one of the extra test zclients */
610 int sharp_zclient_delete(uint32_t session_id
)
612 struct sharp_zclient
*node
;
614 /* Search for session */
615 for (node
= sharp_clients_head
; node
!= NULL
; node
= node
->next
) {
616 if (node
->client
->session_id
== session_id
) {
617 /* Dequeue from list */
619 node
->next
->prev
= node
->prev
;
621 node
->prev
->next
= node
->next
;
622 if (node
== sharp_clients_head
)
623 sharp_clients_head
= node
->next
;
625 /* Clean up zclient */
626 zclient_stop(node
->client
);
627 zclient_free(node
->client
);
630 XFREE(MTYPE_ZC
, node
);
638 /* Handler for opaque messages */
639 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS
)
642 struct zapi_opaque_msg info
;
646 if (zclient_opaque_decode(s
, &info
) != 0)
649 zlog_debug("%s: [%u] received opaque type %u", __func__
,
650 zclient
->session_id
, info
.type
);
656 * Send OPAQUE messages, using subtype 'type'.
658 void sharp_opaque_send(uint32_t type
, uint32_t proto
, uint32_t instance
,
659 uint32_t session_id
, uint32_t count
)
665 /* Prepare a small payload */
666 for (i
= 0; i
< sizeof(buf
); i
++) {
673 /* Send some messages - broadcast and unicast are supported */
674 for (i
= 0; i
< count
; i
++) {
676 ret
= zclient_send_opaque(zclient
, type
, buf
,
679 ret
= zclient_send_opaque_unicast(zclient
, type
, proto
,
680 instance
, session_id
,
683 zlog_debug("%s: send_opaque() failed => %d",
692 * Send OPAQUE registration messages, using subtype 'type'.
694 void sharp_opaque_reg_send(bool is_reg
, uint32_t proto
, uint32_t instance
,
695 uint32_t session_id
, uint32_t type
)
703 zclient_create_header(s
, ZEBRA_OPAQUE_REGISTER
, VRF_DEFAULT
);
705 zclient_create_header(s
, ZEBRA_OPAQUE_UNREGISTER
, VRF_DEFAULT
);
708 stream_putl(s
, type
);
710 /* Add zclient info */
711 stream_putc(s
, proto
);
712 stream_putw(s
, instance
);
713 stream_putl(s
, session_id
);
715 /* Put length at the first point of the stream. */
716 stream_putw_at(s
, 0, stream_get_endp(s
));
718 (void)zclient_send_message(zclient
);
722 void sharp_zebra_send_arp(const struct interface
*ifp
, const struct prefix
*p
)
724 zclient_send_neigh_discovery_req(zclient
, ifp
, p
);
727 static int nhg_notify_owner(ZAPI_CALLBACK_ARGS
)
729 enum zapi_nhg_notify_owner note
;
732 if (!zapi_nhg_notify_decode(zclient
->ibuf
, &id
, ¬e
))
736 case ZAPI_NHG_INSTALLED
:
737 sharp_nhgroup_id_set_installed(id
, true);
738 zlog_debug("Installed nhg %u", id
);
740 case ZAPI_NHG_FAIL_INSTALL
:
741 zlog_debug("Failed install of nhg %u", id
);
743 case ZAPI_NHG_REMOVED
:
744 zlog_debug("Removed nhg %u", id
);
746 case ZAPI_NHG_REMOVE_FAIL
:
747 zlog_debug("Failed removal of nhg %u", id
);
754 void sharp_zebra_init(void)
756 struct zclient_options opt
= {.receive_notify
= true};
758 if_zapi_callbacks(sharp_ifp_create
, sharp_ifp_up
,
759 sharp_ifp_down
, sharp_ifp_destroy
);
761 zclient
= zclient_new(master
, &opt
);
763 zclient_init(zclient
, ZEBRA_ROUTE_SHARP
, 0, &sharp_privs
);
764 zclient
->zebra_connected
= zebra_connected
;
765 zclient
->interface_address_add
= interface_address_add
;
766 zclient
->interface_address_delete
= interface_address_delete
;
767 zclient
->route_notify_owner
= route_notify_owner
;
768 zclient
->nexthop_update
= sharp_nexthop_update
;
769 zclient
->import_check_update
= sharp_nexthop_update
;
770 zclient
->nhg_notify_owner
= nhg_notify_owner
;
772 zclient
->redistribute_route_add
= sharp_redistribute_route
;
773 zclient
->redistribute_route_del
= sharp_redistribute_route
;
774 zclient
->opaque_msg_handler
= sharp_opaque_handler
;