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