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