]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mlag.c
Merge pull request #6811 from rgirada/test_helper
[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_mlag_vty.h"
31 #include "zebra/zebra_router.h"
32 #include "zebra/zebra_memory.h"
33 #include "zebra/zapi_msg.h"
34 #include "zebra/debug.h"
35
36 #ifdef HAVE_PROTOBUF_VERSION_3
37 #include "mlag/mlag.pb-c.h"
38 #endif
39
40 DEFINE_HOOK(zebra_mlag_private_write_data,
41 (uint8_t *data, uint32_t len), (data, len))
42 DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ())
43 DEFINE_HOOK(zebra_mlag_private_open_channel, (), ())
44 DEFINE_HOOK(zebra_mlag_private_close_channel, (), ())
45 DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ())
46
47 #define ZEBRA_MLAG_METADATA_LEN 4
48 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
49
50 uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT];
51 uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT];
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 int msg_type = 0;
114
115 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
116 /*
117 * Place holder we need the message type first
118 */
119 stream_putl(s, msg_type);
120 msg_type = zebra_mlag_protobuf_decode_message(s, data, len);
121
122 if (msg_type <= 0) {
123 /* Something went wrong in decoding */
124 stream_free(s);
125 zlog_err("%s: failed to process mlag data-%d, %u", __func__,
126 msg_type, len);
127 return;
128 }
129
130 /*
131 * additional four bytes are for message type
132 */
133 stream_putl_at(s, 0, msg_type);
134 thread_add_event(zrouter.master, zebra_mlag_post_data_from_main_thread,
135 s, 0, NULL);
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 clients",
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 clients.
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 int32_t zebra_mlag_test_mlag_internal(const char *none, const char *primary,
590 const char *secondary)
591 {
592 enum mlag_role orig = zrouter.mlag_info.role;
593 char buf1[MLAG_ROLE_STRSIZE], buf2[MLAG_ROLE_STRSIZE];
594
595 if (none)
596 zrouter.mlag_info.role = MLAG_ROLE_NONE;
597 if (primary)
598 zrouter.mlag_info.role = MLAG_ROLE_PRIMARY;
599 if (secondary)
600 zrouter.mlag_info.role = MLAG_ROLE_SECONDARY;
601
602 if (IS_ZEBRA_DEBUG_MLAG)
603 zlog_debug("Test: Changing role from %s to %s",
604 mlag_role2str(orig, buf1, sizeof(buf1)),
605 mlag_role2str(orig, buf2, sizeof(buf2)));
606
607 if (orig != zrouter.mlag_info.role) {
608 zsend_capabilities_all_clients();
609 if (zrouter.mlag_info.role != MLAG_ROLE_NONE) {
610 if (zrouter.mlag_info.clients_interested_cnt == 0
611 && !test_mlag_in_progress) {
612 if (zrouter.mlag_info.zebra_pth_mlag == NULL)
613 zebra_mlag_spawn_pthread();
614 zrouter.mlag_info.clients_interested_cnt++;
615 test_mlag_in_progress = true;
616 hook_call(zebra_mlag_private_open_channel);
617 }
618 } else {
619 if (test_mlag_in_progress) {
620 test_mlag_in_progress = false;
621 zrouter.mlag_info.clients_interested_cnt--;
622 hook_call(zebra_mlag_private_close_channel);
623 }
624 }
625 }
626
627 return CMD_SUCCESS;
628 }
629
630 void zebra_mlag_init(void)
631 {
632 zebra_mlag_vty_init();
633
634 /*
635 * Intialiaze the MLAG Global variables
636 * write thread will be created during actual registration with MCLAG
637 */
638 zrouter.mlag_info.clients_interested_cnt = 0;
639 zrouter.mlag_info.connected = false;
640 zrouter.mlag_info.timer_running = false;
641 zrouter.mlag_info.mlag_fifo = stream_fifo_new();
642 zrouter.mlag_info.zebra_pth_mlag = NULL;
643 zrouter.mlag_info.th_master = NULL;
644 zrouter.mlag_info.t_read = NULL;
645 zrouter.mlag_info.t_write = NULL;
646 test_mlag_in_progress = false;
647 zebra_mlag_reset_read_buffer();
648 }
649
650 void zebra_mlag_terminate(void)
651 {
652 }
653
654
655 /*
656 *
657 * ProtoBuf Encoding APIs
658 */
659
660 #ifdef HAVE_PROTOBUF_VERSION_3
661
662 DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF")
663
664 int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
665 {
666 ZebraMlagHeader hdr = ZEBRA_MLAG__HEADER__INIT;
667 struct mlag_msg mlag_msg;
668 uint8_t tmp_buf[ZEBRA_MLAG_BUF_LIMIT];
669 int len = 0;
670 int n_len = 0;
671 int rc = 0;
672 char buf[ZLOG_FILTER_LENGTH_MAX];
673 size_t length;
674
675 if (IS_ZEBRA_DEBUG_MLAG)
676 zlog_debug("%s: Entering..", __func__);
677
678 rc = mlag_lib_decode_mlag_hdr(s, &mlag_msg, &length);
679 if (rc)
680 return rc;
681
682 memset(tmp_buf, 0, ZEBRA_MLAG_BUF_LIMIT);
683
684 if (IS_ZEBRA_DEBUG_MLAG)
685 zlog_debug("%s: Mlag ProtoBuf encoding of message:%s, len:%d",
686 __func__,
687 mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
688 sizeof(buf)),
689 mlag_msg.data_len);
690 *msg_type = mlag_msg.msg_type;
691 switch (mlag_msg.msg_type) {
692 case MLAG_MROUTE_ADD: {
693 struct mlag_mroute_add msg;
694 ZebraMlagMrouteAdd pay_load = ZEBRA_MLAG_MROUTE_ADD__INIT;
695 uint32_t vrf_name_len = 0;
696
697 rc = mlag_lib_decode_mroute_add(s, &msg, &length);
698 if (rc)
699 return rc;
700
701 vrf_name_len = strlen(msg.vrf_name) + 1;
702 pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
703 strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len);
704 pay_load.source_ip = msg.source_ip;
705 pay_load.group_ip = msg.group_ip;
706 pay_load.cost_to_rp = msg.cost_to_rp;
707 pay_load.owner_id = msg.owner_id;
708 pay_load.am_i_dr = msg.am_i_dr;
709 pay_load.am_i_dual_active = msg.am_i_dual_active;
710 pay_load.vrf_id = msg.vrf_id;
711
712 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
713 vrf_name_len = strlen(msg.intf_name) + 1;
714 pay_load.intf_name =
715 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
716 strlcpy(pay_load.intf_name, msg.intf_name,
717 vrf_name_len);
718 }
719
720 len = zebra_mlag_mroute_add__pack(&pay_load, tmp_buf);
721 XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name);
722 if (msg.owner_id == MLAG_OWNER_INTERFACE)
723 XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name);
724 } break;
725 case MLAG_MROUTE_DEL: {
726 struct mlag_mroute_del msg;
727 ZebraMlagMrouteDel pay_load = ZEBRA_MLAG_MROUTE_DEL__INIT;
728 uint32_t vrf_name_len = 0;
729
730 rc = mlag_lib_decode_mroute_del(s, &msg, &length);
731 if (rc)
732 return rc;
733 vrf_name_len = strlen(msg.vrf_name) + 1;
734 pay_load.vrf_name = XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
735 strlcpy(pay_load.vrf_name, msg.vrf_name, vrf_name_len);
736 pay_load.source_ip = msg.source_ip;
737 pay_load.group_ip = msg.group_ip;
738 pay_load.owner_id = msg.owner_id;
739 pay_load.vrf_id = msg.vrf_id;
740
741 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
742 vrf_name_len = strlen(msg.intf_name) + 1;
743 pay_load.intf_name =
744 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
745 strlcpy(pay_load.intf_name, msg.intf_name,
746 vrf_name_len);
747 }
748
749 len = zebra_mlag_mroute_del__pack(&pay_load, tmp_buf);
750 XFREE(MTYPE_MLAG_PBUF, pay_load.vrf_name);
751 if (msg.owner_id == MLAG_OWNER_INTERFACE)
752 XFREE(MTYPE_MLAG_PBUF, pay_load.intf_name);
753 } break;
754 case MLAG_MROUTE_ADD_BULK: {
755 struct mlag_mroute_add msg;
756 ZebraMlagMrouteAddBulk Bulk_msg =
757 ZEBRA_MLAG_MROUTE_ADD_BULK__INIT;
758 ZebraMlagMrouteAdd **pay_load = NULL;
759 bool cleanup = false;
760 uint32_t i, actual;
761
762 Bulk_msg.n_mroute_add = mlag_msg.msg_cnt;
763 pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteAdd *)
764 * mlag_msg.msg_cnt);
765
766 for (i = 0, actual = 0; i < mlag_msg.msg_cnt; i++, actual++) {
767
768 uint32_t vrf_name_len = 0;
769
770 rc = mlag_lib_decode_mroute_add(s, &msg, &length);
771 if (rc) {
772 cleanup = true;
773 break;
774 }
775 pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF,
776 sizeof(ZebraMlagMrouteAdd));
777 zebra_mlag_mroute_add__init(pay_load[i]);
778
779 vrf_name_len = strlen(msg.vrf_name) + 1;
780 pay_load[i]->vrf_name =
781 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
782 strlcpy(pay_load[i]->vrf_name, msg.vrf_name,
783 vrf_name_len);
784 pay_load[i]->source_ip = msg.source_ip;
785 pay_load[i]->group_ip = msg.group_ip;
786 pay_load[i]->cost_to_rp = msg.cost_to_rp;
787 pay_load[i]->owner_id = msg.owner_id;
788 pay_load[i]->am_i_dr = msg.am_i_dr;
789 pay_load[i]->am_i_dual_active = msg.am_i_dual_active;
790 pay_load[i]->vrf_id = msg.vrf_id;
791 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
792 vrf_name_len = strlen(msg.intf_name) + 1;
793 pay_load[i]->intf_name =
794 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
795
796 strlcpy(pay_load[i]->intf_name, msg.intf_name,
797 vrf_name_len);
798 }
799 }
800 if (!cleanup) {
801 Bulk_msg.mroute_add = pay_load;
802 len = zebra_mlag_mroute_add_bulk__pack(&Bulk_msg,
803 tmp_buf);
804 }
805
806 for (i = 0; i < actual; i++) {
807 /*
808 * The mlag_lib_decode_mroute_add can
809 * fail to properly decode and cause nothing
810 * to be allocated. Prevent a crash
811 */
812 if (!pay_load[i])
813 continue;
814
815 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
816 if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
817 && pay_load[i]->intf_name)
818 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
819 XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
820 }
821 XFREE(MTYPE_MLAG_PBUF, pay_load);
822 if (cleanup)
823 return -1;
824 } break;
825 case MLAG_MROUTE_DEL_BULK: {
826 struct mlag_mroute_del msg;
827 ZebraMlagMrouteDelBulk Bulk_msg =
828 ZEBRA_MLAG_MROUTE_DEL_BULK__INIT;
829 ZebraMlagMrouteDel **pay_load = NULL;
830 bool cleanup = false;
831 uint32_t i, actual;
832
833 Bulk_msg.n_mroute_del = mlag_msg.msg_cnt;
834 pay_load = XMALLOC(MTYPE_MLAG_PBUF, sizeof(ZebraMlagMrouteDel *)
835 * mlag_msg.msg_cnt);
836
837 for (i = 0, actual = 0; i < mlag_msg.msg_cnt; i++, actual++) {
838
839 uint32_t vrf_name_len = 0;
840
841 rc = mlag_lib_decode_mroute_del(s, &msg, &length);
842 if (rc) {
843 cleanup = true;
844 break;
845 }
846
847 pay_load[i] = XMALLOC(MTYPE_MLAG_PBUF,
848 sizeof(ZebraMlagMrouteDel));
849 zebra_mlag_mroute_del__init(pay_load[i]);
850
851 vrf_name_len = strlen(msg.vrf_name) + 1;
852 pay_load[i]->vrf_name =
853 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
854
855 strlcpy(pay_load[i]->vrf_name, msg.vrf_name,
856 vrf_name_len);
857 pay_load[i]->source_ip = msg.source_ip;
858 pay_load[i]->group_ip = msg.group_ip;
859 pay_load[i]->owner_id = msg.owner_id;
860 pay_load[i]->vrf_id = msg.vrf_id;
861 if (msg.owner_id == MLAG_OWNER_INTERFACE) {
862 vrf_name_len = strlen(msg.intf_name) + 1;
863 pay_load[i]->intf_name =
864 XMALLOC(MTYPE_MLAG_PBUF, vrf_name_len);
865
866 strlcpy(pay_load[i]->intf_name, msg.intf_name,
867 vrf_name_len);
868 }
869 }
870 if (!cleanup) {
871 Bulk_msg.mroute_del = pay_load;
872 len = zebra_mlag_mroute_del_bulk__pack(&Bulk_msg,
873 tmp_buf);
874 }
875
876 for (i = 0; i < actual; i++) {
877 /*
878 * The mlag_lib_decode_mroute_add can
879 * fail to properly decode and cause nothing
880 * to be allocated. Prevent a crash
881 */
882 if (!pay_load[i])
883 continue;
884
885 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->vrf_name);
886 if (pay_load[i]->owner_id == MLAG_OWNER_INTERFACE
887 && pay_load[i]->intf_name)
888 XFREE(MTYPE_MLAG_PBUF, pay_load[i]->intf_name);
889 XFREE(MTYPE_MLAG_PBUF, pay_load[i]);
890 }
891 XFREE(MTYPE_MLAG_PBUF, pay_load);
892 if (cleanup)
893 return -1;
894 } break;
895 default:
896 break;
897 }
898
899 if (IS_ZEBRA_DEBUG_MLAG)
900 zlog_debug("%s: length of Mlag ProtoBuf encoded message:%s, %d",
901 __func__,
902 mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
903 sizeof(buf)),
904 len);
905 hdr.type = (ZebraMlagHeader__MessageType)mlag_msg.msg_type;
906 if (len != 0) {
907 hdr.data.len = len;
908 hdr.data.data = XMALLOC(MTYPE_MLAG_PBUF, len);
909 memcpy(hdr.data.data, tmp_buf, len);
910 }
911
912 /*
913 * ProtoBuf Infra will not support to demarc the pointers whem multiple
914 * messages are posted inside a single Buffer.
915 * 2 -solutions exist to solve this
916 * 1. add Unenoced length at the beginning of every message, this will
917 * be used to point to next message in the buffer
918 * 2. another solution is defining all messages insides another message
919 * But this will permit only 32 messages. this can be extended with
920 * multiple levels.
921 * for simplicity we are going with solution-1.
922 */
923 len = zebra_mlag__header__pack(&hdr,
924 (mlag_wr_buffer + ZEBRA_MLAG_LEN_SIZE));
925 n_len = htonl(len);
926 memcpy(mlag_wr_buffer, &n_len, ZEBRA_MLAG_LEN_SIZE);
927 len += ZEBRA_MLAG_LEN_SIZE;
928
929 if (IS_ZEBRA_DEBUG_MLAG)
930 zlog_debug(
931 "%s: length of Mlag ProtoBuf message:%s with Header %d",
932 __func__,
933 mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
934 sizeof(buf)),
935 len);
936 XFREE(MTYPE_MLAG_PBUF, hdr.data.data);
937
938 return len;
939 }
940
941 static void zebra_fill_protobuf_msg(struct stream *s, char *name, int len)
942 {
943 int str_len = strlen(name) + 1;
944
945 stream_put(s, name, str_len);
946 /* Fill the rest with Null Character for aligning */
947 stream_put(s, NULL, len - str_len);
948 }
949
950 int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
951 uint32_t len)
952 {
953 uint32_t msg_type;
954 ZebraMlagHeader *hdr;
955 char buf[80];
956
957 hdr = zebra_mlag__header__unpack(NULL, len, data);
958 if (hdr == NULL)
959 return -1;
960
961 /*
962 * ADD The MLAG Header
963 */
964 zclient_create_header(s, ZEBRA_MLAG_FORWARD_MSG, VRF_DEFAULT);
965
966 msg_type = hdr->type;
967
968 if (IS_ZEBRA_DEBUG_MLAG)
969 zlog_debug("%s: Mlag ProtoBuf decoding of message:%s", __func__,
970 mlag_lib_msgid_to_str(msg_type, buf, 80));
971
972 /*
973 * Internal MLAG Message-types & MLAG.proto message types should
974 * always match, otherwise there can be decoding errors
975 * To avoid exposing clients with Protobuf flags, using internal
976 * message-types
977 */
978 stream_putl(s, hdr->type);
979
980 if (hdr->data.len == 0) {
981 /* NULL Payload */
982 stream_putw(s, MLAG_MSG_NULL_PAYLOAD);
983 /* No Batching */
984 stream_putw(s, MLAG_MSG_NO_BATCH);
985 } else {
986 switch (msg_type) {
987 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_STATUS_UPDATE: {
988 ZebraMlagStatusUpdate *msg = NULL;
989
990 msg = zebra_mlag_status_update__unpack(
991 NULL, hdr->data.len, hdr->data.data);
992 if (msg == NULL) {
993 zebra_mlag__header__free_unpacked(hdr, NULL);
994 return -1;
995 }
996 /* Payload len */
997 stream_putw(s, sizeof(struct mlag_status));
998 /* No Batching */
999 stream_putw(s, MLAG_MSG_NO_BATCH);
1000 /* Actual Data */
1001 zebra_fill_protobuf_msg(s, msg->peerlink,
1002 INTERFACE_NAMSIZ);
1003 stream_putl(s, msg->my_role);
1004 stream_putl(s, msg->peer_state);
1005 zebra_mlag_status_update__free_unpacked(msg, NULL);
1006 } break;
1007 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_VXLAN_UPDATE: {
1008 ZebraMlagVxlanUpdate *msg = NULL;
1009
1010 msg = zebra_mlag_vxlan_update__unpack(
1011 NULL, hdr->data.len, hdr->data.data);
1012 if (msg == NULL) {
1013 zebra_mlag__header__free_unpacked(hdr, NULL);
1014 return -1;
1015 }
1016 /* Payload len */
1017 stream_putw(s, sizeof(struct mlag_vxlan));
1018 /* No Batching */
1019 stream_putw(s, MLAG_MSG_NO_BATCH);
1020 /* Actual Data */
1021 stream_putl(s, msg->anycast_ip);
1022 stream_putl(s, msg->local_ip);
1023 zebra_mlag_vxlan_update__free_unpacked(msg, NULL);
1024 } break;
1025 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD: {
1026 ZebraMlagMrouteAdd *msg = NULL;
1027
1028 msg = zebra_mlag_mroute_add__unpack(NULL, hdr->data.len,
1029 hdr->data.data);
1030 if (msg == NULL) {
1031 zebra_mlag__header__free_unpacked(hdr, NULL);
1032 return -1;
1033 }
1034 /* Payload len */
1035 stream_putw(s, sizeof(struct mlag_mroute_add));
1036 /* No Batching */
1037 stream_putw(s, MLAG_MSG_NO_BATCH);
1038 /* Actual Data */
1039 zebra_fill_protobuf_msg(s, msg->vrf_name, VRF_NAMSIZ);
1040
1041 stream_putl(s, msg->source_ip);
1042 stream_putl(s, msg->group_ip);
1043 stream_putl(s, msg->cost_to_rp);
1044 stream_putl(s, msg->owner_id);
1045 stream_putc(s, msg->am_i_dr);
1046 stream_putc(s, msg->am_i_dual_active);
1047 stream_putl(s, msg->vrf_id);
1048 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1049 zebra_fill_protobuf_msg(s, msg->intf_name,
1050 INTERFACE_NAMSIZ);
1051 else
1052 stream_put(s, NULL, INTERFACE_NAMSIZ);
1053 zebra_mlag_mroute_add__free_unpacked(msg, NULL);
1054 } break;
1055 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL: {
1056 ZebraMlagMrouteDel *msg = NULL;
1057
1058 msg = zebra_mlag_mroute_del__unpack(NULL, hdr->data.len,
1059 hdr->data.data);
1060 if (msg == NULL) {
1061 zebra_mlag__header__free_unpacked(hdr, NULL);
1062 return -1;
1063 }
1064 /* Payload len */
1065 stream_putw(s, sizeof(struct mlag_mroute_del));
1066 /* No Batching */
1067 stream_putw(s, MLAG_MSG_NO_BATCH);
1068 /* Actual Data */
1069 zebra_fill_protobuf_msg(s, msg->vrf_name, VRF_NAMSIZ);
1070
1071 stream_putl(s, msg->source_ip);
1072 stream_putl(s, msg->group_ip);
1073 stream_putl(s, msg->owner_id);
1074 stream_putl(s, msg->vrf_id);
1075 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1076 zebra_fill_protobuf_msg(s, msg->intf_name,
1077 INTERFACE_NAMSIZ);
1078 else
1079 stream_put(s, NULL, INTERFACE_NAMSIZ);
1080 zebra_mlag_mroute_del__free_unpacked(msg, NULL);
1081 } break;
1082 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: {
1083 ZebraMlagMrouteAddBulk *Bulk_msg = NULL;
1084 ZebraMlagMrouteAdd *msg = NULL;
1085 size_t i;
1086
1087 Bulk_msg = zebra_mlag_mroute_add_bulk__unpack(
1088 NULL, hdr->data.len, hdr->data.data);
1089 if (Bulk_msg == NULL) {
1090 zebra_mlag__header__free_unpacked(hdr, NULL);
1091 return -1;
1092 }
1093 /* Payload len */
1094 stream_putw(s, (Bulk_msg->n_mroute_add
1095 * sizeof(struct mlag_mroute_add)));
1096 /* No. of msgs in Batch */
1097 stream_putw(s, Bulk_msg->n_mroute_add);
1098
1099 /* Actual Data */
1100 for (i = 0; i < Bulk_msg->n_mroute_add; i++) {
1101
1102 msg = Bulk_msg->mroute_add[i];
1103
1104 zebra_fill_protobuf_msg(s, msg->vrf_name,
1105 VRF_NAMSIZ);
1106 stream_putl(s, msg->source_ip);
1107 stream_putl(s, msg->group_ip);
1108 stream_putl(s, msg->cost_to_rp);
1109 stream_putl(s, msg->owner_id);
1110 stream_putc(s, msg->am_i_dr);
1111 stream_putc(s, msg->am_i_dual_active);
1112 stream_putl(s, msg->vrf_id);
1113 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1114 zebra_fill_protobuf_msg(
1115 s, msg->intf_name,
1116 INTERFACE_NAMSIZ);
1117 else
1118 stream_put(s, NULL, INTERFACE_NAMSIZ);
1119 }
1120 zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg,
1121 NULL);
1122 } break;
1123 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK: {
1124 ZebraMlagMrouteDelBulk *Bulk_msg = NULL;
1125 ZebraMlagMrouteDel *msg = NULL;
1126 size_t i;
1127
1128 Bulk_msg = zebra_mlag_mroute_del_bulk__unpack(
1129 NULL, hdr->data.len, hdr->data.data);
1130 if (Bulk_msg == NULL) {
1131 zebra_mlag__header__free_unpacked(hdr, NULL);
1132 return -1;
1133 }
1134 /* Payload len */
1135 stream_putw(s, (Bulk_msg->n_mroute_del
1136 * sizeof(struct mlag_mroute_del)));
1137 /* No. of msgs in Batch */
1138 stream_putw(s, Bulk_msg->n_mroute_del);
1139
1140 /* Actual Data */
1141 for (i = 0; i < Bulk_msg->n_mroute_del; i++) {
1142
1143 msg = Bulk_msg->mroute_del[i];
1144
1145 zebra_fill_protobuf_msg(s, msg->vrf_name,
1146 VRF_NAMSIZ);
1147 stream_putl(s, msg->source_ip);
1148 stream_putl(s, msg->group_ip);
1149 stream_putl(s, msg->owner_id);
1150 stream_putl(s, msg->vrf_id);
1151 if (msg->owner_id == MLAG_OWNER_INTERFACE)
1152 zebra_fill_protobuf_msg(
1153 s, msg->intf_name,
1154 INTERFACE_NAMSIZ);
1155 else
1156 stream_put(s, NULL, INTERFACE_NAMSIZ);
1157 }
1158 zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg,
1159 NULL);
1160 } break;
1161 case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_ZEBRA_STATUS_UPDATE: {
1162 ZebraMlagZebraStatusUpdate *msg = NULL;
1163
1164 msg = zebra_mlag_zebra_status_update__unpack(
1165 NULL, hdr->data.len, hdr->data.data);
1166 if (msg == NULL) {
1167 zebra_mlag__header__free_unpacked(hdr, NULL);
1168 return -1;
1169 }
1170 /* Payload len */
1171 stream_putw(s, sizeof(struct mlag_frr_status));
1172 /* No Batching */
1173 stream_putw(s, MLAG_MSG_NO_BATCH);
1174 /* Actual Data */
1175 stream_putl(s, msg->peer_frrstate);
1176 zebra_mlag_zebra_status_update__free_unpacked(msg,
1177 NULL);
1178 } break;
1179 default:
1180 break;
1181 }
1182 }
1183 zebra_mlag__header__free_unpacked(hdr, NULL);
1184 return msg_type;
1185 }
1186
1187 #else
1188 int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
1189 {
1190 return 0;
1191 }
1192
1193 int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
1194 uint32_t len)
1195 {
1196 return 0;
1197 }
1198 #endif