]> git.proxmox.com Git - mirror_frr.git/blob - sharpd/sharp_zebra.c
isisd: if IS-IS is configured for v6, prefer v6 bfd sessions
[mirror_frr.git] / sharpd / sharp_zebra.c
1 /*
2 * Zebra connect code.
3 * Copyright (C) Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This file is part of FRR.
7 *
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
11 * later version.
12 *
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.
17 *
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
21 */
22 #include <zebra.h>
23
24 #include "thread.h"
25 #include "command.h"
26 #include "network.h"
27 #include "prefix.h"
28 #include "stream.h"
29 #include "memory.h"
30 #include "zclient.h"
31 #include "nexthop.h"
32 #include "nexthop_group.h"
33
34 #include "sharp_globals.h"
35 #include "sharp_nht.h"
36 #include "sharp_zebra.h"
37
38 /* Zebra structure to hold current status. */
39 struct zclient *zclient = NULL;
40
41 /* For registering threads. */
42 extern struct thread_master *master;
43
44 /* Privs info */
45 extern struct zebra_privs_t sharp_privs;
46
47 DEFINE_MTYPE_STATIC(SHARPD, ZC, "Test zclients");
48
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;
54 };
55
56 /* Head of test zclient list */
57 static struct sharp_zclient *sharp_clients_head;
58
59 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS);
60
61 /* Utility to add a test zclient struct to the list */
62 static void add_zclient(struct zclient *client)
63 {
64 struct sharp_zclient *node;
65
66 node = XCALLOC(MTYPE_ZC, sizeof(struct sharp_zclient));
67
68 node->client = client;
69
70 node->next = sharp_clients_head;
71 if (sharp_clients_head)
72 sharp_clients_head->prev = node;
73 sharp_clients_head = node;
74 }
75
76 /* Interface addition message from zebra. */
77 static int sharp_ifp_create(struct interface *ifp)
78 {
79 return 0;
80 }
81
82 static int sharp_ifp_destroy(struct interface *ifp)
83 {
84 return 0;
85 }
86
87 static int interface_address_add(ZAPI_CALLBACK_ARGS)
88 {
89 zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
90
91 return 0;
92 }
93
94 static int interface_address_delete(ZAPI_CALLBACK_ARGS)
95 {
96 struct connected *c;
97
98 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
99
100 if (!c)
101 return 0;
102
103 connected_free(&c);
104 return 0;
105 }
106
107 static int sharp_ifp_up(struct interface *ifp)
108 {
109 return 0;
110 }
111
112 static int sharp_ifp_down(struct interface *ifp)
113 {
114 return 0;
115 }
116
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)
122 {
123 struct zapi_labels zl = {};
124 struct zapi_nexthop *znh;
125 const struct nexthop *nh;
126 int i, cmd, ret;
127
128 zl.type = ZEBRA_LSP_SHARP;
129 zl.local_label = in_label;
130
131 if (p) {
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;
136 }
137
138 /* List of nexthops is optional for delete */
139 i = 0;
140 if (nhg) {
141 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
142 znh = &zl.nexthops[i];
143
144 /* Must have labels to be useful */
145 if (nh->nh_label == NULL ||
146 nh->nh_label->num_labels == 0)
147 continue;
148
149 if (nh->type == NEXTHOP_TYPE_IFINDEX ||
150 nh->type == NEXTHOP_TYPE_BLACKHOLE)
151 /* Hmm - can't really deal with these types */
152 continue;
153
154 ret = zapi_nexthop_from_nexthop(znh, nh);
155 if (ret < 0)
156 return -1;
157
158 i++;
159 if (i >= MULTIPATH_NUM)
160 break;
161 }
162 }
163
164 /* Whoops - no nexthops isn't very useful for install */
165 if (i == 0 && install_p)
166 return -1;
167
168 zl.nexthop_num = i;
169
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.
173 */
174 if (backup_nhg != NULL) {
175 i = 0;
176 for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
177 znh = &zl.backup_nexthops[i];
178
179 /* Must have labels to be useful */
180 if (nh->nh_label == NULL ||
181 nh->nh_label->num_labels == 0)
182 return -1;
183
184 if (nh->type == NEXTHOP_TYPE_IFINDEX ||
185 nh->type == NEXTHOP_TYPE_BLACKHOLE)
186 /* Hmm - can't really deal with these types */
187 return -1;
188
189 ret = zapi_nexthop_from_nexthop(znh, nh);
190 if (ret < 0)
191 return -1;
192
193 i++;
194 if (i >= MULTIPATH_NUM)
195 break;
196 }
197
198 if (i > 0)
199 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
200
201 zl.backup_nexthop_num = i;
202 }
203
204
205 if (install_p) {
206 if (update_p)
207 cmd = ZEBRA_MPLS_LABELS_REPLACE;
208 else
209 cmd = ZEBRA_MPLS_LABELS_ADD;
210 } else {
211 cmd = ZEBRA_MPLS_LABELS_DELETE;
212 }
213
214 ret = zebra_send_mpls_labels(zclient, cmd, &zl);
215
216 return ret;
217 }
218
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,
223 uint32_t routes)
224 {
225 uint32_t temp, i;
226 bool v4 = false;
227
228 zlog_debug("Inserting %u routes", routes);
229
230 if (p->family == AF_INET) {
231 v4 = true;
232 temp = ntohl(p->u.prefix4.s_addr);
233 } else
234 temp = ntohl(p->u.val32[3]);
235
236 /* Only use backup route/nexthops if present */
237 if (backup_nhg && (backup_nhg->nexthop == NULL))
238 backup_nhg = NULL;
239
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);
243 if (v4)
244 p->u.prefix4.s_addr = htonl(++temp);
245 else
246 p->u.val32[3] = htonl(++temp);
247 }
248 }
249
250 void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
251 uint8_t instance, uint32_t routes)
252 {
253 uint32_t temp, i;
254 bool v4 = false;
255
256 zlog_debug("Removing %u routes", routes);
257
258 if (p->family == AF_INET) {
259 v4 = true;
260 temp = ntohl(p->u.prefix4.s_addr);
261 } else
262 temp = ntohl(p->u.val32[3]);
263
264 monotime(&sg.r.t_start);
265 for (i = 0; i < routes; i++) {
266 route_delete(p, vrf_id, (uint8_t)instance);
267 if (v4)
268 p->u.prefix4.s_addr = htonl(++temp);
269 else
270 p->u.val32[3] = htonl(++temp);
271 }
272 }
273
274 static void handle_repeated(bool installed)
275 {
276 struct prefix p = sg.r.orig_prefix;
277 sg.r.repeat--;
278
279 if (sg.r.repeat <= 0)
280 return;
281
282 if (installed) {
283 sg.r.removed_routes = 0;
284 sharp_remove_routes_helper(&p, sg.r.vrf_id,
285 sg.r.inst, sg.r.total_routes);
286 }
287
288 if (!installed) {
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,
293 sg.r.total_routes);
294 }
295 }
296
297 static int route_notify_owner(ZAPI_CALLBACK_ARGS)
298 {
299 struct timeval r;
300 struct prefix p;
301 enum zapi_route_notify_owner note;
302 uint32_t table;
303
304 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, &note,
305 NULL, NULL))
306 return -1;
307
308 switch (note) {
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);
317 }
318 break;
319 case ZAPI_ROUTE_FAIL_INSTALL:
320 zlog_debug("Failed install of route");
321 break;
322 case ZAPI_ROUTE_BETTER_ADMIN_WON:
323 zlog_debug("Better Admin Distance won over us");
324 break;
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);
333 }
334 break;
335 case ZAPI_ROUTE_REMOVE_FAIL:
336 zlog_debug("Route removal Failure");
337 break;
338 }
339 return 0;
340 }
341
342 static void zebra_connected(struct zclient *zclient)
343 {
344 zclient_send_reg_requests(zclient, VRF_DEFAULT);
345
346 /*
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.
350 *
351 * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
352 * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
353 */
354 }
355
356 void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
357 {
358 zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
359 }
360
361 void nhg_add(uint32_t id, const struct nexthop_group *nhg,
362 const struct nexthop_group *backup_nhg)
363 {
364 struct zapi_nhg api_nhg = {};
365 struct zapi_nexthop *api_nh;
366 struct nexthop *nh;
367
368 api_nhg.id = id;
369 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
370 if (api_nhg.nexthop_num >= MULTIPATH_NUM) {
371 zlog_warn(
372 "%s: number of nexthops greater than max multipath size, truncating",
373 __func__);
374 break;
375 }
376
377 api_nh = &api_nhg.nexthops[api_nhg.nexthop_num];
378
379 zapi_nexthop_from_nexthop(api_nh, nh);
380 api_nhg.nexthop_num++;
381 }
382
383 if (backup_nhg) {
384 for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
385 if (api_nhg.backup_nexthop_num >= MULTIPATH_NUM) {
386 zlog_warn(
387 "%s: number of backup nexthops greater than max multipath size, truncating",
388 __func__);
389 break;
390 }
391 api_nh = &api_nhg.backup_nexthops
392 [api_nhg.backup_nexthop_num];
393
394 zapi_backup_nexthop_from_nexthop(api_nh, nh);
395 api_nhg.backup_nexthop_num++;
396 }
397 }
398
399 zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
400 }
401
402 void nhg_del(uint32_t id)
403 {
404 struct zapi_nhg api_nhg = {};
405
406 api_nhg.id = id;
407
408 zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
409 }
410
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)
414 {
415 struct zapi_route api;
416 struct zapi_nexthop *api_nh;
417 struct nexthop *nh;
418 int i = 0;
419
420 memset(&api, 0, sizeof(api));
421 api.vrf_id = vrf_id;
422 api.type = ZEBRA_ROUTE_SHARP;
423 api.instance = instance;
424 api.safi = SAFI_UNICAST;
425 memcpy(&api.prefix, p, sizeof(*p));
426
427 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
428 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
429
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);
433 api.nhgid = nhgid;
434 } else {
435 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
436 api_nh = &api.nexthops[i];
437
438 zapi_nexthop_from_nexthop(api_nh, nh);
439
440 i++;
441 }
442 api.nexthop_num = i;
443 }
444
445 /* Include backup nexthops, if present */
446 if (backup_nhg && backup_nhg->nexthop) {
447 SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
448
449 i = 0;
450 for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
451 api_nh = &api.backup_nexthops[i];
452
453 zapi_backup_nexthop_from_nexthop(api_nh, nh);
454
455 i++;
456 }
457
458 api.backup_nexthop_num = i;
459 }
460
461 zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
462 }
463
464 void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)
465 {
466 struct zapi_route api;
467
468 memset(&api, 0, sizeof(api));
469 api.vrf_id = vrf_id;
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);
475
476 return;
477 }
478
479 void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
480 bool watch, bool connected)
481 {
482 int command;
483
484 if (!import) {
485 command = ZEBRA_NEXTHOP_REGISTER;
486
487 if (!watch)
488 command = ZEBRA_NEXTHOP_UNREGISTER;
489 } else {
490 command = ZEBRA_IMPORT_ROUTE_REGISTER;
491
492 if (!watch)
493 command = ZEBRA_IMPORT_ROUTE_UNREGISTER;
494 }
495
496 if (zclient_send_rnh(zclient, command, p, connected, vrf_id) < 0)
497 zlog_warn("%s: Failure to send nexthop to zebra", __func__);
498 }
499
500 static int sharp_debug_nexthops(struct zapi_route *api)
501 {
502 int i;
503 char buf[PREFIX_STRLEN];
504
505 if (api->nexthop_num == 0) {
506 zlog_debug(
507 " Not installed");
508 return 0;
509 }
510
511 for (i = 0; i < api->nexthop_num; i++) {
512 struct zapi_nexthop *znh = &api->nexthops[i];
513
514 switch (znh->type) {
515 case NEXTHOP_TYPE_IPV4_IFINDEX:
516 case NEXTHOP_TYPE_IPV4:
517 zlog_debug(
518 " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
519 inet_ntop(AF_INET, &znh->gate.ipv4.s_addr, buf,
520 sizeof(buf)),
521 znh->type, znh->ifindex, znh->vrf_id,
522 znh->label_num);
523 break;
524 case NEXTHOP_TYPE_IPV6_IFINDEX:
525 case NEXTHOP_TYPE_IPV6:
526 zlog_debug(
527 " Nexthop %s, type: %d, ifindex: %d, vrf: %d, label_num: %d",
528 inet_ntop(AF_INET6, &znh->gate.ipv6, buf,
529 sizeof(buf)),
530 znh->type, znh->ifindex, znh->vrf_id,
531 znh->label_num);
532 break;
533 case NEXTHOP_TYPE_IFINDEX:
534 zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d",
535 znh->type, znh->ifindex);
536 break;
537 case NEXTHOP_TYPE_BLACKHOLE:
538 zlog_debug(" Nexthop blackhole");
539 break;
540 }
541 }
542
543 return i;
544 }
545 static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
546 {
547 struct sharp_nh_tracker *nht;
548 struct zapi_route nhr;
549
550 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
551 zlog_err("%s: Decode of update failed", __func__);
552 return 0;
553 }
554
555 zlog_debug("Received update for %pFX", &nhr.prefix);
556
557 nht = sharp_nh_tracker_get(&nhr.prefix);
558 nht->nhop_num = nhr.nexthop_num;
559 nht->updates++;
560
561 sharp_debug_nexthops(&nhr);
562
563 return 0;
564 }
565
566 static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS)
567 {
568 struct zapi_route api;
569
570 if (zapi_route_decode(zclient->ibuf, &api) < 0)
571 zlog_warn("%s: Decode of redistribute failed: %d", __func__,
572 ZEBRA_REDISTRIBUTE_ROUTE_ADD);
573
574 zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd),
575 &api.prefix, zebra_route_string(api.type));
576
577 sharp_debug_nexthops(&api);
578
579 return 0;
580 }
581
582 /* Add a zclient with a specified session id, for testing. */
583 int sharp_zclient_create(uint32_t session_id)
584 {
585 struct zclient *client;
586 struct sharp_zclient *node;
587
588 /* Check for duplicates */
589 for (node = sharp_clients_head; node != NULL; node = node->next) {
590 if (node->client->session_id == session_id)
591 return -1;
592 }
593
594 client = zclient_new(master, &zclient_options_default);
595 client->sock = -1;
596 client->session_id = session_id;
597
598 zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs);
599
600 /* Register handlers for messages we expect this session to see */
601 client->opaque_msg_handler = sharp_opaque_handler;
602
603 /* Enqueue on the list of test clients */
604 add_zclient(client);
605
606 return 0;
607 }
608
609 /* Delete one of the extra test zclients */
610 int sharp_zclient_delete(uint32_t session_id)
611 {
612 struct sharp_zclient *node;
613
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 */
618 if (node->next)
619 node->next->prev = node->prev;
620 if (node->prev)
621 node->prev->next = node->next;
622 if (node == sharp_clients_head)
623 sharp_clients_head = node->next;
624
625 /* Clean up zclient */
626 zclient_stop(node->client);
627 zclient_free(node->client);
628
629 /* Free memory */
630 XFREE(MTYPE_ZC, node);
631 break;
632 }
633 }
634
635 return 0;
636 }
637
638 /* Handler for opaque messages */
639 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)
640 {
641 struct stream *s;
642 struct zapi_opaque_msg info;
643
644 s = zclient->ibuf;
645
646 if (zclient_opaque_decode(s, &info) != 0)
647 return -1;
648
649 zlog_debug("%s: [%u] received opaque type %u", __func__,
650 zclient->session_id, info.type);
651
652 return 0;
653 }
654
655 /*
656 * Send OPAQUE messages, using subtype 'type'.
657 */
658 void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance,
659 uint32_t session_id, uint32_t count)
660 {
661 uint8_t buf[32];
662 int ret;
663 uint32_t i;
664
665 /* Prepare a small payload */
666 for (i = 0; i < sizeof(buf); i++) {
667 if (type < 255)
668 buf[i] = type;
669 else
670 buf[i] = 255;
671 }
672
673 /* Send some messages - broadcast and unicast are supported */
674 for (i = 0; i < count; i++) {
675 if (proto == 0)
676 ret = zclient_send_opaque(zclient, type, buf,
677 sizeof(buf));
678 else
679 ret = zclient_send_opaque_unicast(zclient, type, proto,
680 instance, session_id,
681 buf, sizeof(buf));
682 if (ret < 0) {
683 zlog_debug("%s: send_opaque() failed => %d",
684 __func__, ret);
685 break;
686 }
687 }
688
689 }
690
691 /*
692 * Send OPAQUE registration messages, using subtype 'type'.
693 */
694 void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance,
695 uint32_t session_id, uint32_t type)
696 {
697 struct stream *s;
698
699 s = zclient->obuf;
700 stream_reset(s);
701
702 if (is_reg)
703 zclient_create_header(s, ZEBRA_OPAQUE_REGISTER, VRF_DEFAULT);
704 else
705 zclient_create_header(s, ZEBRA_OPAQUE_UNREGISTER, VRF_DEFAULT);
706
707 /* Send sub-type */
708 stream_putl(s, type);
709
710 /* Add zclient info */
711 stream_putc(s, proto);
712 stream_putw(s, instance);
713 stream_putl(s, session_id);
714
715 /* Put length at the first point of the stream. */
716 stream_putw_at(s, 0, stream_get_endp(s));
717
718 (void)zclient_send_message(zclient);
719
720 }
721
722 void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
723 {
724 zclient_send_neigh_discovery_req(zclient, ifp, p);
725 }
726
727 static int nhg_notify_owner(ZAPI_CALLBACK_ARGS)
728 {
729 enum zapi_nhg_notify_owner note;
730 uint32_t id;
731
732 if (!zapi_nhg_notify_decode(zclient->ibuf, &id, &note))
733 return -1;
734
735 switch (note) {
736 case ZAPI_NHG_INSTALLED:
737 sharp_nhgroup_id_set_installed(id, true);
738 zlog_debug("Installed nhg %u", id);
739 break;
740 case ZAPI_NHG_FAIL_INSTALL:
741 zlog_debug("Failed install of nhg %u", id);
742 break;
743 case ZAPI_NHG_REMOVED:
744 zlog_debug("Removed nhg %u", id);
745 break;
746 case ZAPI_NHG_REMOVE_FAIL:
747 zlog_debug("Failed removal of nhg %u", id);
748 break;
749 }
750
751 return 0;
752 }
753
754 void sharp_zebra_init(void)
755 {
756 struct zclient_options opt = {.receive_notify = true};
757
758 if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up,
759 sharp_ifp_down, sharp_ifp_destroy);
760
761 zclient = zclient_new(master, &opt);
762
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;
771
772 zclient->redistribute_route_add = sharp_redistribute_route;
773 zclient->redistribute_route_del = sharp_redistribute_route;
774 zclient->opaque_msg_handler = sharp_opaque_handler;
775 }