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