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