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