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