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"
33 #include "link_state.h"
35 #include "sharp_globals.h"
36 #include "sharp_nht.h"
37 #include "sharp_zebra.h"
39 /* Zebra structure to hold current status. */
40 struct zclient
*zclient
= NULL
;
42 /* For registering threads. */
43 extern struct thread_master
*master
;
46 extern struct zebra_privs_t sharp_privs
;
48 DEFINE_MTYPE_STATIC(SHARPD
, ZC
, "Test zclients");
50 /* Struct to hold list of test zclients */
51 struct sharp_zclient
{
52 struct sharp_zclient
*prev
;
53 struct sharp_zclient
*next
;
54 struct zclient
*client
;
57 /* Head of test zclient list */
58 static struct sharp_zclient
*sharp_clients_head
;
60 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS
);
62 /* Utility to add a test zclient struct to the list */
63 static void add_zclient(struct zclient
*client
)
65 struct sharp_zclient
*node
;
67 node
= XCALLOC(MTYPE_ZC
, sizeof(struct sharp_zclient
));
69 node
->client
= client
;
71 node
->next
= sharp_clients_head
;
72 if (sharp_clients_head
)
73 sharp_clients_head
->prev
= node
;
74 sharp_clients_head
= node
;
77 /* Interface addition message from zebra. */
78 static int sharp_ifp_create(struct interface
*ifp
)
83 static int sharp_ifp_destroy(struct interface
*ifp
)
88 static int interface_address_add(ZAPI_CALLBACK_ARGS
)
90 zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
95 static int interface_address_delete(ZAPI_CALLBACK_ARGS
)
99 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
108 static int sharp_ifp_up(struct interface
*ifp
)
113 static int sharp_ifp_down(struct interface
*ifp
)
118 int sharp_install_lsps_helper(bool install_p
, bool update_p
,
119 const struct prefix
*p
, uint8_t type
,
120 int instance
, uint32_t in_label
,
121 const struct nexthop_group
*nhg
,
122 const struct nexthop_group
*backup_nhg
)
124 struct zapi_labels zl
= {};
125 struct zapi_nexthop
*znh
;
126 const struct nexthop
*nh
;
129 zl
.type
= ZEBRA_LSP_SHARP
;
130 zl
.local_label
= in_label
;
133 SET_FLAG(zl
.message
, ZAPI_LABELS_FTN
);
134 prefix_copy(&zl
.route
.prefix
, p
);
135 zl
.route
.type
= type
;
136 zl
.route
.instance
= instance
;
139 /* List of nexthops is optional for delete */
142 for (ALL_NEXTHOPS_PTR(nhg
, nh
)) {
143 znh
= &zl
.nexthops
[i
];
145 /* Must have labels to be useful */
146 if (nh
->nh_label
== NULL
||
147 nh
->nh_label
->num_labels
== 0)
150 if (nh
->type
== NEXTHOP_TYPE_IFINDEX
||
151 nh
->type
== NEXTHOP_TYPE_BLACKHOLE
)
152 /* Hmm - can't really deal with these types */
155 ret
= zapi_nexthop_from_nexthop(znh
, nh
);
160 if (i
>= MULTIPATH_NUM
)
165 /* Whoops - no nexthops isn't very useful for install */
166 if (i
== 0 && install_p
)
171 /* Add optional backup nexthop info. Since these are used by index,
172 * we can't just skip over an invalid backup nexthop: we will
173 * invalidate the entire operation.
175 if (backup_nhg
!= NULL
) {
177 for (ALL_NEXTHOPS_PTR(backup_nhg
, nh
)) {
178 znh
= &zl
.backup_nexthops
[i
];
180 /* Must have labels to be useful */
181 if (nh
->nh_label
== NULL
||
182 nh
->nh_label
->num_labels
== 0)
185 if (nh
->type
== NEXTHOP_TYPE_IFINDEX
||
186 nh
->type
== NEXTHOP_TYPE_BLACKHOLE
)
187 /* Hmm - can't really deal with these types */
190 ret
= zapi_nexthop_from_nexthop(znh
, nh
);
195 if (i
>= MULTIPATH_NUM
)
200 SET_FLAG(zl
.message
, ZAPI_LABELS_HAS_BACKUPS
);
202 zl
.backup_nexthop_num
= i
;
208 cmd
= ZEBRA_MPLS_LABELS_REPLACE
;
210 cmd
= ZEBRA_MPLS_LABELS_ADD
;
212 cmd
= ZEBRA_MPLS_LABELS_DELETE
;
215 if (zebra_send_mpls_labels(zclient
, cmd
, &zl
) == ZCLIENT_SEND_FAILURE
)
221 enum where_to_restart
{
222 SHARP_INSTALL_ROUTES_RESTART
,
223 SHARP_DELETE_ROUTES_RESTART
,
226 struct buffer_delay
{
233 const struct nexthop_group
*nhg
;
234 const struct nexthop_group
*backup_nhg
;
235 enum where_to_restart restart
;
240 * route_add - Encodes a route to zebra
242 * This function returns true when the route was buffered
243 * by the underlying stream system
245 static bool route_add(const struct prefix
*p
, vrf_id_t vrf_id
, uint8_t instance
,
246 uint32_t nhgid
, const struct nexthop_group
*nhg
,
247 const struct nexthop_group
*backup_nhg
, char *opaque
)
249 struct zapi_route api
;
250 struct zapi_nexthop
*api_nh
;
254 memset(&api
, 0, sizeof(api
));
256 api
.type
= ZEBRA_ROUTE_SHARP
;
257 api
.instance
= instance
;
258 api
.safi
= SAFI_UNICAST
;
259 memcpy(&api
.prefix
, p
, sizeof(*p
));
261 SET_FLAG(api
.flags
, ZEBRA_FLAG_ALLOW_RECURSION
);
262 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
264 /* Only send via ID if nhgroup has been successfully installed */
265 if (nhgid
&& sharp_nhgroup_id_is_installed(nhgid
)) {
266 SET_FLAG(api
.message
, ZAPI_MESSAGE_NHG
);
269 for (ALL_NEXTHOPS_PTR(nhg
, nh
)) {
270 api_nh
= &api
.nexthops
[i
];
272 zapi_nexthop_from_nexthop(api_nh
, nh
);
279 /* Include backup nexthops, if present */
280 if (backup_nhg
&& backup_nhg
->nexthop
) {
281 SET_FLAG(api
.message
, ZAPI_MESSAGE_BACKUP_NEXTHOPS
);
284 for (ALL_NEXTHOPS_PTR(backup_nhg
, nh
)) {
285 api_nh
= &api
.backup_nexthops
[i
];
287 zapi_backup_nexthop_from_nexthop(api_nh
, nh
);
292 api
.backup_nexthop_num
= i
;
295 if (strlen(opaque
)) {
296 SET_FLAG(api
.message
, ZAPI_MESSAGE_OPAQUE
);
297 api
.opaque
.length
= strlen(opaque
) + 1;
298 assert(api
.opaque
.length
<= ZAPI_MESSAGE_OPAQUE_LENGTH
);
299 memcpy(api
.opaque
.data
, opaque
, api
.opaque
.length
);
302 if (zclient_route_send(ZEBRA_ROUTE_ADD
, zclient
, &api
)
303 == ZCLIENT_SEND_BUFFERED
)
310 * route_delete - Encodes a route for deletion to zebra
312 * This function returns true when the route sent was
313 * buffered by the underlying stream system.
315 static bool route_delete(struct prefix
*p
, vrf_id_t vrf_id
, uint8_t instance
)
317 struct zapi_route api
;
319 memset(&api
, 0, sizeof(api
));
321 api
.type
= ZEBRA_ROUTE_SHARP
;
322 api
.safi
= SAFI_UNICAST
;
323 api
.instance
= instance
;
324 memcpy(&api
.prefix
, p
, sizeof(*p
));
326 if (zclient_route_send(ZEBRA_ROUTE_DELETE
, zclient
, &api
)
327 == ZCLIENT_SEND_BUFFERED
)
333 static void sharp_install_routes_restart(struct prefix
*p
, uint32_t count
,
334 vrf_id_t vrf_id
, uint8_t instance
,
336 const struct nexthop_group
*nhg
,
337 const struct nexthop_group
*backup_nhg
,
338 uint32_t routes
, char *opaque
)
343 if (p
->family
== AF_INET
) {
345 temp
= ntohl(p
->u
.prefix4
.s_addr
);
347 temp
= ntohl(p
->u
.val32
[3]);
349 for (i
= count
; i
< routes
; i
++) {
350 bool buffered
= route_add(p
, vrf_id
, (uint8_t)instance
, nhgid
,
351 nhg
, backup_nhg
, opaque
);
353 p
->u
.prefix4
.s_addr
= htonl(++temp
);
355 p
->u
.val32
[3] = htonl(++temp
);
362 wb
.instance
= instance
;
365 wb
.backup_nhg
= backup_nhg
;
367 wb
.restart
= SHARP_INSTALL_ROUTES_RESTART
;
374 void sharp_install_routes_helper(struct prefix
*p
, vrf_id_t vrf_id
,
375 uint8_t instance
, uint32_t nhgid
,
376 const struct nexthop_group
*nhg
,
377 const struct nexthop_group
*backup_nhg
,
378 uint32_t routes
, char *opaque
)
380 zlog_debug("Inserting %u routes", routes
);
382 /* Only use backup route/nexthops if present */
383 if (backup_nhg
&& (backup_nhg
->nexthop
== NULL
))
386 monotime(&sg
.r
.t_start
);
387 sharp_install_routes_restart(p
, 0, vrf_id
, instance
, nhgid
, nhg
,
388 backup_nhg
, routes
, opaque
);
391 static void sharp_remove_routes_restart(struct prefix
*p
, uint32_t count
,
392 vrf_id_t vrf_id
, uint8_t instance
,
398 if (p
->family
== AF_INET
) {
400 temp
= ntohl(p
->u
.prefix4
.s_addr
);
402 temp
= ntohl(p
->u
.val32
[3]);
404 for (i
= count
; i
< routes
; i
++) {
405 bool buffered
= route_delete(p
, vrf_id
, (uint8_t)instance
);
408 p
->u
.prefix4
.s_addr
= htonl(++temp
);
410 p
->u
.val32
[3] = htonl(++temp
);
416 wb
.instance
= instance
;
418 wb
.restart
= SHARP_DELETE_ROUTES_RESTART
;
425 void sharp_remove_routes_helper(struct prefix
*p
, vrf_id_t vrf_id
,
426 uint8_t instance
, uint32_t routes
)
428 zlog_debug("Removing %u routes", routes
);
430 monotime(&sg
.r
.t_start
);
432 sharp_remove_routes_restart(p
, 0, vrf_id
, instance
, routes
);
435 static void handle_repeated(bool installed
)
437 struct prefix p
= sg
.r
.orig_prefix
;
440 if (sg
.r
.repeat
<= 0)
444 sg
.r
.removed_routes
= 0;
445 sharp_remove_routes_helper(&p
, sg
.r
.vrf_id
,
446 sg
.r
.inst
, sg
.r
.total_routes
);
450 sg
.r
.installed_routes
= 0;
451 sharp_install_routes_helper(&p
, sg
.r
.vrf_id
, sg
.r
.inst
,
452 sg
.r
.nhgid
, &sg
.r
.nhop_group
,
453 &sg
.r
.backup_nhop_group
,
454 sg
.r
.total_routes
, sg
.r
.opaque
);
458 static void sharp_zclient_buffer_ready(void)
460 switch (wb
.restart
) {
461 case SHARP_INSTALL_ROUTES_RESTART
:
462 sharp_install_routes_restart(
463 &wb
.p
, wb
.count
, wb
.vrf_id
, wb
.instance
, wb
.nhgid
,
464 wb
.nhg
, wb
.backup_nhg
, wb
.routes
, wb
.opaque
);
466 case SHARP_DELETE_ROUTES_RESTART
:
467 sharp_remove_routes_restart(&wb
.p
, wb
.count
, wb
.vrf_id
,
468 wb
.instance
, wb
.routes
);
473 static int route_notify_owner(ZAPI_CALLBACK_ARGS
)
477 enum zapi_route_notify_owner note
;
480 if (!zapi_route_notify_decode(zclient
->ibuf
, &p
, &table
, ¬e
,
485 case ZAPI_ROUTE_INSTALLED
:
486 sg
.r
.installed_routes
++;
487 if (sg
.r
.total_routes
== sg
.r
.installed_routes
) {
488 monotime(&sg
.r
.t_end
);
489 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
490 zlog_debug("Installed All Items %jd.%ld",
491 (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
492 handle_repeated(true);
495 case ZAPI_ROUTE_FAIL_INSTALL
:
496 zlog_debug("Failed install of route");
498 case ZAPI_ROUTE_BETTER_ADMIN_WON
:
499 zlog_debug("Better Admin Distance won over us");
501 case ZAPI_ROUTE_REMOVED
:
502 sg
.r
.removed_routes
++;
503 if (sg
.r
.total_routes
== sg
.r
.removed_routes
) {
504 monotime(&sg
.r
.t_end
);
505 timersub(&sg
.r
.t_end
, &sg
.r
.t_start
, &r
);
506 zlog_debug("Removed all Items %jd.%ld",
507 (intmax_t)r
.tv_sec
, (long)r
.tv_usec
);
508 handle_repeated(false);
511 case ZAPI_ROUTE_REMOVE_FAIL
:
512 zlog_debug("Route removal Failure");
518 static void zebra_connected(struct zclient
*zclient
)
520 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
523 * Do not actually turn this on yet
524 * This is just the start of the infrastructure needed here
525 * This can be fixed at a later time.
527 * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
528 * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
532 void vrf_label_add(vrf_id_t vrf_id
, afi_t afi
, mpls_label_t label
)
534 zclient_send_vrf_label(zclient
, vrf_id
, afi
, label
, ZEBRA_LSP_SHARP
);
537 void nhg_add(uint32_t id
, const struct nexthop_group
*nhg
,
538 const struct nexthop_group
*backup_nhg
)
540 struct zapi_nhg api_nhg
= {};
541 struct zapi_nexthop
*api_nh
;
543 bool is_valid
= true;
546 for (ALL_NEXTHOPS_PTR(nhg
, nh
)) {
547 if (api_nhg
.nexthop_num
>= MULTIPATH_NUM
) {
549 "%s: number of nexthops greater than max multipath size, truncating",
554 /* Unresolved nexthops will lead to failure - only send
555 * nexthops that zebra will consider valid.
557 if (nh
->ifindex
== 0)
560 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
562 zapi_nexthop_from_nexthop(api_nh
, nh
);
563 api_nhg
.nexthop_num
++;
566 if (api_nhg
.nexthop_num
== 0) {
567 zlog_debug("%s: nhg %u not sent: no valid nexthops",
574 for (ALL_NEXTHOPS_PTR(backup_nhg
, nh
)) {
575 if (api_nhg
.backup_nexthop_num
>= MULTIPATH_NUM
) {
577 "%s: number of backup nexthops greater than max multipath size, truncating",
582 /* Unresolved nexthop: will be rejected by zebra.
583 * That causes a problem, since the primary nexthops
584 * rely on array indexing into the backup nexthops. If
585 * that array isn't valid, the backup indexes won't be
588 if (nh
->ifindex
== 0) {
589 zlog_debug("%s: nhg %u: invalid backup nexthop",
595 api_nh
= &api_nhg
.backup_nexthops
596 [api_nhg
.backup_nexthop_num
];
598 zapi_backup_nexthop_from_nexthop(api_nh
, nh
);
599 api_nhg
.backup_nexthop_num
++;
605 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
608 void nhg_del(uint32_t id
)
610 struct zapi_nhg api_nhg
= {};
614 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
617 void sharp_zebra_nexthop_watch(struct prefix
*p
, vrf_id_t vrf_id
, bool import
,
618 bool watch
, bool connected
)
623 command
= ZEBRA_NEXTHOP_REGISTER
;
626 command
= ZEBRA_NEXTHOP_UNREGISTER
;
628 command
= ZEBRA_IMPORT_ROUTE_REGISTER
;
631 command
= ZEBRA_IMPORT_ROUTE_UNREGISTER
;
634 if (zclient_send_rnh(zclient
, command
, p
, connected
, vrf_id
)
635 == ZCLIENT_SEND_FAILURE
)
636 zlog_warn("%s: Failure to send nexthop to zebra", __func__
);
639 static int sharp_debug_nexthops(struct zapi_route
*api
)
643 if (api
->nexthop_num
== 0) {
649 for (i
= 0; i
< api
->nexthop_num
; i
++) {
650 struct zapi_nexthop
*znh
= &api
->nexthops
[i
];
653 case NEXTHOP_TYPE_IPV4_IFINDEX
:
654 case NEXTHOP_TYPE_IPV4
:
656 " Nexthop %pI4, type: %d, ifindex: %d, vrf: %d, label_num: %d",
657 &znh
->gate
.ipv4
.s_addr
, znh
->type
, znh
->ifindex
,
658 znh
->vrf_id
, znh
->label_num
);
660 case NEXTHOP_TYPE_IPV6_IFINDEX
:
661 case NEXTHOP_TYPE_IPV6
:
663 " Nexthop %pI6, type: %d, ifindex: %d, vrf: %d, label_num: %d",
664 &znh
->gate
.ipv6
, znh
->type
, znh
->ifindex
,
665 znh
->vrf_id
, znh
->label_num
);
667 case NEXTHOP_TYPE_IFINDEX
:
668 zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d",
669 znh
->type
, znh
->ifindex
);
671 case NEXTHOP_TYPE_BLACKHOLE
:
672 zlog_debug(" Nexthop blackhole");
679 static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS
)
681 struct sharp_nh_tracker
*nht
;
682 struct zapi_route nhr
;
684 if (!zapi_nexthop_update_decode(zclient
->ibuf
, &nhr
)) {
685 zlog_err("%s: Decode of update failed", __func__
);
689 zlog_debug("Received update for %pFX metric: %u", &nhr
.prefix
,
692 nht
= sharp_nh_tracker_get(&nhr
.prefix
);
693 nht
->nhop_num
= nhr
.nexthop_num
;
696 sharp_debug_nexthops(&nhr
);
701 static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS
)
703 struct zapi_route api
;
705 if (zapi_route_decode(zclient
->ibuf
, &api
) < 0)
706 zlog_warn("%s: Decode of redistribute failed: %d", __func__
,
707 ZEBRA_REDISTRIBUTE_ROUTE_ADD
);
709 zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd
),
710 &api
.prefix
, zebra_route_string(api
.type
));
712 sharp_debug_nexthops(&api
);
717 /* Add a zclient with a specified session id, for testing. */
718 int sharp_zclient_create(uint32_t session_id
)
720 struct zclient
*client
;
721 struct sharp_zclient
*node
;
723 /* Check for duplicates */
724 for (node
= sharp_clients_head
; node
!= NULL
; node
= node
->next
) {
725 if (node
->client
->session_id
== session_id
)
729 client
= zclient_new(master
, &zclient_options_default
);
731 client
->session_id
= session_id
;
733 zclient_init(client
, ZEBRA_ROUTE_SHARP
, 0, &sharp_privs
);
735 /* Register handlers for messages we expect this session to see */
736 client
->opaque_msg_handler
= sharp_opaque_handler
;
738 /* Enqueue on the list of test clients */
744 /* Delete one of the extra test zclients */
745 int sharp_zclient_delete(uint32_t session_id
)
747 struct sharp_zclient
*node
;
749 /* Search for session */
750 for (node
= sharp_clients_head
; node
!= NULL
; node
= node
->next
) {
751 if (node
->client
->session_id
== session_id
) {
752 /* Dequeue from list */
754 node
->next
->prev
= node
->prev
;
756 node
->prev
->next
= node
->next
;
757 if (node
== sharp_clients_head
)
758 sharp_clients_head
= node
->next
;
760 /* Clean up zclient */
761 zclient_stop(node
->client
);
762 zclient_free(node
->client
);
765 XFREE(MTYPE_ZC
, node
);
773 static const char *const type2txt
[] = { "Generic", "Vertex", "Edge", "Subnet" };
774 static const char *const status2txt
[] = { "Unknown", "New", "Update",
775 "Delete", "Sync", "Orphan"};
776 /* Handler for opaque messages */
777 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS
)
780 struct zapi_opaque_msg info
;
781 struct ls_element
*lse
;
785 if (zclient_opaque_decode(s
, &info
) != 0)
788 zlog_debug("%s: [%u] received opaque type %u", __func__
,
789 zclient
->session_id
, info
.type
);
791 if (info
.type
== LINK_STATE_UPDATE
) {
792 lse
= ls_stream2ted(sg
.ted
, s
, false);
794 zlog_debug(" |- Got %s %s from Link State Database",
795 status2txt
[lse
->status
],
796 type2txt
[lse
->type
]);
799 "%s: Error to convert Stream into Link State",
807 * Send OPAQUE messages, using subtype 'type'.
809 void sharp_opaque_send(uint32_t type
, uint32_t proto
, uint32_t instance
,
810 uint32_t session_id
, uint32_t count
)
816 /* Prepare a small payload */
817 for (i
= 0; i
< sizeof(buf
); i
++) {
824 /* Send some messages - broadcast and unicast are supported */
825 for (i
= 0; i
< count
; i
++) {
827 ret
= zclient_send_opaque(zclient
, type
, buf
,
830 ret
= zclient_send_opaque_unicast(zclient
, type
, proto
,
831 instance
, session_id
,
833 if (ret
== ZCLIENT_SEND_FAILURE
) {
834 zlog_debug("%s: send_opaque() failed => %d",
843 * Send OPAQUE registration messages, using subtype 'type'.
845 void sharp_opaque_reg_send(bool is_reg
, uint32_t proto
, uint32_t instance
,
846 uint32_t session_id
, uint32_t type
)
854 zclient_create_header(s
, ZEBRA_OPAQUE_REGISTER
, VRF_DEFAULT
);
856 zclient_create_header(s
, ZEBRA_OPAQUE_UNREGISTER
, VRF_DEFAULT
);
859 stream_putl(s
, type
);
861 /* Add zclient info */
862 stream_putc(s
, proto
);
863 stream_putw(s
, instance
);
864 stream_putl(s
, session_id
);
866 /* Put length at the first point of the stream. */
867 stream_putw_at(s
, 0, stream_get_endp(s
));
869 (void)zclient_send_message(zclient
);
873 /* Link State registration */
874 void sharp_zebra_register_te(void)
876 /* First register to received Link State Update messages */
877 zclient_register_opaque(zclient
, LINK_STATE_UPDATE
);
879 /* Then, request initial TED with SYNC message */
880 ls_request_sync(zclient
);
883 void sharp_zebra_send_arp(const struct interface
*ifp
, const struct prefix
*p
)
885 zclient_send_neigh_discovery_req(zclient
, ifp
, p
);
888 static int nhg_notify_owner(ZAPI_CALLBACK_ARGS
)
890 enum zapi_nhg_notify_owner note
;
893 if (!zapi_nhg_notify_decode(zclient
->ibuf
, &id
, ¬e
))
897 case ZAPI_NHG_INSTALLED
:
898 sharp_nhgroup_id_set_installed(id
, true);
899 zlog_debug("Installed nhg %u", id
);
901 case ZAPI_NHG_FAIL_INSTALL
:
902 zlog_debug("Failed install of nhg %u", id
);
904 case ZAPI_NHG_REMOVED
:
905 zlog_debug("Removed nhg %u", id
);
907 case ZAPI_NHG_REMOVE_FAIL
:
908 zlog_debug("Failed removal of nhg %u", id
);
915 void sharp_zebra_init(void)
917 struct zclient_options opt
= {.receive_notify
= true};
919 if_zapi_callbacks(sharp_ifp_create
, sharp_ifp_up
,
920 sharp_ifp_down
, sharp_ifp_destroy
);
922 zclient
= zclient_new(master
, &opt
);
924 zclient_init(zclient
, ZEBRA_ROUTE_SHARP
, 0, &sharp_privs
);
925 zclient
->zebra_connected
= zebra_connected
;
926 zclient
->interface_address_add
= interface_address_add
;
927 zclient
->interface_address_delete
= interface_address_delete
;
928 zclient
->route_notify_owner
= route_notify_owner
;
929 zclient
->nexthop_update
= sharp_nexthop_update
;
930 zclient
->import_check_update
= sharp_nexthop_update
;
931 zclient
->nhg_notify_owner
= nhg_notify_owner
;
932 zclient
->zebra_buffer_write_ready
= sharp_zclient_buffer_ready
;
933 zclient
->redistribute_route_add
= sharp_redistribute_route
;
934 zclient
->redistribute_route_del
= sharp_redistribute_route
;
935 zclient
->opaque_msg_handler
= sharp_opaque_handler
;