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