]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_mlag.c
zebra: print unknown rule family as number
[mirror_frr.git] / zebra / zebra_mlag.c
CommitLineData
df395600 1/* Zebra Mlag Code.
6a597223 2 * Copyright (C) 2018 Cumulus Networks, Inc.
df395600
DS
3 * Donald Sharp
4 *
5 * This file is part of FRR.
6 *
7 * FRR is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * FRR is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with FRR; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22#include "zebra.h"
23
763ec244 24#include "command.h"
df395600 25#include "hook.h"
ee235396
SK
26#include "frr_pthread.h"
27#include "mlag.h"
df395600
DS
28
29#include "zebra/zebra_mlag.h"
fd193241 30#include "zebra/zebra_mlag_vty.h"
e96ba9da 31#include "zebra/zebra_router.h"
ee235396 32#include "zebra/zebra_memory.h"
b120fe3b
DS
33#include "zebra/zapi_msg.h"
34#include "zebra/debug.h"
df395600 35
d621815a
DL
36DEFINE_HOOK(zebra_mlag_private_write_data,
37 (uint8_t *data, uint32_t len), (data, len))
38DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ())
39DEFINE_HOOK(zebra_mlag_private_open_channel, (), ())
40DEFINE_HOOK(zebra_mlag_private_close_channel, (), ())
41DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ())
42
ee235396
SK
43#define ZEBRA_MLAG_METADATA_LEN 4
44#define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
45
46uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT];
47uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT];
48uint32_t mlag_rd_buf_offset;
49
50static bool test_mlag_in_progress;
51
52static int zebra_mlag_signal_write_thread(void);
53static int zebra_mlag_terminate_pthread(struct thread *event);
54static int zebra_mlag_post_data_from_main_thread(struct thread *thread);
55static void zebra_mlag_publish_process_state(struct zserv *client,
56 zebra_message_types_t msg_type);
57
58/**********************MLAG Interaction***************************************/
59
60/*
61 * API to post the Registration to MLAGD
62 * MLAG will not process any messages with out the registration
63 */
64void zebra_mlag_send_register(void)
65{
66 struct stream *s = NULL;
67
68 s = stream_new(sizeof(struct mlag_msg));
69
70 stream_putl(s, MLAG_REGISTER);
71 stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
72 stream_putw(s, MLAG_MSG_NO_BATCH);
73 stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s);
74 zebra_mlag_signal_write_thread();
75
76 if (IS_ZEBRA_DEBUG_MLAG)
77 zlog_debug("%s: Enqueued MLAG Register to MLAG Thread ",
78 __func__);
79}
80
81/*
82 * API to post the De-Registration to MLAGD
83 * MLAG will not process any messages after the de-registration
84 */
85void zebra_mlag_send_deregister(void)
86{
87 struct stream *s = NULL;
88
89 s = stream_new(sizeof(struct mlag_msg));
90
91 stream_putl(s, MLAG_DEREGISTER);
92 stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
93 stream_putw(s, MLAG_MSG_NO_BATCH);
94 stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, s);
95 zebra_mlag_signal_write_thread();
96
97 if (IS_ZEBRA_DEBUG_MLAG)
98 zlog_debug("%s: Enqueued MLAG De-Register to MLAG Thread ",
99 __func__);
100}
101
102/*
103 * API To handle MLAG Received data
104 * Decodes the data using protobuf and enqueue to main thread
105 * main thread publish this to clients based on client subscription
106 */
107void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len)
108{
109 struct stream *s = NULL;
110 struct stream *s1 = NULL;
111 int msg_type = 0;
112
113 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
67fa73f2 114 msg_type = zebra_mlag_protobuf_decode_message(s, data, len);
ee235396
SK
115
116 if (msg_type <= 0) {
117 /* Something went wrong in decoding */
118 stream_free(s);
119 zlog_err("%s: failed to process mlag data-%d, %u", __func__,
120 msg_type, len);
121 return;
122 }
123
124 /*
125 * additional four bytes are for message type
126 */
127 s1 = stream_new(stream_get_endp(s) + ZEBRA_MLAG_METADATA_LEN);
128 stream_putl(s1, msg_type);
129 stream_put(s1, s->data, stream_get_endp(s));
130 thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread,
131 s1, 0, NULL);
132 stream_free(s);
133}
134
135/**********************End of MLAG Interaction********************************/
136
137/************************MLAG Thread Processing*******************************/
138
139/*
140 * after posting every 'ZEBRA_MLAG_POST_LIMIT' packets, MLAG Thread will be
141 * yielded to give CPU for other threads
142 */
143#define ZEBRA_MLAG_POST_LIMIT 100
144
145/*
146 * This thread reads the clients data from the Global queue and encodes with
147 * protobuf and pass on to the MLAG socket.
148 */
149static int zebra_mlag_client_msg_handler(struct thread *event)
150{
151 struct stream *s;
152 uint32_t wr_count = 0;
153 uint32_t msg_type = 0;
67fa73f2 154 uint32_t max_count = 0;
ee235396
SK
155 int len = 0;
156
157 wr_count = stream_fifo_count_safe(zrouter.mlag_info.mlag_fifo);
158 if (IS_ZEBRA_DEBUG_MLAG)
1e76492b 159 zlog_debug(":%s: Processing MLAG write, %u messages in queue",
ee235396
SK
160 __func__, wr_count);
161
67fa73f2 162 max_count = MIN(wr_count, ZEBRA_MLAG_POST_LIMIT);
ee235396 163
67fa73f2 164 for (wr_count = 0; wr_count < max_count; wr_count++) {
ee235396
SK
165 s = stream_fifo_pop_safe(zrouter.mlag_info.mlag_fifo);
166 if (!s) {
167 zlog_debug(":%s: Got a NULL Messages, some thing wrong",
168 __func__);
169 break;
170 }
171
ee235396
SK
172 /*
173 * Encode the data now
174 */
175 len = zebra_mlag_protobuf_encode_client_data(s, &msg_type);
176
177 /*
178 * write to MCLAGD
179 */
67fa73f2 180 if (len > 0) {
d621815a
DL
181 hook_call(zebra_mlag_private_write_data,
182 mlag_wr_buffer, len);
ee235396 183
67fa73f2
SK
184 /*
185 * If message type is De-register, send a signal to main
186 * thread, so that necessary cleanup will be done by
187 * main thread.
188 */
189 if (msg_type == MLAG_DEREGISTER) {
190 thread_add_event(zrouter.master,
191 zebra_mlag_terminate_pthread,
192 NULL, 0, NULL);
193 }
ee235396
SK
194 }
195
196 stream_free(s);
197 }
198
199 if (IS_ZEBRA_DEBUG_MLAG)
200 zlog_debug(":%s: Posted %d messages to MLAGD", __func__,
201 wr_count);
202 /*
203 * Currently there is only message write task is enqueued to this
204 * thread, yielding was added for future purpose, so that this thread
205 * can server other tasks also and in case FIFO is empty, this task will
206 * be schedule when main thread adds some messages
207 */
208 if (wr_count >= ZEBRA_MLAG_POST_LIMIT)
209 zebra_mlag_signal_write_thread();
210 return 0;
211}
212
213/*
214 * API to handle the process state.
215 * In case of Down, Zebra keep monitoring the MLAG state.
216 * all the state Notifications will be published to clients
217 */
218void zebra_mlag_handle_process_state(enum zebra_mlag_state state)
219{
220 if (state == MLAG_UP) {
221 zrouter.mlag_info.connected = true;
222 zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_UP);
223 zebra_mlag_send_register();
224 } else if (state == MLAG_DOWN) {
225 zrouter.mlag_info.connected = false;
226 zebra_mlag_publish_process_state(NULL, ZEBRA_MLAG_PROCESS_DOWN);
d621815a 227 hook_call(zebra_mlag_private_monitor_state);
ee235396
SK
228 }
229}
230
231/***********************End of MLAG Thread processing*************************/
232
233/*************************Multi-entratnt Api's********************************/
234
235/*
236 * Provider api to signal that work/events are available
237 * for the Zebra MLAG Write pthread.
238 * This API is called from 2 pthreads..
239 * 1) by main thread when client posts a MLAG Message
240 * 2) by MLAG Thread, in case of yield
241 * though this api, is called from two threads we don't need any locking
242 * because Thread task enqueue is thread safe means internally it had
243 * necessary protection
244 */
245static int zebra_mlag_signal_write_thread(void)
246{
1e76492b
SK
247 if (IS_ZEBRA_DEBUG_MLAG)
248 zlog_debug(":%s: Scheduling MLAG write", __func__);
249 /*
250 * This api will be called from Both main & MLAG Threads.
251 * main thread writes, "zrouter.mlag_info.th_master" only
252 * during Zebra Init/after MLAG thread is destroyed.
253 * so it is safe to use without any locking
254 */
255 thread_add_event(zrouter.mlag_info.th_master,
256 zebra_mlag_client_msg_handler, NULL, 0,
257 &zrouter.mlag_info.t_write);
ee235396
SK
258 return 0;
259}
260
261/*
262 * API will be used to publish the MLAG state to interested clients
263 * In case client is passed, state is posted only for that client,
264 * otherwise to all interested clients
265 * this api can be called from two threads.
266 * 1) from main thread: when client is passed
267 * 2) from MLAG Thread: when client is NULL
268 *
269 * In second case, to avoid global data access data will be post to Main
270 * thread, so that actual posting to clients will happen from Main thread.
271 */
272static void zebra_mlag_publish_process_state(struct zserv *client,
273 zebra_message_types_t msg_type)
274{
275 struct stream *s;
276
277 if (IS_ZEBRA_DEBUG_MLAG)
278 zlog_debug("%s: Publishing MLAG process state:%s to %s Client",
279 __func__,
280 (msg_type == ZEBRA_MLAG_PROCESS_UP) ? "UP" : "DOWN",
281 (client) ? "one" : "all");
282
283 if (client) {
284 s = stream_new(ZEBRA_HEADER_SIZE);
285 zclient_create_header(s, msg_type, VRF_DEFAULT);
286 zserv_send_message(client, s);
287 return;
288 }
289
290
291 /*
292 * additional four bytes are for mesasge type
293 */
294 s = stream_new(ZEBRA_HEADER_SIZE + ZEBRA_MLAG_METADATA_LEN);
295 stream_putl(s, ZEBRA_MLAG_MSG_BCAST);
296 zclient_create_header(s, msg_type, VRF_DEFAULT);
297 thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread,
298 s, 0, NULL);
299}
300
301/**************************End of Multi-entrant Apis**************************/
302
303/***********************Zebra Main thread processing**************************/
304
305/*
306 * To avoid data corruption, messages will be post to clients only from
307 * main thread, because for that access was needed for clients list.
308 * so instead of forcing the locks, messages will be posted from main thread.
309 */
310static int zebra_mlag_post_data_from_main_thread(struct thread *thread)
311{
312 struct stream *s = THREAD_ARG(thread);
313 struct stream *zebra_s = NULL;
314 struct listnode *node;
315 struct zserv *client;
316 uint32_t msg_type = 0;
317 uint32_t msg_len = 0;
318
319 if (!s)
320 return -1;
321
322 STREAM_GETL(s, msg_type);
323 if (IS_ZEBRA_DEBUG_MLAG)
324 zlog_debug(
325 "%s: Posting MLAG data for msg_type:0x%x to interested cleints",
326 __func__, msg_type);
327
328 msg_len = s->endp - ZEBRA_MLAG_METADATA_LEN;
329 for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
330 if (client->mlag_updates_interested == true) {
331 if (msg_type != ZEBRA_MLAG_MSG_BCAST
332 && !CHECK_FLAG(client->mlag_reg_mask1,
333 (1 << msg_type))) {
334 continue;
335 }
336
337 if (IS_ZEBRA_DEBUG_MLAG)
338 zlog_debug(
339 "%s: Posting MLAG data of length-%d to client:%d ",
340 __func__, msg_len, client->proto);
341
342 zebra_s = stream_new(msg_len);
343 STREAM_GET(zebra_s->data, s, msg_len);
344 zebra_s->endp = msg_len;
345 stream_putw_at(zebra_s, 0, msg_len);
346
347 /*
348 * This stream will be enqueued to client_obuf, it will
349 * be freed after posting to client socket.
350 */
351 zserv_send_message(client, zebra_s);
352 zebra_s = NULL;
353 }
354 }
355
356 stream_free(s);
357 return 0;
358stream_failure:
359 stream_free(s);
360 if (zebra_s)
361 stream_free(zebra_s);
362 return 0;
363}
364
365/*
366 * Start the MLAG Thread, this will be used to write client data on to
367 * MLAG Process and to read the data from MLAG and post to cleints.
368 * when all clients are un-registered, this Thread will be
369 * suspended.
370 */
371static void zebra_mlag_spawn_pthread(void)
372{
373 /* Start MLAG write pthread */
374
375 struct frr_pthread_attr pattr = {.start =
376 frr_pthread_attr_default.start,
377 .stop = frr_pthread_attr_default.stop};
378
379 zrouter.mlag_info.zebra_pth_mlag =
380 frr_pthread_new(&pattr, "Zebra MLAG thread", "Zebra MLAG");
381
382 zrouter.mlag_info.th_master = zrouter.mlag_info.zebra_pth_mlag->master;
383
384
67fa73f2 385 /* Enqueue an initial event to the Newly spawn MLAG pthread */
ee235396
SK
386 zebra_mlag_signal_write_thread();
387
388 frr_pthread_run(zrouter.mlag_info.zebra_pth_mlag, NULL);
389}
390
391/*
392 * all clients are un-registered for MLAG Updates, terminate the
393 * MLAG write thread
394 */
395static int zebra_mlag_terminate_pthread(struct thread *event)
396{
397 if (IS_ZEBRA_DEBUG_MLAG)
398 zlog_debug("Zebra MLAG write thread terminate called");
399
400 if (zrouter.mlag_info.clients_interested_cnt) {
401 if (IS_ZEBRA_DEBUG_MLAG)
402 zlog_debug(
403 "Zebra MLAG: still some clients are interested");
404 return 0;
405 }
406
407 frr_pthread_stop(zrouter.mlag_info.zebra_pth_mlag, NULL);
408
409 /* Destroy pthread */
410 frr_pthread_destroy(zrouter.mlag_info.zebra_pth_mlag);
411 zrouter.mlag_info.zebra_pth_mlag = NULL;
412 zrouter.mlag_info.th_master = NULL;
413 zrouter.mlag_info.t_read = NULL;
414 zrouter.mlag_info.t_write = NULL;
415
416 /*
417 * Send Notification to clean private data
418 */
d621815a 419 hook_call(zebra_mlag_private_cleanup_data);
ee235396
SK
420 return 0;
421}
422
423/*
424 * API to register zebra client for MLAG Updates
425 */
426void zebra_mlag_client_register(ZAPI_HANDLER_ARGS)
427{
428 struct stream *s;
429 uint32_t reg_mask = 0;
430 int rc = 0;
431
432 if (IS_ZEBRA_DEBUG_MLAG)
433 zlog_debug("Received MLAG Registration from client-proto:%d",
434 client->proto);
435
436
437 /* Get input stream. */
438 s = msg;
439
440 /* Get data. */
441 STREAM_GETL(s, reg_mask);
442
443 if (client->mlag_updates_interested == true) {
444
445 if (IS_ZEBRA_DEBUG_MLAG)
446 zlog_debug(
447 "Client is registered, existing mask: 0x%x, new mask: 0x%x",
448 client->mlag_reg_mask1, reg_mask);
449 if (client->mlag_reg_mask1 != reg_mask)
450 client->mlag_reg_mask1 = reg_mask;
451 /*
452 * Client might missed MLAG-UP Notification, post-it again
453 */
454 zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP);
455 return;
456 }
457
458
459 client->mlag_updates_interested = true;
460 client->mlag_reg_mask1 = reg_mask;
461 if (IS_ZEBRA_DEBUG_MLAG)
462 zlog_debug("Registering for MLAG Updates with mask: 0x%x, ",
463 client->mlag_reg_mask1);
464
465 zrouter.mlag_info.clients_interested_cnt++;
466
467 if (zrouter.mlag_info.clients_interested_cnt == 1) {
468 /*
469 * First-client for MLAG Updates,open the communication channel
470 * with MLAG
471 */
472 if (IS_ZEBRA_DEBUG_MLAG)
473 zlog_debug(
474 "First client, opening the channel with MLAG");
475
476 zebra_mlag_spawn_pthread();
d621815a 477 rc = hook_call(zebra_mlag_private_open_channel);
ee235396
SK
478 if (rc < 0) {
479 /*
480 * For some reason, zebra not able to open the
481 * comm-channel with MLAG, so post MLAG-DOWN to client.
482 * later when the channel is open, zebra will send
483 * MLAG-UP
484 */
485 if (IS_ZEBRA_DEBUG_MLAG)
486 zlog_debug(
487 "Fail to open channel with MLAG,rc:%d, post Proto-down",
488 rc);
489 zebra_mlag_publish_process_state(
490 client, ZEBRA_MLAG_PROCESS_DOWN);
491 }
492 }
493
494 if (IS_ZEBRA_DEBUG_MLAG)
495 zlog_debug("Client Registered successfully for MLAG Updates");
496
497 if (zrouter.mlag_info.connected == true)
498 zebra_mlag_publish_process_state(client, ZEBRA_MLAG_PROCESS_UP);
499stream_failure:
500 return;
501}
502
503/*
504 * API to un-register for MLAG Updates
505 */
506void zebra_mlag_client_unregister(ZAPI_HANDLER_ARGS)
507{
508 if (IS_ZEBRA_DEBUG_MLAG)
509 zlog_debug("Received MLAG De-Registration from client-proto:%d",
510 client->proto);
511
512 if (client->mlag_updates_interested == false)
513 /* Unexpected */
514 return;
515
516 client->mlag_updates_interested = false;
517 client->mlag_reg_mask1 = 0;
518 zrouter.mlag_info.clients_interested_cnt--;
519
520 if (zrouter.mlag_info.clients_interested_cnt == 0) {
521 /*
522 * No-client is interested for MLAG Updates,close the
523 * communication channel with MLAG
524 */
525 if (IS_ZEBRA_DEBUG_MLAG)
526 zlog_debug("Last client for MLAG, close the channel ");
527
528 /*
529 * Clean up flow:
530 * =============
531 * 1) main thread calls socket close which posts De-register
532 * to MLAG write thread
533 * 2) after MLAG write thread posts De-register it sends a
534 * signal back to main thread to do the thread cleanup
535 * this was mainly to make sure De-register is posted to MCLAGD.
536 */
d621815a 537 hook_call(zebra_mlag_private_close_channel);
ee235396
SK
538 }
539
540 if (IS_ZEBRA_DEBUG_MLAG)
541 zlog_debug(
542 "Client De-Registered successfully for MLAG Updates");
543}
544
545/*
546 * Does following things.
547 * 1) allocated new local stream, and copies the client data and enqueue
548 * to MLAG Thread
549 * 2) MLAG Thread after dequeing, encode the client data using protobuf
550 * and write on to MLAG
551 */
552void zebra_mlag_forward_client_msg(ZAPI_HANDLER_ARGS)
553{
554 struct stream *zebra_s;
555 struct stream *mlag_s;
556
557 if (IS_ZEBRA_DEBUG_MLAG)
558 zlog_debug("Received Client MLAG Data from client-proto:%d",
559 client->proto);
560
561 /* Get input stream. */
562 zebra_s = msg;
563 mlag_s = stream_new(zebra_s->endp);
564
565 /*
566 * Client data is | Zebra Header + MLAG Data |
567 * we need to enqueue only the MLAG data, skipping Zebra Header
568 */
569 stream_put(mlag_s, zebra_s->data + zebra_s->getp,
570 STREAM_READABLE(zebra_s));
571 stream_fifo_push_safe(zrouter.mlag_info.mlag_fifo, mlag_s);
572 zebra_mlag_signal_write_thread();
573
574 if (IS_ZEBRA_DEBUG_MLAG)
575 zlog_debug("%s: Enqueued Client:%d data to MLAG Thread ",
576 __func__, client->proto);
577}
578
579/***********************End of Zebra Main thread processing*************/
580
ff1fb8d5
DS
581enum mlag_role zebra_mlag_get_role(void)
582{
e96ba9da 583 return zrouter.mlag_info.role;
ff1fb8d5
DS
584}
585
14d9bbbe
DS
586int32_t zebra_mlag_test_mlag_internal(const char *none, const char *primary,
587 const char *secondary)
763ec244 588{
b120fe3b 589 enum mlag_role orig = zrouter.mlag_info.role;
67fa73f2 590 char buf1[MLAG_ROLE_STRSIZE], buf2[MLAG_ROLE_STRSIZE];
b120fe3b 591
763ec244 592 if (none)
e96ba9da 593 zrouter.mlag_info.role = MLAG_ROLE_NONE;
763ec244 594 if (primary)
e96ba9da 595 zrouter.mlag_info.role = MLAG_ROLE_PRIMARY;
763ec244 596 if (secondary)
e96ba9da 597 zrouter.mlag_info.role = MLAG_ROLE_SECONDARY;
763ec244 598
b120fe3b
DS
599 if (IS_ZEBRA_DEBUG_MLAG)
600 zlog_debug("Test: Changing role from %s to %s",
601 mlag_role2str(orig, buf1, sizeof(buf1)),
602 mlag_role2str(orig, buf2, sizeof(buf2)));
603
ee235396 604 if (orig != zrouter.mlag_info.role) {
b120fe3b 605 zsend_capabilities_all_clients();
ee235396
SK
606 if (zrouter.mlag_info.role != MLAG_ROLE_NONE) {
607 if (zrouter.mlag_info.clients_interested_cnt == 0
608 && test_mlag_in_progress == false) {
1e76492b
SK
609 if (zrouter.mlag_info.zebra_pth_mlag == NULL)
610 zebra_mlag_spawn_pthread();
ee235396
SK
611 zrouter.mlag_info.clients_interested_cnt++;
612 test_mlag_in_progress = true;
d621815a 613 hook_call(zebra_mlag_private_open_channel);
ee235396
SK
614 }
615 } else {
616 if (test_mlag_in_progress == true) {
617 test_mlag_in_progress = false;
618 zrouter.mlag_info.clients_interested_cnt--;
d621815a 619 hook_call(zebra_mlag_private_close_channel);
ee235396
SK
620 }
621 }
622 }
b120fe3b 623
763ec244
DS
624 return CMD_SUCCESS;
625}
626
df395600
DS
627void zebra_mlag_init(void)
628{
14d9bbbe 629 zebra_mlag_vty_init();
ee235396
SK
630
631 /*
1e76492b
SK
632 * Intialiaze the MLAG Global variables
633 * write thread will be created during actual registration with MCLAG
ee235396
SK
634 */
635 zrouter.mlag_info.clients_interested_cnt = 0;
636 zrouter.mlag_info.connected = false;
637 zrouter.mlag_info.timer_running = false;
638 zrouter.mlag_info.mlag_fifo = stream_fifo_new();
639 zrouter.mlag_info.zebra_pth_mlag = NULL;
640 zrouter.mlag_info.th_master = NULL;
641 zrouter.mlag_info.t_read = NULL;
642 zrouter.mlag_info.t_write = NULL;
643 test_mlag_in_progress = false;
ee235396 644 zebra_mlag_reset_read_buffer();
df395600
DS
645}
646
647void zebra_mlag_terminate(void)
648{
649}
ee235396
SK
650
651
652/*
653 *
654 * ProtoBuf Encoding APIs
655 */
656
fd193241 657#ifdef HAVE_PROTOBUF_VERSION_3
67fa73f2
SK
658
659DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF")
660
661int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
662{
663 ZebraMlagHeader hdr = ZEBRA_MLAG__HEADER__INIT;
664 struct mlag_msg mlag_msg;
665 uint8_t tmp_buf[ZEBRA_MLAG_BUF_LIMIT];
666 int len = 0;
667 int n_len = 0;
668 int rc = 0;
669 char buf[ZLOG_FILTER_LENGTH_MAX];
670
671 if (IS_ZEBRA_DEBUG_MLAG)
672 zlog_debug("%s: Entering..", __func__);
673
1e76492b 674 rc = mlag_lib_decode_mlag_hdr(s, &mlag_msg);
67fa73f2
SK
675 if (rc)
676 return rc;
677
678 if (IS_ZEBRA_DEBUG_MLAG)
1e76492b
SK
679 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
680 __func__,
681 mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
682 sizeof(buf)),
67fa73f2 683 mlag_msg.data_len);
67fa73f2
SK
684 *msg_type = mlag_msg.msg_type;
685 switch (mlag_msg.msg_type) {
686 case MLAG_MROUTE_ADD: {
687 struct mlag_mroute_add msg;
688 ZebraMlagMrouteAdd pay_load = ZEBRA_MLAG_MROUTE_ADD__INIT;
689 uint32_t vrf_name_len = 0;
690
1e76492b 691 rc = mlag_lib_decode_mroute_add(s, &msg);
67fa73f2
SK
692 if (rc)
693 return rc;
694 vrf_name_len = strlen(msg.vrf_name) + 1;
695 pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
696 strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len);
697 pay_load.source_ip = msg.source_ip;
698 pay_load.group_ip = msg.group_ip;
699 pay_load.cost_to_rp = msg.cost_to_rp;
700 pay_load.owner_id = msg.owner_id;
701 pay_load.am_i_dr = msg.am_i_dr;
702 pay_load.am_i_dual_active = msg.am_i_dual_active;
703 pay_load.vrf_id = msg.vrf_id;
704
705 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
706 vrf_name_len = strlen(msg.intf_name) + 1;
707 pay_load.intf_name =
708 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
709 strlcpy(pay_load.intf_name, msg.intf_name,
710 vrf_name_len);
711 }
712
713 len = zebra_mlag_mroute_add__pack(&pay_load, tmp_buf);
714 XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name);
715 if (msg.owner_id == MLAG_OWNER_INTERFACE)
716 XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name);
717 } break;
718 case MLAG_MROUTE_DEL: {
719 struct mlag_mroute_del msg;
720 ZebraMlagMrouteDel pay_load = ZEBRA_MLAG_MROUTE_DEL__INIT;
721 uint32_t vrf_name_len = 0;
722
1e76492b 723 rc = mlag_lib_decode_mroute_del(s, &msg);
67fa73f2
SK
724 if (rc)
725 return rc;
726 vrf_name_len = strlen(msg.vrf_name) + 1;
727 pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
728 strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len);
729 pay_load.source_ip = msg.source_ip;
730 pay_load.group_ip = msg.group_ip;
731 pay_load.owner_id = msg.owner_id;
732 pay_load.vrf_id = msg.vrf_id;
733
734 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
735 vrf_name_len = strlen(msg.intf_name) + 1;
736 pay_load.intf_name =
737 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
738 strlcpy(pay_load.intf_name, msg.intf_name,
739 vrf_name_len);
740 }
741
742 len = zebra_mlag_mroute_del__pack(&pay_load, tmp_buf);
743 XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name);
744 if (msg.owner_id == MLAG_OWNER_INTERFACE)
745 XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name);
746 } break;
747 case MLAG_MROUTE_ADD_BULK: {
748 struct mlag_mroute_add msg;
749 ZebraMlagMrouteAddBulk Bulk_msg =
750 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT;
751 ZebraMlagMrouteAdd **pay_load = NULL;
752 int i;
753 bool cleanup = false;
754
755 Bulk_msg.n_mroute_add = mlag_msg.msg_cnt;
756 pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteAdd *)
757 * mlag_msg.msg_cnt);
758
759 for (i = 0; i < mlag_msg.msg_cnt; i++) {
760
761 uint32_t vrf_name_len = 0;
762
1e76492b 763 rc = mlag_lib_decode_mroute_add(s, &msg);
67fa73f2
SK
764 if (rc) {
765 cleanup = true;
766 break;
767 }
768 pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF,
769 sizeof(ZebraMlagMrouteAdd));
770 zebra_mlag_mroute_add__init(pay_load[i]);
771
772 vrf_name_len = strlen(msg.vrf_name) + 1;
773 pay_load[i]->vrf_name =
774 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
775 strlcpy(pay_load[i]->vrf_name, msg.vrf_name,
776 vrf_name_len);
777 pay_load[i]->source_ip = msg.source_ip;
778 pay_load[i]->group_ip = msg.group_ip;
779 pay_load[i]->cost_to_rp = msg.cost_to_rp;
780 pay_load[i]->owner_id = msg.owner_id;
781 pay_load[i]->am_i_dr = msg.am_i_dr;
782 pay_load[i]->am_i_dual_active = msg.am_i_dual_active;
783 pay_load[i]->vrf_id = msg.vrf_id;
784 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
785 vrf_name_len = strlen(msg.intf_name) + 1;
786 pay_load[i]->intf_name =
787 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
788
789 strlcpy(pay_load[i]->intf_name, msg.intf_name,
790 vrf_name_len);
791 }
792 }
793 if (cleanup == false) {
794 Bulk_msg.mroute_add = pay_load;
795 len = zebra_mlag_mroute_add_bulk__pack(&Bulk_msg,
796 tmp_buf);
797 }
798
799 for (i = 0; i < mlag_msg.msg_cnt; i++) {
800 if (pay_load[i]->vrf_name)
801 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
802 if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
803 && pay_load[i]->intf_name)
804 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
805 if (pay_load[i])
806 XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
807 }
808 XFREE(MTYPE_MLAG_PBUF, pay_load);
809 if (cleanup == true)
810 return -1;
811 } break;
812 case MLAG_MROUTE_DEL_BULK: {
813 struct mlag_mroute_del msg;
814 ZebraMlagMrouteDelBulk Bulk_msg =
815 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT;
816 ZebraMlagMrouteDel **pay_load = NULL;
817 int i;
818 bool cleanup = false;
819
820 Bulk_msg.n_mroute_del = mlag_msg.msg_cnt;
821 pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteDel *)
822 * mlag_msg.msg_cnt);
823
824 for (i = 0; i < mlag_msg.msg_cnt; i++) {
825
826 uint32_t vrf_name_len = 0;
827
1e76492b 828 rc = mlag_lib_decode_mroute_del(s, &msg);
67fa73f2
SK
829 if (rc) {
830 cleanup = true;
831 break;
832 }
833
834 pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF,
835 sizeof(ZebraMlagMrouteDel));
836 zebra_mlag_mroute_del__init(pay_load[i]);
837
838 vrf_name_len = strlen(msg.vrf_name) + 1;
839 pay_load[i]->vrf_name =
840 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
841
842 strlcpy(pay_load[i]->vrf_name, msg.vrf_name,
843 vrf_name_len);
844 pay_load[i]->source_ip = msg.source_ip;
845 pay_load[i]->group_ip = msg.group_ip;
846 pay_load[i]->owner_id = msg.owner_id;
847 pay_load[i]->vrf_id = msg.vrf_id;
848 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
849 vrf_name_len = strlen(msg.intf_name) + 1;
850 pay_load[i]->intf_name =
851 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
852
853 strlcpy(pay_load[i]->intf_name, msg.intf_name,
854 vrf_name_len);
855 }
856 }
857 if (!cleanup) {
858 Bulk_msg.mroute_del = pay_load;
859 len = zebra_mlag_mroute_del_bulk__pack(&Bulk_msg,
860 tmp_buf);
861 }
862
863 for (i = 0; i < mlag_msg.msg_cnt; i++) {
864 if (pay_load[i]->vrf_name)
865 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
866 if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
867 && pay_load[i]->intf_name)
868 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
869 if (pay_load[i])
870 XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
871 }
872 XFREE(MTYPE_MLAG_PBUF, pay_load);
873 if (cleanup)
874 return -1;
875 } break;
876 default:
877 break;
878 }
879
880 if (IS_ZEBRA_DEBUG_MLAG)
881 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
882 __func__,
1e76492b
SK
883 mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
884 sizeof(buf)),
67fa73f2
SK
885 len);
886 hdr.type = (ZebraMlagHeader__MessageType)mlag_msg.msg_type;
887 if (len != 0) {
888 hdr.data.len = len;
889 hdr.data.data = XMALLOC(MTYPE_MLAG_PBUF, len);
890 memcpy(hdr.data.data, tmp_buf, len);
891 }
892
893 /*
894 * ProtoBuf Infra will not support to demarc the pointers whem multiple
895 * messages are posted inside a single Buffer.
896 * 2 -solutions exist to solve this
897 * 1. add Unenoced length at the beginning of every message, this will
898 * be used to point to next message in the buffer
899 * 2. another solution is defining all messages insides another message
900 * But this will permit only 32 messages. this can be extended with
901 * multiple levels.
902 * for simplicity we are going with solution-1.
903 */
904 len = zebra_mlag__header__pack(&hdr,
905 (mlag_wr_buffer + ZEBRA_MLAG_LEN_SIZE));
906 n_len = htonl(len);
907 memcpy(mlag_wr_buffer, &n_len, ZEBRA_MLAG_LEN_SIZE);
908 len += ZEBRA_MLAG_LEN_SIZE;
909
910 if (IS_ZEBRA_DEBUG_MLAG)
911 zlog_debug(
912 "%s: length of Mlag ProtoBuf message:%s with Header %d",
913 __func__,
1e76492b
SK
914 mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
915 sizeof(buf)),
67fa73f2
SK
916 len);
917 if (hdr.data.data)
918 XFREE(MTYPE_MLAG_PBUF, hdr.data.data);
919
920 return len;
921}
922
923int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
924 uint32_t len)
925{
926 uint32_t msg_type;
927 ZebraMlagHeader *hdr;
928 char buf[80];
929
930 hdr = zebra_mlag__header__unpack(NULL, len, data);
931 if (hdr == NULL)
932 return -1;
933
934 /*
935 * ADD The MLAG Header
936 */
937 zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT);
938
939 msg_type = hdr->type;
940
941 if (IS_ZEBRA_DEBUG_MLAG)
942 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__,
1e76492b 943 mlag_lib_msgid_to_str(msg_type, buf, 80));
67fa73f2
SK
944
945 /*
946 * Internal MLAG Message-types & MLAG.proto message types should
947 * always match, otherwise there can be decoding errors
948 * To avoid exposing clients with Protobuf flags, using internal
949 * message-types
950 */
951 stream_putl(s, hdr->type);
952
953 if (hdr->data.len == 0) {
954 /* NULL Payload */
955 stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
956 /* No Batching */
957 stream_putw(s, MLAG_MSG_NO_BATCH);
958 } else {
959 switch (msg_type) {
960 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE: {
961 ZebraMlagStatusUpdate *msg = NULL;
962
963 msg = zebra_mlag_status_update__unpack(
964 NULL, hdr->data.len, hdr->data.data);
965 if (msg == NULL) {
966 zebra_mlag__header__free_unpacked(hdr, NULL);
967 return -1;
968 }
969 /* Payload len */
970 stream_putw(s, sizeof(struct mlag_status));
971 /* No Batching */
972 stream_putw(s, MLAG_MSG_NO_BATCH);
973 /* Actual Data */
974 stream_put(s, msg->peerlink, INTERFACE_NAMSIZ);
975 stream_putl(s, msg->my_role);
976 stream_putl(s, msg->peer_state);
977 zebra_mlag_status_update__free_unpacked(msg, NULL);
978 } break;
979 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE: {
980 ZebraMlagVxlanUpdate *msg = NULL;
981
982 msg = zebra_mlag_vxlan_update__unpack(
983 NULL, hdr->data.len, hdr->data.data);
984 if (msg == NULL) {
985 zebra_mlag__header__free_unpacked(hdr, NULL);
986 return -1;
987 }
988 /* Payload len */
989 stream_putw(s, sizeof(struct mlag_vxlan));
990 /* No Batching */
991 stream_putw(s, MLAG_MSG_NO_BATCH);
992 /* Actual Data */
993 stream_putl(s, msg->anycast_ip);
994 stream_putl(s, msg->local_ip);
995 zebra_mlag_vxlan_update__free_unpacked(msg, NULL);
996 } break;
997 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD: {
998 ZebraMlagMrouteAdd *msg = NULL;
999
1000 msg = zebra_mlag_mroute_add__unpack(NULL, hdr->data.len,
1001 hdr->data.data);
1002 if (msg == NULL) {
1003 zebra_mlag__header__free_unpacked(hdr, NULL);
1004 return -1;
1005 }
1006 /* Payload len */
1007 stream_putw(s, sizeof(struct mlag_mroute_add));
1008 /* No Batching */
1009 stream_putw(s, MLAG_MSG_NO_BATCH);
1010 /* Actual Data */
1011 stream_put(s, msg->vrf_name, VRF_NAMSIZ);
1012
1013 stream_putl(s, msg->source_ip);
1014 stream_putl(s, msg->group_ip);
1015 stream_putl(s, msg->cost_to_rp);
1016 stream_putl(s, msg->owner_id);
1017 stream_putc(s, msg->am_i_dr);
1018 stream_putc(s, msg->am_i_dual_active);
1019 stream_putl(s, msg->vrf_id);
1020 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1021 stream_put(s, msg->intf_name, INTERFACE_NAMSIZ);
1022 else
1023 stream_put(s, NULL, INTERFACE_NAMSIZ);
1024 zebra_mlag_mroute_add__free_unpacked(msg, NULL);
1025 } break;
1026 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL: {
1027 ZebraMlagMrouteDel *msg = NULL;
1028
1029 msg = zebra_mlag_mroute_del__unpack(NULL, hdr->data.len,
1030 hdr->data.data);
1031 if (msg == NULL) {
1032 zebra_mlag__header__free_unpacked(hdr, NULL);
1033 return -1;
1034 }
1035 /* Payload len */
1036 stream_putw(s, sizeof(struct mlag_mroute_del));
1037 /* No Batching */
1038 stream_putw(s, MLAG_MSG_NO_BATCH);
1039 /* Actual Data */
1040 stream_put(s, msg->vrf_name, VRF_NAMSIZ);
1041
1042 stream_putl(s, msg->source_ip);
1043 stream_putl(s, msg->group_ip);
1044 stream_putl(s, msg->group_ip);
1045 stream_putl(s, msg->owner_id);
1046 stream_putl(s, msg->vrf_id);
1047 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1048 stream_put(s, msg->intf_name, INTERFACE_NAMSIZ);
1049 else
1050 stream_put(s, NULL, INTERFACE_NAMSIZ);
1051 zebra_mlag_mroute_del__free_unpacked(msg, NULL);
1052 } break;
1053 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: {
1054 ZebraMlagMrouteAddBulk *Bulk_msg = NULL;
1055 ZebraMlagMrouteAdd *msg = NULL;
1056 size_t i;
1057
1058 Bulk_msg = zebra_mlag_mroute_add_bulk__unpack(
1059 NULL, hdr->data.len, hdr->data.data);
1060 if (Bulk_msg == NULL) {
1061 zebra_mlag__header__free_unpacked(hdr, NULL);
1062 return -1;
1063 }
1064 /* Payload len */
1065 stream_putw(s, (Bulk_msg->n_mroute_add
1066 * sizeof(struct mlag_mroute_add)));
1067 /* No. of msgs in Batch */
1068 stream_putw(s, Bulk_msg->n_mroute_add);
1069
1070 /* Actual Data */
1071 for (i = 0; i < Bulk_msg->n_mroute_add; i++) {
1072
1073 msg = Bulk_msg->mroute_add[i];
1074
1075 stream_put(s, msg->vrf_name, VRF_NAMSIZ);
1076 stream_putl(s, msg->source_ip);
1077 stream_putl(s, msg->group_ip);
1078 stream_putl(s, msg->cost_to_rp);
1079 stream_putl(s, msg->owner_id);
1080 stream_putc(s, msg->am_i_dr);
1081 stream_putc(s, msg->am_i_dual_active);
1082 stream_putl(s, msg->vrf_id);
1083 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1084 stream_put(s, msg->intf_name,
1085 INTERFACE_NAMSIZ);
1086 else
1087 stream_put(s, NULL, INTERFACE_NAMSIZ);
1088 }
1089 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg,
1090 NULL);
1091 } break;
1092 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK: {
1093 ZebraMlagMrouteDelBulk *Bulk_msg = NULL;
1094 ZebraMlagMrouteDel *msg = NULL;
1095 size_t i;
1096
1097 Bulk_msg = zebra_mlag_mroute_del_bulk__unpack(
1098 NULL, hdr->data.len, hdr->data.data);
1099 if (Bulk_msg == NULL) {
1100 zebra_mlag__header__free_unpacked(hdr, NULL);
1101 return -1;
1102 }
1103 /* Payload len */
1104 stream_putw(s, (Bulk_msg->n_mroute_del
1105 * sizeof(struct mlag_mroute_del)));
1106 /* No. of msgs in Batch */
1107 stream_putw(s, Bulk_msg->n_mroute_del);
1108
1109 /* Actual Data */
1110 for (i = 0; i < Bulk_msg->n_mroute_del; i++) {
1111
1112 msg = Bulk_msg->mroute_del[i];
1113
1114 stream_put(s, msg->vrf_name, VRF_NAMSIZ);
1115 stream_putl(s, msg->source_ip);
1116 stream_putl(s, msg->group_ip);
1117 stream_putl(s, msg->owner_id);
1118 stream_putl(s, msg->vrf_id);
1119 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1120 stream_put(s, msg->intf_name,
1121 INTERFACE_NAMSIZ);
1122 else
1123 stream_put(s, NULL, INTERFACE_NAMSIZ);
1124 }
1125 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg,
1126 NULL);
1127 } break;
1128 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE: {
1129 ZebraMlagZebraStatusUpdate *msg = NULL;
1130
1131 msg = zebra_mlag_zebra_status_update__unpack(
1132 NULL, hdr->data.len, hdr->data.data);
1133 if (msg == NULL) {
1134 zebra_mlag__header__free_unpacked(hdr, NULL);
1135 return -1;
1136 }
1137 /* Payload len */
1138 stream_putw(s, sizeof(struct mlag_frr_status));
1139 /* No Batching */
1140 stream_putw(s, MLAG_MSG_NO_BATCH);
1141 /* Actual Data */
1142 stream_putl(s, msg->peer_frrstate);
1143 zebra_mlag_zebra_status_update__free_unpacked(msg,
1144 NULL);
1145 } break;
1146 default:
1147 break;
1148 }
1149 }
1150 zebra_mlag__header__free_unpacked(hdr, NULL);
1151 return msg_type;
1152}
1153
1154#else
ee235396
SK
1155int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
1156{
1157 return 0;
1158}
1159
67fa73f2 1160int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
ee235396
SK
1161 uint32_t len)
1162{
1163 return 0;
1164}
67fa73f2 1165#endif