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