blob: 4edef5adbebe671f25808a2b22064ddc74683202 [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 *
Pavel Kotucek95300d12016-08-26 16:11:36 +020091format_ethernet_pbb (u8 * s, va_list * va)
92{
93 u32 b_tag = va_arg (*va, u32);
94 u32 i_tag = va_arg (*va, u32);
95 u32 vid = (b_tag & 0xfff);
96 u32 bdei = (b_tag >> 12) & 1;
97 u32 bpcp = (b_tag >> 13);
98 u32 sid = (i_tag & 0xffffff);
99 u8 ires = (i_tag >> 24) & 3;
100 u8 iuca = (i_tag >> 27) & 1;
101 u8 idei = (i_tag >> 28) & 1;
102 u8 ipcp = (i_tag >> 29);
103
104 s =
105 format (s, "B_tag %04X (vid %d, dei %d, pcp %d), ", b_tag, vid, bdei,
106 bpcp);
107 s =
108 format (s, "I_tag %08X (sid %d, res %d, dei %d, pcp %d)", i_tag, sid,
109 ires, iuca, idei, ipcp);
110
111 return s;
112}
113
114u8 *
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700115format_ethernet_header_with_length (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116{
Pavel Kotucek95300d12016-08-26 16:11:36 +0200117 ethernet_pbb_header_packed_t *ph =
118 va_arg (*args, ethernet_pbb_header_packed_t *);
119 ethernet_max_header_t *m = (ethernet_max_header_t *) ph;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120 u32 max_header_bytes = va_arg (*args, u32);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700121 ethernet_main_t *em = &ethernet_main;
122 ethernet_header_t *e = &m->ethernet;
123 ethernet_vlan_header_t *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124 ethernet_type_t type = clib_net_to_host_u16 (e->type);
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700125 ethernet_type_t vlan_type[ARRAY_LEN (m->vlan)];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126 u32 n_vlan = 0, i, header_bytes;
127 uword indent;
128
Pavel Kotucek95300d12016-08-26 16:11:36 +0200129 while ((type == ETHERNET_TYPE_VLAN || type == ETHERNET_TYPE_DOT1AD
130 || type == ETHERNET_TYPE_DOT1AH) && n_vlan < ARRAY_LEN (m->vlan))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131 {
marek zavodskyad2c9c02016-07-07 03:16:10 +0200132 vlan_type[n_vlan] = type;
Pavel Kotucek95300d12016-08-26 16:11:36 +0200133 if (type != ETHERNET_TYPE_DOT1AH)
134 {
135 v = m->vlan + n_vlan;
136 type = clib_net_to_host_u16 (v->type);
137 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 n_vlan++;
139 }
140
141 header_bytes = sizeof (e[0]) + n_vlan * sizeof (v[0]);
142 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
143 return format (s, "ethernet header truncated");
144
145 indent = format_get_indent (s);
146
147 s = format (s, "%U: %U -> %U",
148 format_ethernet_type, type,
149 format_ethernet_address, e->src_address,
150 format_ethernet_address, e->dst_address);
151
Pavel Kotucek95300d12016-08-26 16:11:36 +0200152 if (type != ETHERNET_TYPE_DOT1AH)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 {
Pavel Kotucek95300d12016-08-26 16:11:36 +0200154 for (i = 0; i < n_vlan; i++)
155 {
156 u32 v = clib_net_to_host_u16 (m->vlan[i].priority_cfi_and_id);
157 if (*vlan_type == ETHERNET_TYPE_VLAN)
158 s = format (s, " 802.1q vlan %U", format_ethernet_vlan_tci, v);
159 else
160 s = format (s, " 802.1ad vlan %U", format_ethernet_vlan_tci, v);
161 }
162
163 if (max_header_bytes != 0 && header_bytes < max_header_bytes)
164 {
165 ethernet_type_info_t *ti;
166 vlib_node_t *node = 0;
167
168 ti = ethernet_get_type_info (em, type);
169 if (ti && ti->node_index != ~0)
170 node = vlib_get_node (em->vlib_main, ti->node_index);
171 if (node && node->format_buffer)
172 s = format (s, "\n%U%U",
173 format_white_space, indent,
174 node->format_buffer, (void *) m + header_bytes,
175 max_header_bytes - header_bytes);
176 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177 }
Pavel Kotucek95300d12016-08-26 16:11:36 +0200178 else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179 {
Pavel Kotucek95300d12016-08-26 16:11:36 +0200180 s = format (s, "\n%UPBB header : %U", format_white_space, indent,
181 format_ethernet_pbb,
182 clib_net_to_host_u16 (ph->priority_dei_id),
183 clib_net_to_host_u32 (ph->priority_dei_uca_res_sid));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 }
185
186 return s;
187}
188
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700189u8 *
190format_ethernet_header (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700192 ethernet_max_header_t *m = va_arg (*args, ethernet_max_header_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 return format (s, "%U", format_ethernet_header_with_length, m, 0);
194}
195
196/* Parse X:X:X:X:X:X unix style ethernet address. */
197static uword
198unformat_ethernet_address_unix (unformat_input_t * input, va_list * args)
199{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700200 u8 *result = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201 u32 i, a[6];
202
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700203 if (!unformat (input, "%_%x:%x:%x:%x:%x:%x%_",
204 &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 return 0;
206
207 /* Check range. */
208 for (i = 0; i < ARRAY_LEN (a); i++)
209 if (a[i] >= (1 << 8))
210 return 0;
211
212 for (i = 0; i < ARRAY_LEN (a); i++)
213 result[i] = a[i];
214
215 return 1;
216}
217
218/* Parse X.X.X cisco style ethernet address. */
219static uword
220unformat_ethernet_address_cisco (unformat_input_t * input, va_list * args)
221{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700222 u8 *result = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223 u32 i, a[3];
224
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700225 if (!unformat (input, "%_%x.%x.%x%_", &a[0], &a[1], &a[2]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226 return 0;
227
228 /* Check range. */
229 for (i = 0; i < ARRAY_LEN (a); i++)
230 if (a[i] >= (1 << 16))
231 return 0;
232
233 result[0] = (a[0] >> 8) & 0xff;
234 result[1] = (a[0] >> 0) & 0xff;
235 result[2] = (a[1] >> 8) & 0xff;
236 result[3] = (a[1] >> 0) & 0xff;
237 result[4] = (a[2] >> 8) & 0xff;
238 result[5] = (a[2] >> 0) & 0xff;
239
240 return 1;
241}
242
243/* Parse ethernet address; accept either unix or style addresses. */
244uword
245unformat_ethernet_address (unformat_input_t * input, va_list * args)
246{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700247 u8 *result = va_arg (*args, u8 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 return (unformat_user (input, unformat_ethernet_address_unix, result)
249 || unformat_user (input, unformat_ethernet_address_cisco, result));
250}
251
252/* Returns ethernet type as an int in host byte order. */
253uword
254unformat_ethernet_type_host_byte_order (unformat_input_t * input,
255 va_list * args)
256{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700257 u16 *result = va_arg (*args, u16 *);
258 ethernet_main_t *em = &ethernet_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259 int type, i;
260
261 /* Numeric type. */
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700262 if (unformat (input, "0x%x", &type) || unformat (input, "%d", &type))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263 {
264 if (type >= (1 << 16))
265 return 0;
266 *result = type;
267 return 1;
268 }
269
270 /* Named type. */
271 if (unformat_user (input, unformat_vlib_number_by_name,
272 em->type_info_by_name, &i))
273 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700274 ethernet_type_info_t *ti = vec_elt_at_index (em->type_infos, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275 *result = ti->type;
276 return 1;
277 }
278
279 return 0;
280}
281
282uword
283unformat_ethernet_type_net_byte_order (unformat_input_t * input,
284 va_list * args)
285{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700286 u16 *result = va_arg (*args, u16 *);
287 if (!unformat_user (input, unformat_ethernet_type_host_byte_order, result))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288 return 0;
289
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700290 *result = clib_host_to_net_u16 ((u16) * result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 return 1;
292}
293
294uword
295unformat_ethernet_header (unformat_input_t * input, va_list * args)
296{
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700297 u8 **result = va_arg (*args, u8 **);
298 ethernet_max_header_t _m, *m = &_m;
299 ethernet_header_t *e = &m->ethernet;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300 u16 type;
301 u32 n_vlan;
302
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700303 if (!unformat (input, "%U: %U -> %U",
304 unformat_ethernet_type_host_byte_order, &type,
305 unformat_ethernet_address, &e->src_address,
306 unformat_ethernet_address, &e->dst_address))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307 return 0;
308
309 n_vlan = 0;
310 while (unformat (input, "vlan"))
311 {
312 u32 id, priority;
313
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700314 if (!unformat_user (input, unformat_vlib_number, &id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315 || id >= ETHERNET_N_VLAN)
316 return 0;
317
318 if (unformat (input, "priority %d", &priority))
319 {
320 if (priority >= 8)
321 return 0;
322 id |= priority << 13;
323 }
324
325 if (unformat (input, "cfi"))
326 id |= 1 << 12;
327
328 /* Too many vlans given. */
329 if (n_vlan >= ARRAY_LEN (m->vlan))
330 return 0;
331
332 m->vlan[n_vlan].priority_cfi_and_id = clib_host_to_net_u16 (id);
333 n_vlan++;
334 }
335
336 if (n_vlan == 0)
337 e->type = clib_host_to_net_u16 (type);
338 else
339 {
340 int i;
341
342 e->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
343 for (i = 0; i < n_vlan - 1; i++)
344 m->vlan[i].type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
345 m->vlan[n_vlan - 1].type = clib_host_to_net_u16 (type);
346 }
347
348 /* Add header to result. */
349 {
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700350 void *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 u32 n_bytes = sizeof (e[0]) + n_vlan * sizeof (m->vlan[0]);
352
353 vec_add2 (*result, p, n_bytes);
Damjan Marionf1213b82016-03-13 02:22:06 +0100354 clib_memcpy (p, m, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355 }
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700356
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 return 1;
358}
Keith Burns (alagalah)e70dcc82016-08-15 18:33:19 -0700359
360/*
361 * fd.io coding-style-patch-verification: ON
362 *
363 * Local Variables:
364 * eval: (c-set-style "gnu")
365 * End:
366 */