]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_flowspec_util.c
bgpd: support for json in show bgp ipv4 flowspec commands
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
CommitLineData
034cdee9
PG
1/* BGP FlowSpec Utilities
2 * Portions:
3 * Copyright (C) 2017 ChinaTelecom SDN Group
4 * Copyright (C) 2018 6WIND
5 *
6 * FRRouting 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 * FRRouting 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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "zebra.h"
22
23#include "prefix.h"
24#include "bgp_flowspec_util.h"
25
26static void hex2bin(uint8_t *hex, int *bin)
27{
28 int remainder = *hex;
29 int i = 0;
30
31 while (remainder >= 1 && i < 8) {
32 bin[7-i] = remainder % 2;
33 remainder = remainder / 2;
34 i++;
35 }
36 for (; i < 8; i++)
37 bin[7-i] = 0;
38}
39
40static int hexstr2num(uint8_t *hexstr, int len)
41{
42 int i = 0;
43 int num = 0;
44
45 for (i = 0; i < len; i++)
46 num = hexstr[i] + 16*16*num;
47 return num;
48}
49
50
51/*
52 * handle the flowspec address src/dst or generic address NLRI
53 * return number of bytes analysed ( >= 0).
54 */
55int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
56 uint8_t *nlri_ptr,
57 uint32_t max_len,
58 void *result, int *error)
59{
60 char *display = (char *)result; /* for return_string */
61 struct prefix *prefix = (struct prefix *)result;
62 uint32_t offset = 0;
63 struct prefix prefix_local;
64 int psize;
65
66 *error = 0;
67 memset(&prefix_local, 0, sizeof(struct prefix));
68 /* read the prefix length */
69 prefix_local.prefixlen = nlri_ptr[offset];
70 psize = PSIZE(prefix_local.prefixlen);
71 offset++;
72 /* TODO Flowspec IPv6 Support */
73 prefix_local.family = AF_INET;
74 /* Prefix length check. */
75 if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
76 *error = -1;
77 /* When packet overflow occur return immediately. */
78 if (psize + offset > max_len)
79 *error = -1;
80 /* Defensive coding, double-check
81 * the psize fits in a struct prefix
82 */
83 if (psize > (ssize_t)sizeof(prefix_local.u))
84 *error = -1;
85 memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
86 offset += psize;
87 switch (type) {
88 case BGP_FLOWSPEC_RETURN_STRING:
89 prefix2str(&prefix_local, display,
90 BGP_FLOWSPEC_STRING_DISPLAY_MAX);
91 break;
92 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
93 PREFIX_COPY_IPV4(prefix, &prefix_local)
94 break;
95 case BGP_FLOWSPEC_VALIDATE_ONLY:
96 default:
97 break;
98 }
99 return offset;
100}
101
102/*
103 * handle the flowspec operator NLRI
104 * return number of bytes analysed
105 * if there is an error, the passed error param is used to give error:
106 * -1 if decoding error,
107 */
108int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
109 uint8_t *nlri_ptr,
110 uint32_t max_len,
111 void *result, int *error)
112{
113 int op[8];
114 int len, value, value_size;
115 int loop = 0;
116 char *ptr = (char *)result; /* for return_string */
117 uint32_t offset = 0;
118
119 *error = 0;
120 do {
121 hex2bin(&nlri_ptr[offset], op);
122 offset++;
123 len = 2*op[2]+op[3];
124 value_size = 1 << len;
125 value = hexstr2num(&nlri_ptr[offset], value_size);
126 /* can not be < and > at the same time */
127 if (op[5] == 1 && op[6] == 1)
128 *error = -1;
129 /* if first element, AND bit can not be set */
130 if (op[1] == 1 && loop == 0)
131 *error = -1;
132 switch (type) {
133 case BGP_FLOWSPEC_RETURN_STRING:
134 if (loop)
135 ptr += sprintf(ptr, ", ");
136 if (op[5] == 1)
137 ptr += sprintf(ptr, "<");
138 if (op[6] == 1)
139 ptr += sprintf(ptr, ">");
140 if (op[7] == 1)
141 ptr += sprintf(ptr, "=");
142 ptr += sprintf(ptr, " %d ", value);
143 break;
144 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
145 /* TODO : FS OPAQUE */
146 break;
147 case BGP_FLOWSPEC_VALIDATE_ONLY:
148 default:
149 /* no action */
150 break;
151 }
152 offset += value_size;
153 loop++;
154 } while (op[0] == 0 && offset < max_len - 1);
155 if (offset > max_len)
156 *error = -1;
157 /* use error parameter to count the number of entries */
158 if (*error == 0)
159 *error = loop;
160 return offset;
161}
162
163
164/*
165 * handle the flowspec tcpflags field
166 * return number of bytes analysed
167 * if there is an error, the passed error param is used to give error:
168 * -1 if decoding error,
169 */
170int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
171 uint8_t *nlri_ptr,
172 uint32_t max_len,
173 void *result, int *error)
174{
175 int op[8];
176 int len, value_size, loop = 0, value;
177 char *ptr = (char *)result; /* for return_string */
178 uint32_t offset = 0;
179
180 *error = 0;
181 do {
182 hex2bin(&nlri_ptr[offset], op);
183 /* if first element, AND bit can not be set */
184 if (op[1] == 1 && loop == 0)
185 *error = -1;
186 offset++;
187 len = 2 * op[2] + op[3];
188 value_size = 1 << len;
189 value = hexstr2num(&nlri_ptr[offset], value_size);
190 switch (type) {
191 case BGP_FLOWSPEC_RETURN_STRING:
192 if (op[1] == 1 && loop != 0)
193 ptr += sprintf(ptr, ", and ");
194 else if (op[1] == 0 && loop != 0)
195 ptr += sprintf(ptr, ", or ");
196 ptr += sprintf(ptr, "tcp flags is ");
197 if (op[6] == 1)
198 ptr += sprintf(ptr, "not ");
199 if (op[7] == 1)
200 ptr += sprintf(ptr, "exactly match ");
201 ptr += sprintf(ptr, "%d", value);
202 break;
203 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
204 /* TODO : FS OPAQUE */
205 break;
206 case BGP_FLOWSPEC_VALIDATE_ONLY:
207 default:
208 /* no action */
209 break;
210 }
211 offset += value_size;
212 loop++;
213 } while (op[0] == 0 && offset < max_len - 1);
214 if (offset > max_len)
215 *error = -1;
216 /* use error parameter to count the number of entries */
217 if (*error == 0)
218 *error = loop;
219 return offset;
220}
221
222/*
223 * handle the flowspec fragment type field
224 * return error (returned values are invalid) or number of bytes analysed
225 * -1 if error in decoding
226 * >= 0 : number of bytes analysed (ok).
227 */
228int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
229 uint8_t *nlri_ptr,
230 uint32_t max_len,
231 void *result, int *error)
232{
233 int op[8];
234 int len, value, value_size, loop = 0;
235 char *ptr = (char *)result; /* for return_string */
236 uint32_t offset = 0;
237
238 *error = 0;
239 do {
240 hex2bin(&nlri_ptr[offset], op);
241 offset++;
242 len = 2 * op[2] + op[3];
243 value_size = 1 << len;
244 value = hexstr2num(&nlri_ptr[offset], value_size);
245 if (value != 1 && value != 2 && value != 4 && value != 8)
246 *error = -1;
247 offset += value_size;
248 /* TODO : as per RFC5574 : first Fragment bits are Reserved
249 * does that mean that it is not possible
250 * to handle multiple occurences ?
251 * as of today, we only grab the first TCP fragment
252 */
253 if (loop) {
254 *error = -2;
255 loop++;
256 continue;
257 }
258 switch (type) {
259 case BGP_FLOWSPEC_RETURN_STRING:
260 switch (value) {
261 case 1:
262 ptr += sprintf(ptr, "dont-fragment");
263 break;
264 case 2:
265 ptr += sprintf(ptr, "is-fragment");
266 break;
267 case 4:
268 ptr += sprintf(ptr, "first-fragment");
269 break;
270 case 8:
271 ptr += sprintf(ptr, "last-fragment");
272 break;
273 default:
274 {}
275 }
276 break;
277 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
278 /* TODO : FS OPAQUE */
279 break;
280 case BGP_FLOWSPEC_VALIDATE_ONLY:
281 default:
282 /* no action */
283 break;
284 }
285 loop++;
286 } while (op[0] == 0 && offset < max_len - 1);
287 if (offset > max_len)
288 *error = -1;
289 return offset;
290}