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