]>
Commit | Line | Data |
---|---|---|
244c1cdc DS |
1 | /* Kernel routing table updates using netlink over GNU/Linux system. |
2 | * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * GNU Zebra is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
18 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | * 02111-1307, USA. | |
20 | */ | |
21 | ||
22 | #include <zebra.h> | |
23 | #include <sys/un.h> /* for sockaddr_un */ | |
24 | #include <net/if.h> | |
c8ed14dd | 25 | #include "vty.h" |
244c1cdc DS |
26 | #include "zebra/zserv.h" |
27 | #include "zebra/interface.h" | |
28 | #include "zebra/debug.h" | |
29 | #include "zebra/zebra_ptm.h" | |
30 | #include "if.h" | |
31 | #include "command.h" | |
c43ed2e4 DS |
32 | #include "stream.h" |
33 | #include "ptm_lib.h" | |
c8ed14dd | 34 | #include "buffer.h" |
c43ed2e4 | 35 | #include "zebra/zebra_ptm_redistribute.h" |
68fe91d6 | 36 | #include "bfd.h" |
d553294e | 37 | #include "vrf.h" |
7c551956 DS |
38 | #include "rib.h" |
39 | #include "zebra_vrf.h" | |
244c1cdc DS |
40 | |
41 | #define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */ | |
42 | #define ZEBRA_PTM_RECONNECT_TIME_MAX 300 | |
c01acf98 | 43 | |
c01acf98 | 44 | #define PTM_MSG_LEN 4 |
0a56c844 | 45 | #define PTM_HEADER_LEN 37 |
c43ed2e4 DS |
46 | |
47 | const char ZEBRA_PTM_GET_STATUS_CMD[] = "get-status"; | |
48 | const char ZEBRA_PTM_BFD_START_CMD[] = "start-bfd-sess"; | |
49 | const char ZEBRA_PTM_BFD_STOP_CMD[] = "stop-bfd-sess"; | |
055c4dfc | 50 | const char ZEBRA_PTM_BFD_CLIENT_REG_CMD[] = "reg-bfd-client"; |
567b877d | 51 | const char ZEBRA_PTM_BFD_CLIENT_DEREG_CMD[] = "dereg-bfd-client"; |
c43ed2e4 | 52 | |
c8ed14dd | 53 | const char ZEBRA_PTM_CMD_STR[] = "cmd"; |
b255a4b1 | 54 | const char ZEBRA_PTM_CMD_STATUS_STR[] = "cmd_status"; |
c43ed2e4 DS |
55 | const char ZEBRA_PTM_PORT_STR[] = "port"; |
56 | const char ZEBRA_PTM_CBL_STR[] = "cbl status"; | |
57 | const char ZEBRA_PTM_PASS_STR[] = "pass"; | |
58 | const char ZEBRA_PTM_FAIL_STR[] = "fail"; | |
59 | const char ZEBRA_PTM_BFDSTATUS_STR[] = "state"; | |
60 | const char ZEBRA_PTM_BFDSTATUS_UP_STR[] = "Up"; | |
61 | const char ZEBRA_PTM_BFDSTATUS_DOWN_STR[] = "Down"; | |
62 | const char ZEBRA_PTM_BFDDEST_STR[] = "peer"; | |
63 | const char ZEBRA_PTM_BFDSRC_STR[] = "local"; | |
d553294e | 64 | const char ZEBRA_PTM_BFDVRF_STR[] = "vrf"; |
c43ed2e4 DS |
65 | const char ZEBRA_PTM_INVALID_PORT_NAME[] = "N/A"; |
66 | const char ZEBRA_PTM_INVALID_SRC_IP[] = "N/A"; | |
d553294e | 67 | const char ZEBRA_PTM_INVALID_VRF[] = "N/A"; |
c43ed2e4 DS |
68 | |
69 | const char ZEBRA_PTM_BFD_DST_IP_FIELD[] = "dstIPaddr"; | |
70 | const char ZEBRA_PTM_BFD_SRC_IP_FIELD[] = "srcIPaddr"; | |
71 | const char ZEBRA_PTM_BFD_MIN_RX_FIELD[] = "requiredMinRx"; | |
72 | const char ZEBRA_PTM_BFD_MIN_TX_FIELD[] = "upMinTx"; | |
73 | const char ZEBRA_PTM_BFD_DETECT_MULT_FIELD[] = "detectMult"; | |
74 | const char ZEBRA_PTM_BFD_MULTI_HOP_FIELD[] = "multiHop"; | |
75 | const char ZEBRA_PTM_BFD_CLIENT_FIELD[] = "client"; | |
76 | const char ZEBRA_PTM_BFD_SEQID_FIELD[] = "seqid"; | |
77 | const char ZEBRA_PTM_BFD_IFNAME_FIELD[] = "ifName"; | |
78 | const char ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD[] = "maxHopCnt"; | |
68fe91d6 | 79 | const char ZEBRA_PTM_BFD_SEND_EVENT[] = "sendEvent"; |
d553294e | 80 | const char ZEBRA_PTM_BFD_VRF_NAME_FIELD[] = "vrfName"; |
c01acf98 | 81 | |
c43ed2e4 | 82 | static ptm_lib_handle_t *ptm_hdl; |
244c1cdc | 83 | |
c8ed14dd DS |
84 | struct zebra_ptm_cb ptm_cb; |
85 | ||
244c1cdc | 86 | static int zebra_ptm_socket_init(void); |
244c1cdc DS |
87 | int zebra_ptm_sock_read(struct thread *); |
88 | static void zebra_ptm_install_commands (void); | |
b255a4b1 | 89 | static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt); |
c43ed2e4 | 90 | void zebra_bfd_peer_replay_req (void); |
950bd436 | 91 | void zebra_ptm_send_status_req(void); |
92 | void zebra_ptm_reset_status(int ptm_disable); | |
244c1cdc DS |
93 | |
94 | const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket"; | |
95 | ||
244c1cdc DS |
96 | void |
97 | zebra_ptm_init (void) | |
98 | { | |
c43ed2e4 DS |
99 | char buf[64]; |
100 | ||
c8ed14dd DS |
101 | memset(&ptm_cb, 0, sizeof(struct zebra_ptm_cb)); |
102 | ||
103 | ptm_cb.out_data = calloc(1, ZEBRA_PTM_SEND_MAX_SOCKBUF); | |
104 | if (!ptm_cb.out_data) | |
105 | { | |
106 | zlog_warn("%s: Allocation of send data failed", __func__); | |
107 | return; | |
108 | } | |
109 | ||
110 | ptm_cb.in_data = calloc(1, ZEBRA_PTM_MAX_SOCKBUF); | |
111 | if (!ptm_cb.in_data) | |
112 | { | |
113 | zlog_warn("%s: Allocation of recv data failed", __func__); | |
114 | free(ptm_cb.out_data); | |
115 | return; | |
116 | } | |
117 | ||
118 | ptm_cb.pid = getpid(); | |
244c1cdc | 119 | zebra_ptm_install_commands(); |
c43ed2e4 DS |
120 | |
121 | sprintf(buf, "%s", "quagga"); | |
b255a4b1 | 122 | ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_msg_cb, |
123 | zebra_ptm_handle_msg_cb); | |
c8ed14dd DS |
124 | ptm_cb.wb = buffer_new(0); |
125 | ||
126 | ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; | |
127 | ||
128 | ptm_cb.ptm_sock = -1; | |
129 | } | |
130 | ||
131 | void | |
132 | zebra_ptm_finish(void) | |
133 | { | |
134 | if (ptm_cb.ptm_sock != -1) | |
135 | close(ptm_cb.ptm_sock); | |
136 | ||
137 | if (ptm_cb.wb) | |
138 | buffer_free(ptm_cb.wb); | |
139 | ||
140 | if (ptm_cb.out_data) | |
141 | free(ptm_cb.out_data); | |
142 | ||
143 | if (ptm_cb.in_data) | |
144 | free(ptm_cb.in_data); | |
145 | ||
146 | /* Release threads. */ | |
147 | if (ptm_cb.t_read) | |
148 | thread_cancel (ptm_cb.t_read); | |
149 | if (ptm_cb.t_write) | |
150 | thread_cancel (ptm_cb.t_write); | |
151 | if (ptm_cb.t_timer) | |
152 | thread_cancel (ptm_cb.t_timer); | |
153 | } | |
154 | ||
155 | static int | |
156 | zebra_ptm_flush_messages (struct thread *thread) | |
157 | { | |
158 | ptm_cb.t_write = NULL; | |
159 | ||
160 | if (ptm_cb.ptm_sock == -1) | |
161 | return -1; | |
162 | ||
163 | errno = 0; | |
164 | ||
165 | switch (buffer_flush_available(ptm_cb.wb, ptm_cb.ptm_sock)) | |
166 | { | |
167 | case BUFFER_ERROR: | |
168 | zlog_warn ("%s ptm socket error: %s", __func__, | |
169 | safe_strerror (errno)); | |
170 | close(ptm_cb.ptm_sock); | |
171 | ptm_cb.ptm_sock = -1; | |
950bd436 | 172 | zebra_ptm_reset_status(0); |
c8ed14dd DS |
173 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, |
174 | NULL, ptm_cb.reconnect_time); | |
175 | return (-1); | |
176 | case BUFFER_PENDING: | |
177 | ptm_cb.t_write = thread_add_write(zebrad.master, zebra_ptm_flush_messages, | |
178 | NULL, ptm_cb.ptm_sock); | |
179 | break; | |
180 | case BUFFER_EMPTY: | |
181 | break; | |
182 | } | |
183 | ||
184 | return(0); | |
185 | } | |
186 | ||
187 | static int | |
188 | zebra_ptm_send_message(char *data, int size) | |
189 | { | |
190 | errno = 0; | |
191 | switch (buffer_write(ptm_cb.wb, ptm_cb.ptm_sock, data, size)) | |
192 | { | |
193 | case BUFFER_ERROR: | |
194 | zlog_warn ("%s ptm socket error: %s", __func__, safe_strerror (errno)); | |
195 | close(ptm_cb.ptm_sock); | |
196 | ptm_cb.ptm_sock = -1; | |
950bd436 | 197 | zebra_ptm_reset_status(0); |
c8ed14dd DS |
198 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, |
199 | NULL, ptm_cb.reconnect_time); | |
200 | return -1; | |
201 | case BUFFER_EMPTY: | |
202 | THREAD_OFF(ptm_cb.t_write); | |
203 | break; | |
204 | case BUFFER_PENDING: | |
205 | THREAD_WRITE_ON(zebrad.master, ptm_cb.t_write, | |
206 | zebra_ptm_flush_messages, NULL, ptm_cb.ptm_sock); | |
207 | break; | |
208 | } | |
209 | ||
210 | return 0; | |
244c1cdc DS |
211 | } |
212 | ||
213 | int | |
214 | zebra_ptm_connect (struct thread *t) | |
215 | { | |
c43ed2e4 | 216 | int init = 0; |
c43ed2e4 | 217 | |
c8ed14dd | 218 | if (ptm_cb.ptm_sock == -1) { |
c43ed2e4 DS |
219 | zebra_ptm_socket_init(); |
220 | init = 1; | |
221 | } | |
244c1cdc | 222 | |
c8ed14dd | 223 | if (ptm_cb.ptm_sock != -1) { |
c43ed2e4 | 224 | if (init) { |
c8ed14dd DS |
225 | ptm_cb.t_read = thread_add_read (zebrad.master, zebra_ptm_sock_read, |
226 | NULL, ptm_cb.ptm_sock); | |
c43ed2e4 DS |
227 | zebra_bfd_peer_replay_req(); |
228 | } | |
950bd436 | 229 | zebra_ptm_send_status_req(); |
c8ed14dd | 230 | ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; |
986aa00f | 231 | } else if (ptm_cb.reconnect_time < ZEBRA_PTM_RECONNECT_TIME_MAX){ |
c8ed14dd DS |
232 | ptm_cb.reconnect_time *= 2; |
233 | if (ptm_cb.reconnect_time > ZEBRA_PTM_RECONNECT_TIME_MAX) | |
234 | ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX; | |
244c1cdc | 235 | |
c8ed14dd DS |
236 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, NULL, |
237 | ptm_cb.reconnect_time); | |
986aa00f | 238 | } else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX){ |
239 | ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL; | |
244c1cdc DS |
240 | } |
241 | ||
242 | return(errno); | |
243 | } | |
244 | ||
244c1cdc DS |
245 | DEFUN (zebra_ptm_enable, |
246 | zebra_ptm_enable_cmd, | |
247 | "ptm-enable", | |
248 | "Enable neighbor check with specified topology\n") | |
249 | { | |
250 | struct listnode *i; | |
251 | struct interface *ifp; | |
986aa00f | 252 | struct zebra_if *if_data; |
b2d7c082 | 253 | vrf_iter_t iter; |
244c1cdc | 254 | |
986aa00f | 255 | ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_ON; |
244c1cdc | 256 | |
b2d7c082 DS |
257 | for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) |
258 | for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), i, ifp)) | |
259 | if (!ifp->ptm_enable) | |
260 | { | |
986aa00f | 261 | if_data = (struct zebra_if *)ifp->info; |
262 | if (if_data && | |
263 | (if_data->ptm_enable == ZEBRA_IF_PTM_ENABLE_UNSPEC)) | |
264 | { | |
265 | ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_ON; | |
266 | } | |
b2d7c082 | 267 | /* Assign a default unknown status */ |
986aa00f | 268 | ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; |
b2d7c082 | 269 | } |
244c1cdc DS |
270 | |
271 | zebra_ptm_connect(NULL); | |
272 | ||
273 | return CMD_SUCCESS; | |
274 | } | |
275 | ||
276 | DEFUN (no_zebra_ptm_enable, | |
277 | no_zebra_ptm_enable_cmd, | |
278 | "no ptm-enable", | |
279 | NO_STR | |
280 | "Enable neighbor check with specified topology\n") | |
281 | { | |
986aa00f | 282 | ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; |
950bd436 | 283 | zebra_ptm_reset_status(1); |
244c1cdc DS |
284 | return CMD_SUCCESS; |
285 | } | |
286 | ||
986aa00f | 287 | DEFUN (zebra_ptm_enable_if, |
288 | zebra_ptm_enable_if_cmd, | |
289 | "ptm-enable", | |
290 | "Enable neighbor check with specified topology\n") | |
291 | { | |
292 | struct interface *ifp; | |
293 | struct zebra_if *if_data; | |
294 | int old_ptm_enable; | |
295 | int send_linkdown = 0; | |
296 | ||
297 | ifp = (struct interface *) vty->index; | |
298 | if (ifp->ifindex == IFINDEX_INTERNAL) | |
299 | { | |
300 | return CMD_SUCCESS; | |
301 | } | |
302 | ||
303 | old_ptm_enable = ifp->ptm_enable; | |
304 | ifp->ptm_enable = ptm_cb.ptm_enable; | |
305 | ||
306 | if (if_is_no_ptm_operative(ifp)) | |
307 | send_linkdown = 1; | |
308 | ||
309 | if (!old_ptm_enable && ptm_cb.ptm_enable) | |
310 | { | |
311 | if (!if_is_operative (ifp) && send_linkdown) | |
312 | { | |
313 | if (IS_ZEBRA_DEBUG_EVENT) | |
314 | zlog_debug ("%s: Bringing down interface %s\n", __func__, | |
315 | ifp->name); | |
316 | if_down (ifp); | |
317 | } | |
318 | } | |
319 | ||
320 | if_data = ifp->info; | |
321 | if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC; | |
322 | ||
323 | return CMD_SUCCESS; | |
324 | } | |
325 | ||
326 | DEFUN (no_zebra_ptm_enable_if, | |
327 | no_zebra_ptm_enable_if_cmd, | |
328 | "no ptm-enable", | |
329 | NO_STR | |
330 | "Enable neighbor check with specified topology\n") | |
331 | { | |
332 | struct interface *ifp; | |
333 | int send_linkup = 0; | |
334 | struct zebra_if *if_data; | |
335 | ||
336 | ifp = (struct interface *) vty->index; | |
337 | ||
338 | if ((ifp->ifindex != IFINDEX_INTERNAL) && (ifp->ptm_enable)) | |
339 | { | |
340 | if (!if_is_operative(ifp)) | |
341 | send_linkup = 1; | |
342 | ||
343 | ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; | |
344 | if (if_is_no_ptm_operative (ifp) && send_linkup) | |
345 | { | |
346 | if (IS_ZEBRA_DEBUG_EVENT) | |
347 | zlog_debug ("%s: Bringing up interface %s\n", __func__, | |
348 | ifp->name); | |
349 | if_up (ifp); | |
350 | } | |
351 | } | |
352 | ||
353 | if_data = ifp->info; | |
354 | if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; | |
355 | ||
356 | return CMD_SUCCESS; | |
357 | } | |
358 | ||
359 | ||
244c1cdc DS |
360 | void |
361 | zebra_ptm_write (struct vty *vty) | |
362 | { | |
c8ed14dd | 363 | if (ptm_cb.ptm_enable) |
244c1cdc DS |
364 | vty_out (vty, "ptm-enable%s", VTY_NEWLINE); |
365 | ||
366 | return; | |
367 | } | |
368 | ||
369 | static int | |
370 | zebra_ptm_socket_init (void) | |
371 | { | |
372 | int ret; | |
373 | int sock; | |
374 | struct sockaddr_un addr; | |
375 | ||
c8ed14dd | 376 | ptm_cb.ptm_sock = -1; |
c01acf98 | 377 | |
0a56c844 | 378 | sock = socket (PF_UNIX, (SOCK_STREAM | SOCK_NONBLOCK), 0); |
244c1cdc DS |
379 | if (sock < 0) |
380 | return -1; | |
381 | ||
382 | /* Make server socket. */ | |
383 | memset (&addr, 0, sizeof (struct sockaddr_un)); | |
384 | addr.sun_family = AF_UNIX; | |
385 | memcpy (&addr.sun_path, ZEBRA_PTM_SOCK_NAME, | |
386 | sizeof(ZEBRA_PTM_SOCK_NAME)); | |
387 | ||
388 | ret = connect(sock, (struct sockaddr *) &addr, | |
c01acf98 | 389 | sizeof (addr.sun_family)+sizeof (ZEBRA_PTM_SOCK_NAME)-1); |
244c1cdc DS |
390 | if (ret < 0) |
391 | { | |
986aa00f | 392 | if (IS_ZEBRA_DEBUG_EVENT) |
393 | zlog_debug("%s: Unable to connect to socket %s [%s]", | |
c01acf98 | 394 | __func__, ZEBRA_PTM_SOCK_NAME, safe_strerror(errno)); |
244c1cdc DS |
395 | close (sock); |
396 | return -1; | |
397 | } | |
c8ed14dd | 398 | ptm_cb.ptm_sock = sock; |
244c1cdc DS |
399 | return sock; |
400 | } | |
401 | ||
402 | static void | |
403 | zebra_ptm_install_commands (void) | |
404 | { | |
405 | install_element (CONFIG_NODE, &zebra_ptm_enable_cmd); | |
406 | install_element (CONFIG_NODE, &no_zebra_ptm_enable_cmd); | |
986aa00f | 407 | install_element (INTERFACE_NODE, &zebra_ptm_enable_if_cmd); |
408 | install_element (INTERFACE_NODE, &no_zebra_ptm_enable_if_cmd); | |
244c1cdc DS |
409 | } |
410 | ||
c43ed2e4 | 411 | /* BFD session goes down, send message to the protocols. */ |
c8ed14dd | 412 | static void |
68fe91d6 | 413 | if_bfd_session_update (struct interface *ifp, struct prefix *dp, |
d553294e | 414 | struct prefix *sp, int status, vrf_id_t vrf_id) |
c01acf98 | 415 | { |
c43ed2e4 DS |
416 | if (IS_ZEBRA_DEBUG_EVENT) |
417 | { | |
418 | char buf[2][INET6_ADDRSTRLEN]; | |
419 | ||
420 | if (ifp) | |
421 | { | |
68fe91d6 | 422 | zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d on %s" |
423 | " %s event", | |
424 | inet_ntop (dp->family, &dp->u.prefix, buf[0], | |
425 | INET6_ADDRSTRLEN), dp->prefixlen, ifp->name, | |
426 | bfd_get_status_str(status)); | |
c43ed2e4 DS |
427 | } |
428 | else | |
429 | { | |
68fe91d6 | 430 | zlog_debug ("MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d " |
d553294e | 431 | "with src %s/%d and vrf %d %s event", |
c43ed2e4 DS |
432 | inet_ntop (dp->family, &dp->u.prefix, buf[0], INET6_ADDRSTRLEN), |
433 | dp->prefixlen, | |
434 | inet_ntop (sp->family, &sp->u.prefix, buf[1], INET6_ADDRSTRLEN), | |
d553294e | 435 | sp->prefixlen, vrf_id, bfd_get_status_str(status)); |
c43ed2e4 | 436 | } |
c01acf98 | 437 | } |
c01acf98 | 438 | |
d553294e | 439 | zebra_interface_bfd_update (ifp, dp, sp, status, vrf_id); |
c01acf98 DS |
440 | } |
441 | ||
c43ed2e4 | 442 | static int |
b255a4b1 | 443 | zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt, struct interface *ifp) |
244c1cdc | 444 | { |
c43ed2e4 DS |
445 | char bfdst_str[32]; |
446 | char dest_str[64]; | |
447 | char src_str[64]; | |
d553294e | 448 | char vrf_str[64]; |
244c1cdc | 449 | struct prefix dest_prefix; |
c43ed2e4 | 450 | struct prefix src_prefix; |
244c1cdc | 451 | |
c43ed2e4 | 452 | ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSTATUS_STR, bfdst_str); |
c01acf98 | 453 | |
c43ed2e4 | 454 | if (bfdst_str[0] == '\0') { |
c43ed2e4 | 455 | return -1; |
c01acf98 DS |
456 | } |
457 | ||
c43ed2e4 | 458 | ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDDEST_STR, dest_str); |
c01acf98 | 459 | |
c43ed2e4 DS |
460 | if (dest_str[0] == '\0') { |
461 | zlog_debug("%s: Key %s not found in PTM msg", __func__, | |
c01acf98 | 462 | ZEBRA_PTM_BFDDEST_STR); |
c43ed2e4 | 463 | return -1; |
c01acf98 | 464 | } |
244c1cdc | 465 | |
c43ed2e4 | 466 | ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDSRC_STR, src_str); |
c01acf98 | 467 | |
c43ed2e4 DS |
468 | if (src_str[0] == '\0') { |
469 | zlog_debug("%s: Key %s not found in PTM msg", __func__, | |
470 | ZEBRA_PTM_BFDSRC_STR); | |
471 | return -1; | |
c01acf98 DS |
472 | } |
473 | ||
d553294e | 474 | ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_BFDVRF_STR, vrf_str); |
475 | ||
476 | if (vrf_str[0] == '\0') { | |
477 | zlog_debug("%s: Key %s not found in PTM msg", __func__, | |
478 | ZEBRA_PTM_BFDVRF_STR); | |
479 | return -1; | |
480 | } | |
481 | ||
c8ed14dd | 482 | if (IS_ZEBRA_DEBUG_EVENT) |
d553294e | 483 | zlog_debug("%s: Recv Port [%s] bfd status [%s] vrf [%s] peer [%s] local [%s]", |
b255a4b1 | 484 | __func__, ifp ? ifp->name : "N/A", bfdst_str, |
d553294e | 485 | vrf_str, dest_str, src_str); |
c43ed2e4 | 486 | |
68fe91d6 | 487 | if (str2prefix(dest_str, &dest_prefix) == 0) { |
488 | zlog_err("%s: Peer addr %s not found", __func__, | |
489 | dest_str); | |
490 | return -1; | |
491 | } | |
c01acf98 | 492 | |
68fe91d6 | 493 | memset(&src_prefix, 0, sizeof(struct prefix)); |
494 | if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) { | |
495 | if (str2prefix(src_str, &src_prefix) == 0) { | |
496 | zlog_err("%s: Local addr %s not found", __func__, | |
497 | src_str); | |
498 | return -1; | |
c43ed2e4 | 499 | } |
68fe91d6 | 500 | } |
c43ed2e4 | 501 | |
68fe91d6 | 502 | if (!strcmp (bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) { |
d553294e | 503 | if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_DOWN, |
504 | vrf_name_to_id(vrf_str)); | |
68fe91d6 | 505 | } else { |
d553294e | 506 | if_bfd_session_update(ifp, &dest_prefix, &src_prefix, BFD_STATUS_UP, |
507 | vrf_name_to_id(vrf_str)); | |
c01acf98 | 508 | } |
c43ed2e4 DS |
509 | |
510 | return 0; | |
c01acf98 DS |
511 | } |
512 | ||
c43ed2e4 | 513 | static int |
b255a4b1 | 514 | zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt, struct interface *ifp, |
515 | char *cbl_str) | |
c01acf98 | 516 | { |
950bd436 | 517 | int send_linkup = 0; |
518 | ||
b255a4b1 | 519 | if (IS_ZEBRA_DEBUG_EVENT) |
520 | zlog_debug("%s: Recv Port [%s] cbl status [%s]", __func__, | |
521 | ifp->name, cbl_str); | |
522 | ||
950bd436 | 523 | if (!strcmp(cbl_str, ZEBRA_PTM_PASS_STR) && |
524 | (ifp->ptm_status != ZEBRA_PTM_STATUS_UP)) { | |
525 | ||
526 | if (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN) | |
527 | send_linkup = 1; | |
528 | ifp->ptm_status = ZEBRA_PTM_STATUS_UP; | |
529 | if (ifp->ptm_enable && if_is_no_ptm_operative (ifp) && send_linkup) | |
b255a4b1 | 530 | if_up (ifp); |
950bd436 | 531 | } else if (!strcmp (cbl_str, ZEBRA_PTM_FAIL_STR) && |
532 | (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) { | |
533 | ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN; | |
b255a4b1 | 534 | if (ifp->ptm_enable && if_is_no_ptm_operative (ifp)) |
535 | if_down (ifp); | |
536 | } | |
537 | ||
538 | return 0; | |
539 | } | |
950bd436 | 540 | |
b255a4b1 | 541 | /* |
542 | * zebra_ptm_handle_msg_cb - The purpose of this callback function is to handle | |
543 | * all the command responses and notifications received from PTM. | |
544 | * | |
545 | * Command responses: Upon establishing connection with PTM, Zebra requests | |
546 | * status of all interfaces using 'get-status' command if global ptm-enable | |
547 | * knob is enabled. As a response to the get-status command PTM sends status | |
548 | * of all the interfaces as command responses. All other type of command | |
549 | * responses with cmd_status key word are dropped. The sole purpose of | |
550 | * registering this function as callback for the command responses is to | |
551 | * handle the responses to get-status command. | |
552 | * | |
553 | * Notifications: Cable status and BFD session status changes are sent as | |
554 | * notifications by PTM. So, this function is also the callback function for | |
555 | * processing all the notifications from the PTM. | |
556 | * | |
557 | */ | |
558 | static int | |
559 | zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt) | |
560 | { | |
561 | struct interface *ifp = NULL; | |
c43ed2e4 | 562 | char port_str[128]; |
b255a4b1 | 563 | char cbl_str[32]; |
564 | char cmd_status_str[32]; | |
c8ed14dd | 565 | |
b255a4b1 | 566 | ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CMD_STATUS_STR, cmd_status_str); |
c8ed14dd DS |
567 | |
568 | /* Drop command response messages */ | |
b255a4b1 | 569 | if (cmd_status_str[0] != '\0') { |
c8ed14dd DS |
570 | return 0; |
571 | } | |
c01acf98 | 572 | |
c43ed2e4 | 573 | ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_PORT_STR, port_str); |
c01acf98 | 574 | |
c43ed2e4 | 575 | if (port_str[0] == '\0') { |
b255a4b1 | 576 | zlog_debug("%s: Key %s not found in PTM msg", __func__, |
c01acf98 | 577 | ZEBRA_PTM_PORT_STR); |
b255a4b1 | 578 | return -1; |
c01acf98 DS |
579 | } |
580 | ||
b255a4b1 | 581 | if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) { |
f8962871 | 582 | ifp = if_lookup_by_name_all_vrf(port_str); |
c01acf98 | 583 | |
b255a4b1 | 584 | if (!ifp) { |
585 | zlog_err("%s: %s not found in interface list", __func__, port_str); | |
586 | return -1; | |
587 | } | |
c01acf98 DS |
588 | } |
589 | ||
b255a4b1 | 590 | ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str); |
244c1cdc | 591 | |
b255a4b1 | 592 | if (cbl_str[0] == '\0') { |
593 | return zebra_ptm_handle_bfd_msg(arg, in_ctxt, ifp); | |
594 | } else { | |
595 | if (ifp) { | |
596 | return zebra_ptm_handle_cbl_msg(arg, in_ctxt, ifp, cbl_str); | |
597 | } else { | |
598 | return -1; | |
599 | } | |
244c1cdc | 600 | } |
c01acf98 DS |
601 | } |
602 | ||
c01acf98 DS |
603 | int |
604 | zebra_ptm_sock_read (struct thread *thread) | |
605 | { | |
606 | int sock, done = 0; | |
c43ed2e4 | 607 | int rc; |
c01acf98 | 608 | |
c43ed2e4 | 609 | errno = 0; |
c01acf98 DS |
610 | sock = THREAD_FD (thread); |
611 | ||
612 | if (sock == -1) | |
613 | return -1; | |
614 | ||
615 | /* PTM communicates in CSV format */ | |
616 | while(!done) { | |
c8ed14dd | 617 | rc = ptm_lib_process_msg(ptm_hdl, sock, ptm_cb.in_data, ZEBRA_PTM_MAX_SOCKBUF, |
c43ed2e4 DS |
618 | NULL); |
619 | if (rc <= 0) | |
620 | break; | |
c01acf98 DS |
621 | } |
622 | ||
c43ed2e4 DS |
623 | if (rc <= 0) { |
624 | if (((rc == 0) && !errno) || (errno && (errno != EWOULDBLOCK) && (errno != EAGAIN))) { | |
625 | zlog_warn ("%s routing socket error: %s(%d) bytes %d", __func__, | |
626 | safe_strerror (errno), errno, rc); | |
c01acf98 | 627 | |
c8ed14dd DS |
628 | close (ptm_cb.ptm_sock); |
629 | ptm_cb.ptm_sock = -1; | |
950bd436 | 630 | zebra_ptm_reset_status(0); |
c8ed14dd DS |
631 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, |
632 | NULL, ptm_cb.reconnect_time); | |
c01acf98 | 633 | return (-1); |
0a56c844 | 634 | } |
c01acf98 DS |
635 | } |
636 | ||
c8ed14dd DS |
637 | ptm_cb.t_read = thread_add_read (zebrad.master, zebra_ptm_sock_read, |
638 | NULL, ptm_cb.ptm_sock); | |
c43ed2e4 DS |
639 | |
640 | return 0; | |
641 | } | |
642 | ||
643 | /* BFD peer/dst register/update */ | |
644 | int | |
645 | zebra_ptm_bfd_dst_register (struct zserv *client, int sock, u_short length, | |
d651649e | 646 | int command, struct zebra_vrf *zvrf) |
c43ed2e4 | 647 | { |
c43ed2e4 DS |
648 | struct stream *s; |
649 | struct prefix src_p; | |
650 | struct prefix dst_p; | |
651 | u_char multi_hop; | |
652 | u_char multi_hop_cnt; | |
653 | u_char detect_mul; | |
654 | unsigned int min_rx_timer; | |
655 | unsigned int min_tx_timer; | |
656 | char if_name[INTERFACE_NAMSIZ]; | |
657 | u_char len; | |
658 | void *out_ctxt; | |
659 | char buf[INET6_ADDRSTRLEN]; | |
660 | char tmp_buf[64]; | |
661 | int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; | |
055c4dfc | 662 | unsigned int pid; |
c43ed2e4 DS |
663 | |
664 | if (command == ZEBRA_BFD_DEST_UPDATE) | |
665 | client->bfd_peer_upd8_cnt++; | |
666 | else | |
667 | client->bfd_peer_add_cnt++; | |
668 | ||
c8ed14dd DS |
669 | if (IS_ZEBRA_DEBUG_EVENT) |
670 | zlog_debug("bfd_dst_register msg from client %s: length=%d", | |
671 | zebra_route_string(client->proto), length); | |
c43ed2e4 | 672 | |
c8ed14dd | 673 | if (ptm_cb.ptm_sock == -1) |
c43ed2e4 | 674 | { |
c8ed14dd DS |
675 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, |
676 | NULL, ptm_cb.reconnect_time); | |
c43ed2e4 DS |
677 | return -1; |
678 | } | |
679 | ||
680 | ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); | |
681 | sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_START_CMD); | |
c8ed14dd | 682 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf); |
055c4dfc | 683 | sprintf(tmp_buf, "%s", zebra_route_string(client->proto)); |
c43ed2e4 DS |
684 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, |
685 | tmp_buf); | |
c43ed2e4 DS |
686 | |
687 | s = client->ibuf; | |
688 | ||
055c4dfc | 689 | pid = stream_getl(s); |
690 | sprintf(tmp_buf, "%d", pid); | |
691 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD, tmp_buf); | |
692 | ||
c43ed2e4 DS |
693 | dst_p.family = stream_getw(s); |
694 | ||
695 | if (dst_p.family == AF_INET) | |
696 | dst_p.prefixlen = IPV4_MAX_BYTELEN; | |
697 | else | |
698 | dst_p.prefixlen = IPV6_MAX_BYTELEN; | |
699 | ||
700 | stream_get(&dst_p.u.prefix, s, dst_p.prefixlen); | |
701 | if (dst_p.family == AF_INET) | |
702 | { | |
703 | inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf)); | |
704 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf); | |
705 | } | |
706 | #ifdef HAVE_IPV6 | |
707 | else | |
708 | { | |
709 | inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf)); | |
710 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf); | |
711 | } | |
712 | #endif /* HAVE_IPV6 */ | |
713 | ||
714 | min_rx_timer = stream_getl(s); | |
715 | sprintf(tmp_buf, "%d", min_rx_timer); | |
716 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_RX_FIELD, | |
717 | tmp_buf); | |
718 | min_tx_timer = stream_getl(s); | |
719 | sprintf(tmp_buf, "%d", min_tx_timer); | |
720 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MIN_TX_FIELD, | |
721 | tmp_buf); | |
722 | detect_mul = stream_getc(s); | |
723 | sprintf(tmp_buf, "%d", detect_mul); | |
724 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DETECT_MULT_FIELD, | |
725 | tmp_buf); | |
726 | ||
727 | multi_hop = stream_getc(s); | |
728 | if (multi_hop) | |
729 | { | |
730 | sprintf(tmp_buf, "%d", 1); | |
731 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD, | |
732 | tmp_buf); | |
733 | src_p.family = stream_getw(s); | |
734 | ||
735 | if (src_p.family == AF_INET) | |
736 | src_p.prefixlen = IPV4_MAX_BYTELEN; | |
737 | else | |
738 | src_p.prefixlen = IPV6_MAX_BYTELEN; | |
739 | ||
740 | stream_get(&src_p.u.prefix, s, src_p.prefixlen); | |
741 | if (src_p.family == AF_INET) | |
742 | { | |
743 | inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf)); | |
744 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
745 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
746 | } | |
747 | #ifdef HAVE_IPV6 | |
748 | else | |
749 | { | |
750 | inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf)); | |
751 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
752 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
753 | } | |
754 | #endif /* HAVE_IPV6 */ | |
755 | ||
756 | multi_hop_cnt = stream_getc(s); | |
757 | sprintf(tmp_buf, "%d", multi_hop_cnt); | |
758 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MAX_HOP_CNT_FIELD, | |
759 | tmp_buf); | |
d553294e | 760 | |
7b3eaa99 DS |
761 | if (zvrf->vrf_id != VRF_DEFAULT) |
762 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_VRF_NAME_FIELD, | |
763 | zvrf->name); | |
c43ed2e4 DS |
764 | } |
765 | else | |
766 | { | |
767 | #ifdef HAVE_IPV6 | |
768 | if (dst_p.family == AF_INET6) | |
769 | { | |
770 | src_p.family = stream_getw(s); | |
771 | ||
772 | if (src_p.family == AF_INET) | |
773 | src_p.prefixlen = IPV4_MAX_BYTELEN; | |
774 | else | |
775 | src_p.prefixlen = IPV6_MAX_BYTELEN; | |
776 | ||
777 | stream_get(&src_p.u.prefix, s, src_p.prefixlen); | |
778 | if (src_p.family == AF_INET) | |
779 | { | |
780 | inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf)); | |
781 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
782 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
783 | } | |
784 | else | |
785 | { | |
786 | inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf)); | |
787 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
788 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
789 | } | |
790 | } | |
791 | #endif /* HAVE_IPV6 */ | |
792 | len = stream_getc(s); | |
793 | stream_get(if_name, s, len); | |
794 | if_name[len] = '\0'; | |
795 | ||
796 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD, | |
797 | if_name); | |
798 | } | |
799 | ||
68fe91d6 | 800 | sprintf(tmp_buf, "%d", 1); |
801 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEND_EVENT, | |
802 | tmp_buf); | |
803 | ||
c8ed14dd DS |
804 | ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len); |
805 | ||
806 | if (IS_ZEBRA_DEBUG_SEND) | |
807 | zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, | |
808 | ptm_cb.out_data); | |
809 | zebra_ptm_send_message(ptm_cb.out_data, data_len); | |
c43ed2e4 DS |
810 | return 0; |
811 | } | |
812 | ||
813 | /* BFD peer/dst deregister */ | |
814 | int | |
d553294e | 815 | zebra_ptm_bfd_dst_deregister (struct zserv *client, int sock, u_short length, |
d651649e | 816 | struct zebra_vrf *zvrf) |
c43ed2e4 | 817 | { |
c43ed2e4 DS |
818 | struct stream *s; |
819 | struct prefix src_p; | |
820 | struct prefix dst_p; | |
821 | u_char multi_hop; | |
822 | char if_name[INTERFACE_NAMSIZ]; | |
823 | u_char len; | |
824 | char buf[INET6_ADDRSTRLEN]; | |
825 | char tmp_buf[64]; | |
826 | int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; | |
827 | void *out_ctxt; | |
055c4dfc | 828 | unsigned int pid; |
c43ed2e4 DS |
829 | |
830 | client->bfd_peer_del_cnt++; | |
831 | ||
c8ed14dd DS |
832 | if (IS_ZEBRA_DEBUG_EVENT) |
833 | zlog_debug("bfd_dst_deregister msg from client %s: length=%d", | |
834 | zebra_route_string(client->proto), length); | |
c43ed2e4 | 835 | |
c8ed14dd | 836 | if (ptm_cb.ptm_sock == -1) |
c43ed2e4 | 837 | { |
c8ed14dd DS |
838 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, |
839 | NULL, ptm_cb.reconnect_time); | |
c43ed2e4 DS |
840 | return -1; |
841 | } | |
842 | ||
843 | ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); | |
844 | ||
845 | sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_STOP_CMD); | |
c8ed14dd | 846 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf); |
c43ed2e4 | 847 | |
055c4dfc | 848 | sprintf(tmp_buf, "%s", zebra_route_string(client->proto)); |
c43ed2e4 DS |
849 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, |
850 | tmp_buf); | |
851 | ||
c43ed2e4 DS |
852 | s = client->ibuf; |
853 | ||
055c4dfc | 854 | pid = stream_getl(s); |
855 | sprintf(tmp_buf, "%d", pid); | |
856 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD, tmp_buf); | |
857 | ||
c43ed2e4 DS |
858 | dst_p.family = stream_getw(s); |
859 | ||
860 | if (dst_p.family == AF_INET) | |
861 | dst_p.prefixlen = IPV4_MAX_BYTELEN; | |
862 | else | |
863 | dst_p.prefixlen = IPV6_MAX_BYTELEN; | |
864 | ||
865 | stream_get(&dst_p.u.prefix, s, dst_p.prefixlen); | |
866 | if (dst_p.family == AF_INET) | |
867 | { | |
868 | inet_ntop(AF_INET, &dst_p.u.prefix4, buf, sizeof(buf)); | |
869 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf); | |
870 | } | |
871 | #ifdef HAVE_IPV6 | |
872 | else | |
873 | { | |
874 | inet_ntop(AF_INET6, &dst_p.u.prefix6, buf, sizeof(buf)); | |
875 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_DST_IP_FIELD, buf); | |
876 | } | |
877 | #endif /* HAVE_IPV6 */ | |
878 | ||
879 | multi_hop = stream_getc(s); | |
880 | if (multi_hop) | |
881 | { | |
882 | sprintf(tmp_buf, "%d", 1); | |
883 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_MULTI_HOP_FIELD, | |
884 | tmp_buf); | |
885 | ||
886 | src_p.family = stream_getw(s); | |
887 | ||
888 | if (src_p.family == AF_INET) | |
889 | src_p.prefixlen = IPV4_MAX_BYTELEN; | |
890 | else | |
891 | src_p.prefixlen = IPV6_MAX_BYTELEN; | |
892 | ||
893 | stream_get(&src_p.u.prefix, s, src_p.prefixlen); | |
894 | if (src_p.family == AF_INET) | |
895 | { | |
896 | inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf)); | |
897 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
898 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
899 | } | |
900 | #ifdef HAVE_IPV6 | |
901 | else | |
902 | { | |
903 | inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf)); | |
904 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
905 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
906 | } | |
907 | #endif /* HAVE_IPV6 */ | |
7b3eaa99 DS |
908 | if (zvrf->vrf_id != VRF_DEFAULT) |
909 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_VRF_NAME_FIELD, | |
910 | zvrf->name); | |
c43ed2e4 DS |
911 | } |
912 | else | |
913 | { | |
914 | #ifdef HAVE_IPV6 | |
915 | if (dst_p.family == AF_INET6) | |
916 | { | |
917 | src_p.family = stream_getw(s); | |
918 | ||
919 | if (src_p.family == AF_INET) | |
920 | src_p.prefixlen = IPV4_MAX_BYTELEN; | |
921 | else | |
922 | src_p.prefixlen = IPV6_MAX_BYTELEN; | |
923 | ||
924 | stream_get(&src_p.u.prefix, s, src_p.prefixlen); | |
925 | if (src_p.family == AF_INET) | |
926 | { | |
927 | inet_ntop(AF_INET, &src_p.u.prefix4, buf, sizeof(buf)); | |
928 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
929 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
930 | } | |
931 | else | |
932 | { | |
933 | inet_ntop(AF_INET6, &src_p.u.prefix6, buf, sizeof(buf)); | |
934 | ptm_lib_append_msg(ptm_hdl, out_ctxt, | |
935 | ZEBRA_PTM_BFD_SRC_IP_FIELD, buf); | |
936 | } | |
937 | } | |
938 | #endif /* HAVE_IPV6 */ | |
939 | ||
940 | len = stream_getc(s); | |
941 | stream_get(if_name, s, len); | |
942 | if_name[len] = '\0'; | |
943 | ||
944 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_IFNAME_FIELD, | |
945 | if_name); | |
946 | } | |
c01acf98 | 947 | |
c8ed14dd DS |
948 | ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len); |
949 | if (IS_ZEBRA_DEBUG_SEND) | |
950 | zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, | |
951 | ptm_cb.out_data); | |
952 | ||
953 | zebra_ptm_send_message(ptm_cb.out_data, data_len); | |
c01acf98 DS |
954 | return 0; |
955 | } | |
c8ed14dd | 956 | |
055c4dfc | 957 | /* BFD client register */ |
958 | int | |
959 | zebra_ptm_bfd_client_register (struct zserv *client, int sock, u_short length) | |
960 | { | |
961 | struct stream *s; | |
962 | unsigned int pid; | |
963 | void *out_ctxt; | |
964 | char tmp_buf[64]; | |
965 | int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; | |
966 | ||
967 | client->bfd_client_reg_cnt++; | |
968 | ||
969 | if (IS_ZEBRA_DEBUG_EVENT) | |
970 | zlog_debug("bfd_client_register msg from client %s: length=%d", | |
971 | zebra_route_string(client->proto), length); | |
972 | ||
973 | if (ptm_cb.ptm_sock == -1) | |
974 | { | |
975 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, | |
976 | NULL, ptm_cb.reconnect_time); | |
977 | return -1; | |
978 | } | |
979 | ||
980 | ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); | |
981 | ||
982 | sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_REG_CMD); | |
983 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf); | |
984 | ||
985 | sprintf(tmp_buf, "%s", zebra_route_string(client->proto)); | |
986 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, | |
987 | tmp_buf); | |
988 | ||
989 | s = client->ibuf; | |
990 | ||
991 | pid = stream_getl(s); | |
992 | sprintf(tmp_buf, "%d", pid); | |
993 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_SEQID_FIELD, | |
994 | tmp_buf); | |
995 | ||
996 | ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len); | |
997 | ||
998 | if (IS_ZEBRA_DEBUG_SEND) | |
999 | zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, | |
1000 | ptm_cb.out_data); | |
1001 | zebra_ptm_send_message(ptm_cb.out_data, data_len); | |
1002 | return 0; | |
1003 | } | |
1004 | ||
567b877d | 1005 | /* BFD client deregister */ |
1006 | void | |
1007 | zebra_ptm_bfd_client_deregister (struct zserv *client) | |
1008 | { | |
1009 | void *out_ctxt; | |
1010 | char tmp_buf[64]; | |
1011 | int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF; | |
1012 | ||
1013 | if (client->proto != ZEBRA_ROUTE_OSPF && client->proto != ZEBRA_ROUTE_BGP | |
1014 | && client->proto != ZEBRA_ROUTE_OSPF6) | |
1015 | return; | |
1016 | ||
1017 | if (IS_ZEBRA_DEBUG_EVENT) | |
1018 | zlog_debug("bfd_client_deregister msg for client %s", | |
1019 | zebra_route_string(client->proto)); | |
1020 | ||
1021 | if (ptm_cb.ptm_sock == -1) | |
1022 | { | |
1023 | ptm_cb.t_timer = thread_add_timer (zebrad.master, zebra_ptm_connect, | |
1024 | NULL, ptm_cb.reconnect_time); | |
1025 | return; | |
1026 | } | |
1027 | ||
1028 | ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); | |
1029 | ||
1030 | sprintf(tmp_buf, "%s", ZEBRA_PTM_BFD_CLIENT_DEREG_CMD); | |
1031 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, tmp_buf); | |
1032 | ||
1033 | sprintf(tmp_buf, "%s", zebra_route_string(client->proto)); | |
1034 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_BFD_CLIENT_FIELD, | |
1035 | tmp_buf); | |
1036 | ||
1037 | ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &data_len); | |
1038 | ||
1039 | if (IS_ZEBRA_DEBUG_SEND) | |
1040 | zlog_debug ("%s: Sent message (%d) %s", __func__, data_len, | |
1041 | ptm_cb.out_data); | |
1042 | zebra_ptm_send_message(ptm_cb.out_data, data_len); | |
1043 | } | |
1044 | ||
c8ed14dd DS |
1045 | int |
1046 | zebra_ptm_get_enable_state(void) | |
1047 | { | |
1048 | return ptm_cb.ptm_enable; | |
1049 | } | |
950bd436 | 1050 | |
1051 | /* | |
1052 | * zebra_ptm_get_status_str - Convert status to a display string. | |
1053 | */ | |
1054 | static const char * | |
1055 | zebra_ptm_get_status_str(int status) | |
1056 | { | |
1057 | switch (status) | |
1058 | { | |
1059 | case ZEBRA_PTM_STATUS_DOWN: | |
1060 | return "fail"; | |
1061 | case ZEBRA_PTM_STATUS_UP: | |
1062 | return "pass"; | |
1063 | case ZEBRA_PTM_STATUS_UNKNOWN: | |
1064 | default: | |
1065 | return "n/a"; | |
1066 | } | |
1067 | } | |
1068 | ||
1069 | void | |
1070 | zebra_ptm_show_status(struct vty *vty, struct interface *ifp) | |
1071 | { | |
1072 | vty_out (vty, " PTM status: "); | |
1073 | if (ifp->ptm_enable) { | |
1074 | vty_out (vty, "%s%s", zebra_ptm_get_status_str (ifp->ptm_status), | |
1075 | VTY_NEWLINE); | |
1076 | } else { | |
1077 | vty_out (vty, "disabled%s", VTY_NEWLINE); | |
1078 | } | |
1079 | } | |
1080 | ||
1081 | void | |
1082 | zebra_ptm_send_status_req(void) | |
1083 | { | |
1084 | void *out_ctxt; | |
1085 | int len = ZEBRA_PTM_SEND_MAX_SOCKBUF; | |
1086 | ||
1087 | if (ptm_cb.ptm_enable) | |
1088 | { | |
1089 | ptm_lib_init_msg(ptm_hdl, 0, PTMLIB_MSG_TYPE_CMD, NULL, &out_ctxt); | |
1090 | ptm_lib_append_msg(ptm_hdl, out_ctxt, ZEBRA_PTM_CMD_STR, | |
1091 | ZEBRA_PTM_GET_STATUS_CMD); | |
1092 | ptm_lib_complete_msg(ptm_hdl, out_ctxt, ptm_cb.out_data, &len); | |
1093 | ||
1094 | zebra_ptm_send_message(ptm_cb.out_data, len); | |
1095 | } | |
1096 | } | |
1097 | ||
1098 | void | |
1099 | zebra_ptm_reset_status(int ptm_disable) | |
1100 | { | |
1101 | struct listnode *i; | |
1102 | struct interface *ifp; | |
1103 | int send_linkup; | |
b2d7c082 | 1104 | vrf_iter_t iter; |
950bd436 | 1105 | |
b2d7c082 DS |
1106 | for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) |
1107 | for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), i, ifp)) | |
1108 | { | |
1109 | send_linkup = 0; | |
1110 | if (ifp->ptm_enable) | |
986aa00f | 1111 | { |
1112 | if (!if_is_operative(ifp)) | |
1113 | send_linkup = 1; | |
b2d7c082 DS |
1114 | |
1115 | if (ptm_disable) | |
986aa00f | 1116 | ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; |
b2d7c082 DS |
1117 | ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; |
1118 | ||
986aa00f | 1119 | if (if_is_operative (ifp) && send_linkup) |
1120 | { | |
1121 | if (IS_ZEBRA_DEBUG_EVENT) | |
1122 | zlog_debug ("%s: Bringing up interface %s", __func__, | |
1123 | ifp->name); | |
1124 | if_up (ifp); | |
b2d7c082 DS |
1125 | } |
1126 | } | |
1127 | } | |
950bd436 | 1128 | } |
986aa00f | 1129 | |
1130 | void | |
1131 | zebra_ptm_if_init(struct zebra_if *zebra_ifp) | |
1132 | { | |
1133 | zebra_ifp->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC; | |
1134 | } | |
1135 | ||
1136 | void | |
1137 | zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp) | |
1138 | { | |
1139 | if (zebra_ifp && zebra_ifp->ptm_enable != ZEBRA_IF_PTM_ENABLE_UNSPEC) | |
1140 | ifp->ptm_enable = zebra_ifp->ptm_enable; | |
1141 | } | |
1142 | ||
1143 | void | |
1144 | zebra_ptm_if_write (struct vty *vty, struct zebra_if *zebra_ifp) | |
1145 | { | |
1146 | if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF) | |
1147 | vty_out (vty, " no ptm-enable%s", VTY_NEWLINE); | |
1148 | } |