]> git.proxmox.com Git - mirror_frr.git/blob - sharpd/sharp_zebra.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / sharpd / sharp_zebra.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Zebra connect code.
4 * Copyright (C) Cumulus Networks, Inc.
5 * Donald Sharp
6 */
7 #include <zebra.h>
8
9 #include "thread.h"
10 #include "command.h"
11 #include "network.h"
12 #include "prefix.h"
13 #include "stream.h"
14 #include "memory.h"
15 #include "zclient.h"
16 #include "nexthop.h"
17 #include "nexthop_group.h"
18 #include "link_state.h"
19 #include "tc.h"
20
21 #include "sharp_globals.h"
22 #include "sharp_nht.h"
23 #include "sharp_zebra.h"
24
25 /* Zebra structure to hold current status. */
26 struct zclient *zclient = NULL;
27
28 /* For registering threads. */
29 extern struct thread_master *master;
30
31 /* Privs info */
32 extern struct zebra_privs_t sharp_privs;
33
34 DEFINE_MTYPE_STATIC(SHARPD, ZC, "Test zclients");
35
36 /* Struct to hold list of test zclients */
37 struct sharp_zclient {
38 struct sharp_zclient *prev;
39 struct sharp_zclient *next;
40 struct zclient *client;
41 };
42
43 /* Head of test zclient list */
44 static struct sharp_zclient *sharp_clients_head;
45
46 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS);
47
48 /* Utility to add a test zclient struct to the list */
49 static void add_zclient(struct zclient *client)
50 {
51 struct sharp_zclient *node;
52
53 node = XCALLOC(MTYPE_ZC, sizeof(struct sharp_zclient));
54
55 node->client = client;
56
57 node->next = sharp_clients_head;
58 if (sharp_clients_head)
59 sharp_clients_head->prev = node;
60 sharp_clients_head = node;
61 }
62
63 /* Interface addition message from zebra. */
64 static int sharp_ifp_create(struct interface *ifp)
65 {
66 return 0;
67 }
68
69 static int sharp_ifp_destroy(struct interface *ifp)
70 {
71 return 0;
72 }
73
74 static int interface_address_add(ZAPI_CALLBACK_ARGS)
75 {
76 zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
77
78 return 0;
79 }
80
81 static int interface_address_delete(ZAPI_CALLBACK_ARGS)
82 {
83 struct connected *c;
84
85 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
86
87 if (!c)
88 return 0;
89
90 connected_free(&c);
91 return 0;
92 }
93
94 static int sharp_ifp_up(struct interface *ifp)
95 {
96 return 0;
97 }
98
99 static int sharp_ifp_down(struct interface *ifp)
100 {
101 return 0;
102 }
103
104 int sharp_install_lsps_helper(bool install_p, bool update_p,
105 const struct prefix *p, uint8_t type,
106 int instance, uint32_t in_label,
107 const struct nexthop_group *nhg,
108 const struct nexthop_group *backup_nhg)
109 {
110 struct zapi_labels zl = {};
111 struct zapi_nexthop *znh;
112 const struct nexthop *nh;
113 int i, cmd, ret;
114
115 zl.type = ZEBRA_LSP_SHARP;
116 zl.local_label = in_label;
117
118 if (p) {
119 SET_FLAG(zl.message, ZAPI_LABELS_FTN);
120 prefix_copy(&zl.route.prefix, p);
121 zl.route.type = type;
122 zl.route.instance = instance;
123 }
124
125 /* List of nexthops is optional for delete */
126 i = 0;
127 if (nhg) {
128 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
129 znh = &zl.nexthops[i];
130
131 /* Must have labels to be useful */
132 if (nh->nh_label == NULL ||
133 nh->nh_label->num_labels == 0)
134 continue;
135
136 if (nh->type == NEXTHOP_TYPE_IFINDEX ||
137 nh->type == NEXTHOP_TYPE_BLACKHOLE)
138 /* Hmm - can't really deal with these types */
139 continue;
140
141 ret = zapi_nexthop_from_nexthop(znh, nh);
142 if (ret < 0)
143 return -1;
144
145 i++;
146 if (i >= MULTIPATH_NUM)
147 break;
148 }
149 }
150
151 /* Whoops - no nexthops isn't very useful for install */
152 if (i == 0 && install_p)
153 return -1;
154
155 zl.nexthop_num = i;
156
157 /* Add optional backup nexthop info. Since these are used by index,
158 * we can't just skip over an invalid backup nexthop: we will
159 * invalidate the entire operation.
160 */
161 if (backup_nhg != NULL) {
162 i = 0;
163 for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
164 znh = &zl.backup_nexthops[i];
165
166 /* Must have labels to be useful */
167 if (nh->nh_label == NULL ||
168 nh->nh_label->num_labels == 0)
169 return -1;
170
171 if (nh->type == NEXTHOP_TYPE_IFINDEX ||
172 nh->type == NEXTHOP_TYPE_BLACKHOLE)
173 /* Hmm - can't really deal with these types */
174 return -1;
175
176 ret = zapi_nexthop_from_nexthop(znh, nh);
177 if (ret < 0)
178 return -1;
179
180 i++;
181 if (i >= MULTIPATH_NUM)
182 break;
183 }
184
185 if (i > 0)
186 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
187
188 zl.backup_nexthop_num = i;
189 }
190
191
192 if (install_p) {
193 if (update_p)
194 cmd = ZEBRA_MPLS_LABELS_REPLACE;
195 else
196 cmd = ZEBRA_MPLS_LABELS_ADD;
197 } else {
198 cmd = ZEBRA_MPLS_LABELS_DELETE;
199 }
200
201 if (zebra_send_mpls_labels(zclient, cmd, &zl) == ZCLIENT_SEND_FAILURE)
202 return -1;
203
204 return 0;
205 }
206
207 enum where_to_restart {
208 SHARP_INSTALL_ROUTES_RESTART,
209 SHARP_DELETE_ROUTES_RESTART,
210 };
211
212 struct buffer_delay {
213 struct prefix p;
214 uint32_t count;
215 uint32_t routes;
216 vrf_id_t vrf_id;
217 uint8_t instance;
218 uint32_t nhgid;
219 uint32_t flags;
220 const struct nexthop_group *nhg;
221 const struct nexthop_group *backup_nhg;
222 enum where_to_restart restart;
223 char *opaque;
224 } wb;
225
226 /*
227 * route_add - Encodes a route to zebra
228 *
229 * This function returns true when the route was buffered
230 * by the underlying stream system
231 */
232 static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,
233 uint32_t nhgid, const struct nexthop_group *nhg,
234 const struct nexthop_group *backup_nhg, uint32_t flags,
235 char *opaque)
236 {
237 struct zapi_route api;
238 struct zapi_nexthop *api_nh;
239 struct nexthop *nh;
240 int i = 0;
241
242 memset(&api, 0, sizeof(api));
243 api.vrf_id = vrf_id;
244 api.type = ZEBRA_ROUTE_SHARP;
245 api.instance = instance;
246 api.safi = SAFI_UNICAST;
247 memcpy(&api.prefix, p, sizeof(*p));
248
249 api.flags = flags;
250 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
251 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
252
253 /* Only send via ID if nhgroup has been successfully installed */
254 if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) {
255 SET_FLAG(api.message, ZAPI_MESSAGE_NHG);
256 api.nhgid = nhgid;
257 } else {
258 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
259 api_nh = &api.nexthops[i];
260
261 zapi_nexthop_from_nexthop(api_nh, nh);
262
263 i++;
264 }
265 api.nexthop_num = i;
266 }
267
268 /* Include backup nexthops, if present */
269 if (backup_nhg && backup_nhg->nexthop) {
270 SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
271
272 i = 0;
273 for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
274 api_nh = &api.backup_nexthops[i];
275
276 zapi_backup_nexthop_from_nexthop(api_nh, nh);
277
278 i++;
279 }
280
281 api.backup_nexthop_num = i;
282 }
283
284 if (strlen(opaque)) {
285 SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE);
286 api.opaque.length = strlen(opaque) + 1;
287 assert(api.opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH);
288 memcpy(api.opaque.data, opaque, api.opaque.length);
289 }
290
291 if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api) ==
292 ZCLIENT_SEND_BUFFERED)
293 return true;
294 else
295 return false;
296 }
297
298 /*
299 * route_delete - Encodes a route for deletion to zebra
300 *
301 * This function returns true when the route sent was
302 * buffered by the underlying stream system.
303 */
304 static bool route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance)
305 {
306 struct zapi_route api;
307
308 memset(&api, 0, sizeof(api));
309 api.vrf_id = vrf_id;
310 api.type = ZEBRA_ROUTE_SHARP;
311 api.safi = SAFI_UNICAST;
312 api.instance = instance;
313 memcpy(&api.prefix, p, sizeof(*p));
314
315 if (zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api) ==
316 ZCLIENT_SEND_BUFFERED)
317 return true;
318 else
319 return false;
320 }
321
322 static void sharp_install_routes_restart(struct prefix *p, uint32_t count,
323 vrf_id_t vrf_id, uint8_t instance,
324 uint32_t nhgid,
325 const struct nexthop_group *nhg,
326 const struct nexthop_group *backup_nhg,
327 uint32_t routes, uint32_t flags,
328 char *opaque)
329 {
330 uint32_t temp, i;
331 bool v4 = false;
332
333 if (p->family == AF_INET) {
334 v4 = true;
335 temp = ntohl(p->u.prefix4.s_addr);
336 } else
337 temp = ntohl(p->u.val32[3]);
338
339 for (i = count; i < routes; i++) {
340 bool buffered = route_add(p, vrf_id, (uint8_t)instance, nhgid,
341 nhg, backup_nhg, flags, opaque);
342 if (v4)
343 p->u.prefix4.s_addr = htonl(++temp);
344 else
345 p->u.val32[3] = htonl(++temp);
346
347 if (buffered) {
348 wb.p = *p;
349 wb.count = i + 1;
350 wb.routes = routes;
351 wb.vrf_id = vrf_id;
352 wb.instance = instance;
353 wb.nhgid = nhgid;
354 wb.nhg = nhg;
355 wb.flags = flags;
356 wb.backup_nhg = backup_nhg;
357 wb.opaque = opaque;
358 wb.restart = SHARP_INSTALL_ROUTES_RESTART;
359
360 return;
361 }
362 }
363 }
364
365 void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
366 uint8_t instance, uint32_t nhgid,
367 const struct nexthop_group *nhg,
368 const struct nexthop_group *backup_nhg,
369 uint32_t routes, uint32_t flags, char *opaque)
370 {
371 zlog_debug("Inserting %u routes", routes);
372
373 /* Only use backup route/nexthops if present */
374 if (backup_nhg && (backup_nhg->nexthop == NULL))
375 backup_nhg = NULL;
376
377 monotime(&sg.r.t_start);
378 sharp_install_routes_restart(p, 0, vrf_id, instance, nhgid, nhg,
379 backup_nhg, routes, flags, opaque);
380 }
381
382 static void sharp_remove_routes_restart(struct prefix *p, uint32_t count,
383 vrf_id_t vrf_id, uint8_t instance,
384 uint32_t routes)
385 {
386 uint32_t temp, i;
387 bool v4 = false;
388
389 if (p->family == AF_INET) {
390 v4 = true;
391 temp = ntohl(p->u.prefix4.s_addr);
392 } else
393 temp = ntohl(p->u.val32[3]);
394
395 for (i = count; i < routes; i++) {
396 bool buffered = route_delete(p, vrf_id, (uint8_t)instance);
397
398 if (v4)
399 p->u.prefix4.s_addr = htonl(++temp);
400 else
401 p->u.val32[3] = htonl(++temp);
402
403 if (buffered) {
404 wb.p = *p;
405 wb.count = i + 1;
406 wb.vrf_id = vrf_id;
407 wb.instance = instance;
408 wb.routes = routes;
409 wb.restart = SHARP_DELETE_ROUTES_RESTART;
410
411 return;
412 }
413 }
414 }
415
416 void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
417 uint8_t instance, uint32_t routes)
418 {
419 zlog_debug("Removing %u routes", routes);
420
421 monotime(&sg.r.t_start);
422
423 sharp_remove_routes_restart(p, 0, vrf_id, instance, routes);
424 }
425
426 static void handle_repeated(bool installed)
427 {
428 struct prefix p = sg.r.orig_prefix;
429 sg.r.repeat--;
430
431 if (sg.r.repeat <= 0)
432 return;
433
434 if (installed) {
435 sg.r.removed_routes = 0;
436 sharp_remove_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
437 sg.r.total_routes);
438 }
439
440 if (!installed) {
441 sg.r.installed_routes = 0;
442 sharp_install_routes_helper(
443 &p, sg.r.vrf_id, sg.r.inst, sg.r.nhgid,
444 &sg.r.nhop_group, &sg.r.backup_nhop_group,
445 sg.r.total_routes, sg.r.flags, sg.r.opaque);
446 }
447 }
448
449 static void sharp_zclient_buffer_ready(void)
450 {
451 switch (wb.restart) {
452 case SHARP_INSTALL_ROUTES_RESTART:
453 sharp_install_routes_restart(
454 &wb.p, wb.count, wb.vrf_id, wb.instance, wb.nhgid,
455 wb.nhg, wb.backup_nhg, wb.routes, wb.flags, wb.opaque);
456 return;
457 case SHARP_DELETE_ROUTES_RESTART:
458 sharp_remove_routes_restart(&wb.p, wb.count, wb.vrf_id,
459 wb.instance, wb.routes);
460 return;
461 }
462 }
463
464 static int route_notify_owner(ZAPI_CALLBACK_ARGS)
465 {
466 struct timeval r;
467 struct prefix p;
468 enum zapi_route_notify_owner note;
469 uint32_t table;
470
471 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table, &note, NULL,
472 NULL))
473 return -1;
474
475 switch (note) {
476 case ZAPI_ROUTE_INSTALLED:
477 sg.r.installed_routes++;
478 if (sg.r.total_routes == sg.r.installed_routes) {
479 monotime(&sg.r.t_end);
480 timersub(&sg.r.t_end, &sg.r.t_start, &r);
481 zlog_debug("Installed All Items %jd.%ld",
482 (intmax_t)r.tv_sec, (long)r.tv_usec);
483 handle_repeated(true);
484 }
485 break;
486 case ZAPI_ROUTE_FAIL_INSTALL:
487 zlog_debug("Failed install of route");
488 break;
489 case ZAPI_ROUTE_BETTER_ADMIN_WON:
490 zlog_debug("Better Admin Distance won over us");
491 break;
492 case ZAPI_ROUTE_REMOVED:
493 sg.r.removed_routes++;
494 if (sg.r.total_routes == sg.r.removed_routes) {
495 monotime(&sg.r.t_end);
496 timersub(&sg.r.t_end, &sg.r.t_start, &r);
497 zlog_debug("Removed all Items %jd.%ld",
498 (intmax_t)r.tv_sec, (long)r.tv_usec);
499 handle_repeated(false);
500 }
501 break;
502 case ZAPI_ROUTE_REMOVE_FAIL:
503 zlog_debug("Route removal Failure");
504 break;
505 }
506 return 0;
507 }
508
509 static void zebra_connected(struct zclient *zclient)
510 {
511 zclient_send_reg_requests(zclient, VRF_DEFAULT);
512
513 /*
514 * Do not actually turn this on yet
515 * This is just the start of the infrastructure needed here
516 * This can be fixed at a later time.
517 *
518 * zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
519 * ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
520 */
521 }
522
523 void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
524 {
525 zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
526 }
527
528 void nhg_add(uint32_t id, const struct nexthop_group *nhg,
529 const struct nexthop_group *backup_nhg)
530 {
531 struct zapi_nhg api_nhg = {};
532 struct zapi_nexthop *api_nh;
533 struct nexthop *nh;
534 bool is_valid = true;
535
536 api_nhg.id = id;
537
538 api_nhg.resilience = nhg->nhgr;
539
540 for (ALL_NEXTHOPS_PTR(nhg, nh)) {
541 if (api_nhg.nexthop_num >= MULTIPATH_NUM) {
542 zlog_warn(
543 "%s: number of nexthops greater than max multipath size, truncating",
544 __func__);
545 break;
546 }
547
548 /* Unresolved nexthops will lead to failure - only send
549 * nexthops that zebra will consider valid.
550 */
551 if (nh->ifindex == 0)
552 continue;
553
554 api_nh = &api_nhg.nexthops[api_nhg.nexthop_num];
555
556 zapi_nexthop_from_nexthop(api_nh, nh);
557 api_nhg.nexthop_num++;
558 }
559
560 if (api_nhg.nexthop_num == 0) {
561 zlog_debug("%s: nhg %u not sent: no valid nexthops", __func__,
562 id);
563 is_valid = false;
564 goto done;
565 }
566
567 if (backup_nhg) {
568 for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
569 if (api_nhg.backup_nexthop_num >= MULTIPATH_NUM) {
570 zlog_warn(
571 "%s: number of backup nexthops greater than max multipath size, truncating",
572 __func__);
573 break;
574 }
575
576 /* Unresolved nexthop: will be rejected by zebra.
577 * That causes a problem, since the primary nexthops
578 * rely on array indexing into the backup nexthops. If
579 * that array isn't valid, the backup indexes won't be
580 * valid.
581 */
582 if (nh->ifindex == 0) {
583 zlog_debug("%s: nhg %u: invalid backup nexthop",
584 __func__, id);
585 is_valid = false;
586 break;
587 }
588
589 api_nh = &api_nhg.backup_nexthops
590 [api_nhg.backup_nexthop_num];
591
592 zapi_backup_nexthop_from_nexthop(api_nh, nh);
593 api_nhg.backup_nexthop_num++;
594 }
595 }
596
597 done:
598 if (is_valid)
599 zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
600 }
601
602 void nhg_del(uint32_t id)
603 {
604 struct zapi_nhg api_nhg = {};
605
606 api_nhg.id = id;
607
608 zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
609 }
610
611 void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import,
612 bool watch, bool connected)
613 {
614 int command;
615
616 command = ZEBRA_NEXTHOP_REGISTER;
617
618 if (!watch)
619 command = ZEBRA_NEXTHOP_UNREGISTER;
620
621 if (zclient_send_rnh(zclient, command, p, SAFI_UNICAST, connected,
622 false, vrf_id) == ZCLIENT_SEND_FAILURE)
623 zlog_warn("%s: Failure to send nexthop to zebra", __func__);
624 }
625
626 static int sharp_debug_nexthops(struct zapi_route *api)
627 {
628 int i;
629
630 if (api->nexthop_num == 0) {
631 zlog_debug(" Not installed");
632 return 0;
633 }
634
635 for (i = 0; i < api->nexthop_num; i++) {
636 struct zapi_nexthop *znh = &api->nexthops[i];
637
638 switch (znh->type) {
639 case NEXTHOP_TYPE_IPV4_IFINDEX:
640 case NEXTHOP_TYPE_IPV4:
641 zlog_debug(
642 " Nexthop %pI4, type: %d, ifindex: %d, vrf: %d, label_num: %d",
643 &znh->gate.ipv4.s_addr, znh->type, znh->ifindex,
644 znh->vrf_id, znh->label_num);
645 break;
646 case NEXTHOP_TYPE_IPV6_IFINDEX:
647 case NEXTHOP_TYPE_IPV6:
648 zlog_debug(
649 " Nexthop %pI6, type: %d, ifindex: %d, vrf: %d, label_num: %d",
650 &znh->gate.ipv6, znh->type, znh->ifindex,
651 znh->vrf_id, znh->label_num);
652 break;
653 case NEXTHOP_TYPE_IFINDEX:
654 zlog_debug(" Nexthop IFINDEX: %d, ifindex: %d",
655 znh->type, znh->ifindex);
656 break;
657 case NEXTHOP_TYPE_BLACKHOLE:
658 zlog_debug(" Nexthop blackhole");
659 break;
660 }
661 }
662
663 return i;
664 }
665 static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
666 {
667 struct sharp_nh_tracker *nht;
668 struct zapi_route nhr;
669 struct prefix matched;
670
671 if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) {
672 zlog_err("%s: Decode of update failed", __func__);
673 return 0;
674 }
675
676 zlog_debug("Received update for %pFX actual match: %pFX metric: %u",
677 &matched, &nhr.prefix, nhr.metric);
678
679 nht = sharp_nh_tracker_get(&matched);
680 nht->nhop_num = nhr.nexthop_num;
681 nht->updates++;
682
683 sharp_debug_nexthops(&nhr);
684
685 return 0;
686 }
687
688 static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS)
689 {
690 struct zapi_route api;
691
692 if (zapi_route_decode(zclient->ibuf, &api) < 0)
693 zlog_warn("%s: Decode of redistribute failed: %d", __func__,
694 ZEBRA_REDISTRIBUTE_ROUTE_ADD);
695
696 zlog_debug("%s: %pFX (%s)", zserv_command_string(cmd), &api.prefix,
697 zebra_route_string(api.type));
698
699 sharp_debug_nexthops(&api);
700
701 return 0;
702 }
703
704 void sharp_redistribute_vrf(struct vrf *vrf, int type)
705 {
706 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type,
707 0, vrf->vrf_id);
708 }
709
710 static zclient_handler *const sharp_opaque_handlers[] = {
711 [ZEBRA_OPAQUE_MESSAGE] = sharp_opaque_handler,
712 };
713
714 /* Add a zclient with a specified session id, for testing. */
715 int sharp_zclient_create(uint32_t session_id)
716 {
717 struct zclient *client;
718 struct sharp_zclient *node;
719
720 /* Check for duplicates */
721 for (node = sharp_clients_head; node != NULL; node = node->next) {
722 if (node->client->session_id == session_id)
723 return -1;
724 }
725
726 client = zclient_new(master, &zclient_options_default,
727 sharp_opaque_handlers,
728 array_size(sharp_opaque_handlers));
729 client->sock = -1;
730 client->session_id = session_id;
731
732 zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs);
733
734 /* Enqueue on the list of test clients */
735 add_zclient(client);
736
737 return 0;
738 }
739
740 /* Delete one of the extra test zclients */
741 int sharp_zclient_delete(uint32_t session_id)
742 {
743 struct sharp_zclient *node;
744
745 /* Search for session */
746 for (node = sharp_clients_head; node != NULL; node = node->next) {
747 if (node->client->session_id == session_id) {
748 /* Dequeue from list */
749 if (node->next)
750 node->next->prev = node->prev;
751 if (node->prev)
752 node->prev->next = node->next;
753 if (node == sharp_clients_head)
754 sharp_clients_head = node->next;
755
756 /* Clean up zclient */
757 zclient_stop(node->client);
758 zclient_free(node->client);
759
760 /* Free memory */
761 XFREE(MTYPE_ZC, node);
762 break;
763 }
764 }
765
766 return 0;
767 }
768
769 static const char *const type2txt[] = {"Generic", "Vertex", "Edge", "Subnet"};
770 static const char *const status2txt[] = {"Unknown", "New", "Update",
771 "Delete", "Sync", "Orphan"};
772 /* Handler for opaque messages */
773 static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS)
774 {
775 struct stream *s;
776 struct zapi_opaque_msg info;
777 struct ls_element *lse;
778
779 s = zclient->ibuf;
780
781 if (zclient_opaque_decode(s, &info) != 0)
782 return -1;
783
784 zlog_debug("%s: [%u] received opaque type %u", __func__,
785 zclient->session_id, info.type);
786
787 if (info.type == LINK_STATE_UPDATE) {
788 lse = ls_stream2ted(sg.ted, s, false);
789 if (lse) {
790 zlog_debug(" |- Got %s %s from Link State Database",
791 status2txt[lse->status],
792 type2txt[lse->type]);
793 lse->status = SYNC;
794 } else
795 zlog_debug(
796 "%s: Error to convert Stream into Link State",
797 __func__);
798 }
799
800 return 0;
801 }
802
803 /*
804 * Send OPAQUE messages, using subtype 'type'.
805 */
806 void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance,
807 uint32_t session_id, uint32_t count)
808 {
809 uint8_t buf[32];
810 int ret;
811 uint32_t i;
812
813 /* Prepare a small payload */
814 for (i = 0; i < sizeof(buf); i++) {
815 if (type < 255)
816 buf[i] = type;
817 else
818 buf[i] = 255;
819 }
820
821 /* Send some messages - broadcast and unicast are supported */
822 for (i = 0; i < count; i++) {
823 if (proto == 0)
824 ret = zclient_send_opaque(zclient, type, buf,
825 sizeof(buf));
826 else
827 ret = zclient_send_opaque_unicast(zclient, type, proto,
828 instance, session_id,
829 buf, sizeof(buf));
830 if (ret == ZCLIENT_SEND_FAILURE) {
831 zlog_debug("%s: send_opaque() failed => %d", __func__,
832 ret);
833 break;
834 }
835 }
836 }
837
838 /*
839 * Send OPAQUE registration messages, using subtype 'type'.
840 */
841 void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance,
842 uint32_t session_id, uint32_t type)
843 {
844 struct stream *s;
845
846 s = zclient->obuf;
847 stream_reset(s);
848
849 if (is_reg)
850 zclient_create_header(s, ZEBRA_OPAQUE_REGISTER, VRF_DEFAULT);
851 else
852 zclient_create_header(s, ZEBRA_OPAQUE_UNREGISTER, VRF_DEFAULT);
853
854 /* Send sub-type */
855 stream_putl(s, type);
856
857 /* Add zclient info */
858 stream_putc(s, proto);
859 stream_putw(s, instance);
860 stream_putl(s, session_id);
861
862 /* Put length at the first point of the stream. */
863 stream_putw_at(s, 0, stream_get_endp(s));
864
865 (void)zclient_send_message(zclient);
866 }
867
868 /* Link State registration */
869 void sharp_zebra_register_te(void)
870 {
871 /* First register to received Link State Update messages */
872 zclient_register_opaque(zclient, LINK_STATE_UPDATE);
873
874 /* Then, request initial TED with SYNC message */
875 ls_request_sync(zclient);
876 }
877
878 void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
879 {
880 zclient_send_neigh_discovery_req(zclient, ifp, p);
881 }
882
883 static int nhg_notify_owner(ZAPI_CALLBACK_ARGS)
884 {
885 enum zapi_nhg_notify_owner note;
886 uint32_t id;
887
888 if (!zapi_nhg_notify_decode(zclient->ibuf, &id, &note))
889 return -1;
890
891 switch (note) {
892 case ZAPI_NHG_INSTALLED:
893 sharp_nhgroup_id_set_installed(id, true);
894 zlog_debug("Installed nhg %u", id);
895 break;
896 case ZAPI_NHG_FAIL_INSTALL:
897 zlog_debug("Failed install of nhg %u", id);
898 break;
899 case ZAPI_NHG_REMOVED:
900 zlog_debug("Removed nhg %u", id);
901 break;
902 case ZAPI_NHG_REMOVE_FAIL:
903 zlog_debug("Failed removal of nhg %u", id);
904 break;
905 }
906
907 return 0;
908 }
909
910 int sharp_zebra_srv6_manager_get_locator_chunk(const char *locator_name)
911 {
912 return srv6_manager_get_locator_chunk(zclient, locator_name);
913 }
914
915 int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name)
916 {
917 return srv6_manager_release_locator_chunk(zclient, locator_name);
918 }
919
920 static int sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
921 {
922 struct stream *s = NULL;
923 struct srv6_locator_chunk s6c = {};
924 struct listnode *node, *nnode;
925 struct sharp_srv6_locator *loc;
926
927 s = zclient->ibuf;
928 zapi_srv6_locator_chunk_decode(s, &s6c);
929
930 for (ALL_LIST_ELEMENTS(sg.srv6_locators, node, nnode, loc)) {
931 struct prefix_ipv6 *chunk = NULL;
932 struct listnode *chunk_node;
933 struct prefix_ipv6 *c;
934
935 if (strcmp(loc->name, s6c.locator_name) != 0) {
936 zlog_err("%s: Locator name unmatch %s:%s", __func__,
937 loc->name, s6c.locator_name);
938 continue;
939 }
940
941 for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c))
942 if (!prefix_cmp(c, &s6c.prefix))
943 return 0;
944
945 chunk = prefix_ipv6_new();
946 *chunk = s6c.prefix;
947 listnode_add(loc->chunks, chunk);
948 return 0;
949 }
950
951 zlog_err("%s: can't get locator_chunk!!", __func__);
952 return 0;
953 }
954
955 int sharp_zebra_send_interface_protodown(struct interface *ifp, bool down)
956 {
957 zlog_debug("Sending zebra to set %s protodown %s", ifp->name,
958 down ? "on" : "off");
959
960 if (zclient_send_interface_protodown(zclient, ifp->vrf->vrf_id, ifp,
961 down) == ZCLIENT_SEND_FAILURE)
962 return -1;
963
964 return 0;
965 }
966
967 int sharp_zebra_send_tc_filter_rate(struct interface *ifp,
968 const struct prefix *source,
969 const struct prefix *destination,
970 uint8_t ip_proto, uint16_t src_port,
971 uint16_t dst_port, uint64_t rate)
972 {
973 #define SHARPD_TC_HANDLE 0x0001
974 struct stream *s;
975
976 s = zclient->obuf;
977
978 struct tc_qdisc q = {.ifindex = ifp->ifindex, .kind = TC_QDISC_HTB};
979
980 zapi_tc_qdisc_encode(ZEBRA_TC_QDISC_INSTALL, s, &q);
981 if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
982 return -1;
983
984 struct tc_class c = {.ifindex = ifp->ifindex,
985 .handle = SHARPD_TC_HANDLE & 0xffff,
986 .kind = TC_QDISC_HTB,
987 .u.htb.ceil = rate,
988 .u.htb.rate = rate};
989
990 zapi_tc_class_encode(ZEBRA_TC_CLASS_ADD, s, &c);
991 if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
992 return -1;
993
994 struct tc_filter f = {.ifindex = ifp->ifindex,
995 .handle = SHARPD_TC_HANDLE,
996 .priority = 0x1,
997 .kind = TC_FILTER_FLOWER,
998 .u.flower.filter_bm = 0};
999
1000 #ifdef ETH_P_IP
1001 f.protocol = ETH_P_IP;
1002 #else
1003 f.protocol = 0x0800;
1004 #endif
1005
1006 f.u.flower.filter_bm |= TC_FLOWER_IP_PROTOCOL;
1007 f.u.flower.ip_proto = ip_proto;
1008 f.u.flower.filter_bm |= TC_FLOWER_SRC_IP;
1009 prefix_copy(&f.u.flower.src_ip, source);
1010 f.u.flower.filter_bm |= TC_FLOWER_DST_IP;
1011 prefix_copy(&f.u.flower.dst_ip, destination);
1012 f.u.flower.filter_bm |= TC_FLOWER_SRC_PORT;
1013 f.u.flower.src_port_min = f.u.flower.src_port_max = src_port;
1014 f.u.flower.filter_bm |= TC_FLOWER_DST_PORT;
1015 f.u.flower.dst_port_min = f.u.flower.dst_port_max = dst_port;
1016 f.u.flower.classid = SHARPD_TC_HANDLE & 0xffff;
1017
1018 zapi_tc_filter_encode(ZEBRA_TC_FILTER_ADD, s, &f);
1019 if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE)
1020 return -1;
1021
1022 return 0;
1023 }
1024
1025 static zclient_handler *const sharp_handlers[] = {
1026 [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
1027 [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
1028 [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner,
1029 [ZEBRA_NEXTHOP_UPDATE] = sharp_nexthop_update,
1030 [ZEBRA_NHG_NOTIFY_OWNER] = nhg_notify_owner,
1031 [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = sharp_redistribute_route,
1032 [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = sharp_redistribute_route,
1033 [ZEBRA_OPAQUE_MESSAGE] = sharp_opaque_handler,
1034 [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
1035 sharp_zebra_process_srv6_locator_chunk,
1036 };
1037
1038 void sharp_zebra_init(void)
1039 {
1040 struct zclient_options opt = {.receive_notify = true};
1041
1042 if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, sharp_ifp_down,
1043 sharp_ifp_destroy);
1044
1045 zclient = zclient_new(master, &opt, sharp_handlers,
1046 array_size(sharp_handlers));
1047
1048 zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs);
1049 zclient->zebra_connected = zebra_connected;
1050 zclient->zebra_buffer_write_ready = sharp_zclient_buffer_ready;
1051 }