blob: 13a209fb6847fe4f99efea7db5ee851c0895a203 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 * ethernet_format.c: ethernet formatting/parsing.
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40#include <vlib/vlib.h>
41#include <vnet/ethernet/ethernet.h>
42
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070043u8 *
44format_ethernet_address (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070045{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070046 ethernet_main_t *em = &ethernet_main;
47 u8 *a = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
49 if (em->format_ethernet_address_16bit)
50 return format (s, "%02x%02x.%02x%02x.%02x%02x",
51 a[0], a[1], a[2], a[3], a[4], a[5]);
52 else
53 return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
54 a[0], a[1], a[2], a[3], a[4], a[5]);
55}
56
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070057u8 *
58format_ethernet_type (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070059{
60 ethernet_type_t type = va_arg (*args, u32);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070061 ethernet_main_t *em = &ethernet_main;
62 ethernet_type_info_t *t = ethernet_get_type_info (em, type);
Ed Warnickecb9cada2015-12-08 15:45:58 -070063
64 if (t)
65 s = format (s, "%s", t->name);
66 else
67 s = format (s, "0x%04x", type);
68
69 return s;
70}
71
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070072u8 *
73format_ethernet_vlan_tci (u8 * s, va_list * va)
marek zavodskyad2c9c02016-07-07 03:16:10 +020074{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070075 u32 vlan_tci = va_arg (*va, u32);
marek zavodskyad2c9c02016-07-07 03:16:10 +020076
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070077 u32 vid = (vlan_tci & 0xfff);
78 u32 cfi = (vlan_tci >> 12) & 1;
79 u32 pri = (vlan_tci >> 13);
marek zavodskyad2c9c02016-07-07 03:16:10 +020080
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070081 s = format (s, "%d", vid);
82 if (pri != 0)
83 s = format (s, " priority %d", pri);
84 if (cfi != 0)
85 s = format (s, " cfi");
marek zavodskyad2c9c02016-07-07 03:16:10 +020086
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070087 return s;
marek zavodskyad2c9c02016-07-07 03:16:10 +020088}
89
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070090u8 *
91format_ethernet_header_with_length (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070092{
Pavel Kotucek95300d12016-08-26 16:11:36 +020093 ethernet_pbb_header_packed_t *ph =
94 va_arg (*args, ethernet_pbb_header_packed_t *);
95 ethernet_max_header_t *m = (ethernet_max_header_t *) ph;
Ed Warnickecb9cada2015-12-08 15:45:58 -070096 u32 max_header_bytes = va_arg (*args, u32);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -070097 ethernet_main_t *em = &ethernet_main;
98 ethernet_header_t *e = &m->ethernet;
99 ethernet_vlan_header_t *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100 ethernet_type_t type = clib_net_to_host_u16 (e->type);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700101 ethernet_type_t vlan_type[ARRAY_LEN (m->vlan)];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102 u32 n_vlan = 0, i, header_bytes;
Christophe Fontained3c008d2017-10-02 18:10:54 +0200103 u32 indent;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104
Pavel Kotucek95300d12016-08-26 16:11:36 +0200105 while ((type == ETHERNET_TYPE_VLAN || type == ETHERNET_TYPE_DOT1AD
106 || type == ETHERNET_TYPE_DOT1AH) && n_vlan < ARRAY_LEN (m->vlan))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107 {
marek zavodskyad2c9c02016-07-07 03:16:10 +0200108 vlan_type[n_vlan] = type;
Pavel Kotucek95300d12016-08-26 16:11:36 +0200109 if (type != ETHERNET_TYPE_DOT1AH)
110 {
111 v = m->vlan + n_vlan;
112 type = clib_net_to_host_u16 (v->type);
113 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114 n_vlan++;
115 }
116
117 header_bytes = sizeof (e[0]) + n_vlan * sizeof (v[0]);
118 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
119 return format (s, "ethernet header truncated");
120
121 indent = format_get_indent (s);
122
123 s = format (s, "%U: %U -> %U",
124 format_ethernet_type, type,
125 format_ethernet_address, e->src_address,
126 format_ethernet_address, e->dst_address);
127
Pavel Kotucek95300d12016-08-26 16:11:36 +0200128 if (type != ETHERNET_TYPE_DOT1AH)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129 {
Pavel Kotucek95300d12016-08-26 16:11:36 +0200130 for (i = 0; i < n_vlan; i++)
131 {
132 u32 v = clib_net_to_host_u16 (m->vlan[i].priority_cfi_and_id);
133 if (*vlan_type == ETHERNET_TYPE_VLAN)
134 s = format (s, " 802.1q vlan %U", format_ethernet_vlan_tci, v);
135 else
136 s = format (s, " 802.1ad vlan %U", format_ethernet_vlan_tci, v);
137 }
138
139 if (max_header_bytes != 0 && header_bytes < max_header_bytes)
140 {
141 ethernet_type_info_t *ti;
142 vlib_node_t *node = 0;
143
144 ti = ethernet_get_type_info (em, type);
145 if (ti && ti->node_index != ~0)
146 node = vlib_get_node (em->vlib_main, ti->node_index);
147 if (node && node->format_buffer)
148 s = format (s, "\n%U%U",
149 format_white_space, indent,
150 node->format_buffer, (void *) m + header_bytes,
151 max_header_bytes - header_bytes);
152 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 }
Pavel Kotucek95300d12016-08-26 16:11:36 +0200154 else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155 {
Pavel Kotucek65e84572017-01-16 17:01:56 +0100156 s =
157 format (s, " %s b-tag %04X",
158 (clib_net_to_host_u16 (ph->b_type) ==
159 ETHERNET_TYPE_DOT1AD) ? "802.1ad" : "",
160 clib_net_to_host_u16 (ph->priority_dei_id));
161 s =
162 format (s, " %s i-tag %08X",
163 (clib_net_to_host_u16 (ph->i_type) ==
164 ETHERNET_TYPE_DOT1AH) ? "802.1ah" : "",
165 clib_net_to_host_u32 (ph->priority_dei_uca_res_sid));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 }
167
168 return s;
169}
170
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700171u8 *
172format_ethernet_header (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700174 ethernet_max_header_t *m = va_arg (*args, ethernet_max_header_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175 return format (s, "%U", format_ethernet_header_with_length, m, 0);
176}
177
178/* Parse X:X:X:X:X:X unix style ethernet address. */
179static uword
180unformat_ethernet_address_unix (unformat_input_t * input, va_list * args)
181{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700182 u8 *result = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 u32 i, a[6];
184
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700185 if (!unformat (input, "%_%x:%x:%x:%x:%x:%x%_",
186 &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 return 0;
188
189 /* Check range. */
190 for (i = 0; i < ARRAY_LEN (a); i++)
191 if (a[i] >= (1 << 8))
192 return 0;
193
194 for (i = 0; i < ARRAY_LEN (a); i++)
195 result[i] = a[i];
196
197 return 1;
198}
199
200/* Parse X.X.X cisco style ethernet address. */
201static uword
202unformat_ethernet_address_cisco (unformat_input_t * input, va_list * args)
203{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700204 u8 *result = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 u32 i, a[3];
206
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700207 if (!unformat (input, "%_%x.%x.%x%_", &a[0], &a[1], &a[2]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208 return 0;
209
210 /* Check range. */
211 for (i = 0; i < ARRAY_LEN (a); i++)
212 if (a[i] >= (1 << 16))
213 return 0;
214
215 result[0] = (a[0] >> 8) & 0xff;
216 result[1] = (a[0] >> 0) & 0xff;
217 result[2] = (a[1] >> 8) & 0xff;
218 result[3] = (a[1] >> 0) & 0xff;
219 result[4] = (a[2] >> 8) & 0xff;
220 result[5] = (a[2] >> 0) & 0xff;
221
222 return 1;
223}
224
225/* Parse ethernet address; accept either unix or style addresses. */
226uword
227unformat_ethernet_address (unformat_input_t * input, va_list * args)
228{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700229 u8 *result = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230 return (unformat_user (input, unformat_ethernet_address_unix, result)
231 || unformat_user (input, unformat_ethernet_address_cisco, result));
232}
233
234/* Returns ethernet type as an int in host byte order. */
235uword
236unformat_ethernet_type_host_byte_order (unformat_input_t * input,
237 va_list * args)
238{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700239 u16 *result = va_arg (*args, u16 *);
240 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 int type, i;
242
243 /* Numeric type. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700244 if (unformat (input, "0x%x", &type) || unformat (input, "%d", &type))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 {
246 if (type >= (1 << 16))
247 return 0;
248 *result = type;
249 return 1;
250 }
251
252 /* Named type. */
253 if (unformat_user (input, unformat_vlib_number_by_name,
254 em->type_info_by_name, &i))
255 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700256 ethernet_type_info_t *ti = vec_elt_at_index (em->type_infos, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 *result = ti->type;
258 return 1;
259 }
260
261 return 0;
262}
263
264uword
265unformat_ethernet_type_net_byte_order (unformat_input_t * input,
266 va_list * args)
267{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700268 u16 *result = va_arg (*args, u16 *);
269 if (!unformat_user (input, unformat_ethernet_type_host_byte_order, result))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 return 0;
271
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700272 *result = clib_host_to_net_u16 ((u16) * result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273 return 1;
274}
275
276uword
277unformat_ethernet_header (unformat_input_t * input, va_list * args)
278{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700279 u8 **result = va_arg (*args, u8 **);
280 ethernet_max_header_t _m, *m = &_m;
281 ethernet_header_t *e = &m->ethernet;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700282 u16 type;
283 u32 n_vlan;
284
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700285 if (!unformat (input, "%U: %U -> %U",
286 unformat_ethernet_type_host_byte_order, &type,
287 unformat_ethernet_address, &e->src_address,
288 unformat_ethernet_address, &e->dst_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289 return 0;
290
291 n_vlan = 0;
292 while (unformat (input, "vlan"))
293 {
294 u32 id, priority;
295
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700296 if (!unformat_user (input, unformat_vlib_number, &id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 || id >= ETHERNET_N_VLAN)
298 return 0;
299
300 if (unformat (input, "priority %d", &priority))
301 {
302 if (priority >= 8)
303 return 0;
304 id |= priority << 13;
305 }
306
307 if (unformat (input, "cfi"))
308 id |= 1 << 12;
309
310 /* Too many vlans given. */
311 if (n_vlan >= ARRAY_LEN (m->vlan))
312 return 0;
313
314 m->vlan[n_vlan].priority_cfi_and_id = clib_host_to_net_u16 (id);
315 n_vlan++;
316 }
317
318 if (n_vlan == 0)
319 e->type = clib_host_to_net_u16 (type);
320 else
321 {
322 int i;
323
324 e->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
325 for (i = 0; i < n_vlan - 1; i++)
326 m->vlan[i].type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
327 m->vlan[n_vlan - 1].type = clib_host_to_net_u16 (type);
328 }
329
330 /* Add header to result. */
331 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700332 void *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333 u32 n_bytes = sizeof (e[0]) + n_vlan * sizeof (m->vlan[0]);
334
335 vec_add2 (*result, p, n_bytes);
Damjan Marionf1213b82016-03-13 02:22:06 +0100336 clib_memcpy (p, m, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700338
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339 return 1;
340}
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700341
342/*
343 * fd.io coding-style-patch-verification: ON
344 *
345 * Local Variables:
346 * eval: (c-set-style "gnu")
347 * End:
348 */