]>
Commit | Line | Data |
---|---|---|
7f342629 DS |
1 | /** |
2 | * bfd.c: BFD handling routines | |
3 | * | |
4 | * @copyright Copyright (C) 2015 Cumulus Networks, Inc. | |
5 | * | |
6 | * This file is part of GNU Zebra. | |
7 | * | |
8 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2, or (at your option) any | |
11 | * later version. | |
12 | * | |
13 | * GNU Zebra is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
20 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
21 | * 02111-1307, USA. | |
22 | */ | |
23 | ||
24 | #include <zebra.h> | |
25 | ||
26 | #include "command.h" | |
27 | #include "memory.h" | |
28 | #include "prefix.h" | |
29 | #include "thread.h" | |
30 | #include "stream.h" | |
31 | #include "zclient.h" | |
32 | #include "table.h" | |
33 | #include "vty.h" | |
34 | #include "bfd.h" | |
35 | ||
36 | /* | |
37 | * bfd_info_create - Allocate the BFD information | |
38 | */ | |
39 | struct bfd_info * | |
40 | bfd_info_create(void) | |
41 | { | |
42 | struct bfd_info *bfd_info; | |
43 | ||
44 | bfd_info = XCALLOC (MTYPE_BFD_INFO, sizeof (struct bfd_info)); | |
45 | assert(bfd_info); | |
46 | ||
47 | return bfd_info; | |
48 | } | |
49 | ||
50 | /* | |
51 | * bfd_info_free - Free the BFD information. | |
52 | */ | |
53 | void | |
54 | bfd_info_free(void **bfd_info) | |
55 | { | |
56 | if (*bfd_info) | |
57 | { | |
58 | XFREE (MTYPE_BFD_INFO, *bfd_info); | |
59 | *bfd_info = NULL; | |
60 | } | |
61 | } | |
62 | ||
63 | /* | |
64 | * bfd_validate_param - Validate the BFD paramter information. | |
65 | */ | |
66 | int | |
67 | bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str, | |
68 | const char *tx_str, u_int8_t *dm_val, u_int32_t *rx_val, | |
69 | u_int32_t *tx_val) | |
70 | { | |
71 | VTY_GET_INTEGER_RANGE ("detect-mul", *dm_val, dm_str, | |
72 | BFD_MIN_DETECT_MULT, BFD_MAX_DETECT_MULT); | |
73 | VTY_GET_INTEGER_RANGE ("min-rx", *rx_val, rx_str, | |
74 | BFD_MIN_MIN_RX, BFD_MAX_MIN_RX); | |
75 | VTY_GET_INTEGER_RANGE ("min-tx", *tx_val, tx_str, | |
76 | BFD_MIN_MIN_TX, BFD_MAX_MIN_TX); | |
77 | return CMD_SUCCESS; | |
78 | } | |
79 | ||
80 | /* | |
81 | * bfd_set_param - Set the configured BFD paramter values | |
82 | */ | |
83 | void | |
84 | bfd_set_param (struct bfd_info **bfd_info, u_int32_t min_rx, u_int32_t min_tx, | |
85 | u_int8_t detect_mult, int defaults, int *command) | |
86 | { | |
87 | if (!*bfd_info) | |
88 | { | |
89 | *bfd_info = bfd_info_create(); | |
90 | *command = ZEBRA_BFD_DEST_REGISTER; | |
91 | } | |
92 | else | |
93 | { | |
94 | if (((*bfd_info)->required_min_rx != min_rx) || | |
95 | ((*bfd_info)->desired_min_tx != min_tx) || | |
96 | ((*bfd_info)->detect_mult != detect_mult)) | |
97 | *command = ZEBRA_BFD_DEST_UPDATE; | |
98 | } | |
99 | ||
100 | if (*command) | |
101 | { | |
102 | (*bfd_info)->required_min_rx = min_rx; | |
103 | (*bfd_info)->desired_min_tx = min_tx; | |
104 | (*bfd_info)->detect_mult = detect_mult; | |
105 | } | |
106 | ||
107 | if (!defaults) | |
108 | SET_FLAG ((*bfd_info)->flags, BFD_FLAG_PARAM_CFG); | |
109 | else | |
110 | UNSET_FLAG ((*bfd_info)->flags, BFD_FLAG_PARAM_CFG); | |
111 | } | |
112 | ||
113 | /* | |
114 | * bfd_peer_sendmsg - Format and send a peer register/Unregister | |
115 | * command to Zebra to be forwarded to BFD | |
116 | */ | |
117 | void | |
118 | bfd_peer_sendmsg (struct zclient *zclient, struct bfd_info *bfd_info, | |
119 | int family, void *dst_ip, void *src_ip, char *if_name, | |
120 | int ttl, int multihop, int command, int set_flag) | |
121 | { | |
122 | struct stream *s; | |
123 | int ret; | |
124 | int len; | |
125 | ||
126 | /* Check socket. */ | |
127 | if (!zclient || zclient->sock < 0) | |
128 | { | |
129 | zlog_debug("%s: Can't send BFD peer register, Zebra client not " | |
130 | "established", __FUNCTION__); | |
131 | return; | |
132 | } | |
133 | ||
134 | s = zclient->obuf; | |
135 | stream_reset (s); | |
136 | zclient_create_header (s, command); | |
137 | ||
138 | stream_putw(s, family); | |
139 | switch (family) | |
140 | { | |
141 | case AF_INET: | |
142 | stream_put_in_addr (s, (struct in_addr *)dst_ip); | |
143 | break; | |
144 | #ifdef HAVE_IPV6 | |
145 | case AF_INET6: | |
146 | stream_put(s, dst_ip, 16); | |
147 | break; | |
148 | #endif | |
149 | default: | |
150 | break; | |
151 | } | |
152 | ||
153 | if (command != ZEBRA_BFD_DEST_DEREGISTER) | |
154 | { | |
155 | stream_putl(s, bfd_info->required_min_rx); | |
156 | stream_putl(s, bfd_info->desired_min_tx); | |
157 | stream_putc(s, bfd_info->detect_mult); | |
158 | } | |
159 | ||
160 | if (multihop) | |
161 | { | |
162 | stream_putc(s, 1); | |
163 | /* Multi-hop destination send the source IP address to BFD */ | |
164 | if (src_ip) | |
165 | { | |
166 | stream_putw(s, family); | |
167 | switch (family) | |
168 | { | |
169 | case AF_INET: | |
170 | stream_put_in_addr (s, (struct in_addr *) src_ip); | |
171 | break; | |
172 | #ifdef HAVE_IPV6 | |
173 | case AF_INET6: | |
174 | stream_put(s, src_ip, 16); | |
175 | break; | |
176 | #endif | |
177 | default: | |
178 | break; | |
179 | } | |
180 | } | |
181 | stream_putc(s, ttl); | |
182 | } | |
183 | else | |
184 | { | |
185 | stream_putc(s, 0); | |
186 | #ifdef HAVE_IPV6 | |
187 | if ((family == AF_INET6) && (src_ip)) | |
188 | { | |
189 | stream_putw(s, family); | |
190 | stream_put(s, src_ip, 16); | |
191 | } | |
192 | #endif | |
193 | if (if_name) | |
194 | { | |
195 | len = strlen(if_name); | |
196 | stream_putc(s, len); | |
197 | stream_put(s, if_name, len); | |
198 | } | |
199 | else | |
200 | { | |
201 | stream_putc(s, 0); | |
202 | } | |
203 | } | |
204 | ||
205 | stream_putw_at (s, 0, stream_get_endp (s)); | |
206 | ||
207 | ret = zclient_send_message(zclient); | |
208 | ||
209 | if (ret < 0) | |
210 | { | |
211 | zlog_warn("bfd_peer_sendmsg: zclient_send_message() failed"); | |
212 | return; | |
213 | } | |
214 | ||
215 | if (set_flag) | |
216 | { | |
217 | if (command == ZEBRA_BFD_DEST_REGISTER) | |
218 | SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG); | |
219 | else if (command == ZEBRA_BFD_DEST_DEREGISTER) | |
220 | UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG); | |
221 | } | |
222 | ||
223 | return; | |
224 | } | |
225 | ||
226 | /* | |
227 | * bfd_get_command_dbg_str - Convert command to a debug string. | |
228 | */ | |
229 | const char * | |
230 | bfd_get_command_dbg_str(int command) | |
231 | { | |
232 | switch (command) | |
233 | { | |
234 | case ZEBRA_BFD_DEST_REGISTER: | |
235 | return "Register"; | |
236 | case ZEBRA_BFD_DEST_DEREGISTER: | |
237 | return "Deregister"; | |
238 | case ZEBRA_BFD_DEST_UPDATE: | |
239 | return "Update"; | |
240 | default: | |
241 | return "Unknown"; | |
242 | } | |
243 | } | |
244 | ||
245 | /* | |
246 | * bfd_get_peer_info - Extract the Peer information for which the BFD session | |
247 | * went down from the message sent from Zebra to clients. | |
248 | */ | |
249 | struct interface * | |
250 | bfd_get_peer_info (struct stream *s, struct prefix *dp, struct prefix *sp) | |
251 | { | |
252 | unsigned int ifindex; | |
253 | struct interface *ifp = NULL; | |
254 | int plen; | |
255 | ||
256 | /* Get interface index. */ | |
257 | ifindex = stream_getl (s); | |
258 | ||
259 | /* Lookup index. */ | |
260 | if (ifindex != 0) | |
261 | { | |
262 | ifp = if_lookup_by_index (ifindex); | |
263 | if (ifp == NULL) | |
264 | { | |
265 | zlog_warn ("zebra_interface_bfd_read: " | |
266 | "Can't find interface by ifindex: %d ", ifindex); | |
267 | return NULL; | |
268 | } | |
269 | } | |
270 | ||
271 | /* Fetch destination address. */ | |
272 | dp->family = stream_getc (s); | |
273 | ||
274 | plen = prefix_blen (dp); | |
275 | stream_get (&dp->u.prefix, s, plen); | |
276 | dp->prefixlen = stream_getc (s); | |
277 | ||
278 | if (sp) | |
279 | { | |
280 | sp->family = stream_getc (s); | |
281 | ||
282 | plen = prefix_blen (sp); | |
283 | stream_get (&sp->u.prefix, s, plen); | |
284 | sp->prefixlen = stream_getc (s); | |
285 | } | |
286 | return ifp; | |
287 | } |