Line data Source code
1 : /*
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 :
43 : u8 *
44 1894960 : format_ethernet_address (u8 * s, va_list * args)
45 : {
46 1894960 : ethernet_main_t *em = ðernet_main;
47 1894960 : u8 *a = va_arg (*args, u8 *);
48 :
49 1894960 : if (em->format_ethernet_address_16bit)
50 0 : return format (s, "%02x%02x.%02x%02x.%02x%02x",
51 0 : a[0], a[1], a[2], a[3], a[4], a[5]);
52 : else
53 1894960 : return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
54 1894960 : a[0], a[1], a[2], a[3], a[4], a[5]);
55 : }
56 :
57 : u8 *
58 0 : format_mac_address (u8 * s, va_list * args)
59 : {
60 0 : return (format_ethernet_address (s, args));
61 : }
62 :
63 : u8 *
64 912412 : format_ethernet_type (u8 * s, va_list * args)
65 : {
66 912412 : ethernet_type_t type = va_arg (*args, u32);
67 912412 : ethernet_main_t *em = ðernet_main;
68 912412 : ethernet_type_info_t *t = ethernet_get_type_info (em, type);
69 :
70 912412 : if (t)
71 911515 : s = format (s, "%s", t->name);
72 : else
73 897 : s = format (s, "0x%04x", type);
74 :
75 912412 : return s;
76 : }
77 :
78 : u8 *
79 15523 : format_ethernet_vlan_tci (u8 * s, va_list * va)
80 : {
81 15523 : u32 vlan_tci = va_arg (*va, u32);
82 :
83 15523 : u32 vid = (vlan_tci & 0xfff);
84 15523 : u32 cfi = (vlan_tci >> 12) & 1;
85 15523 : u32 pri = (vlan_tci >> 13);
86 :
87 15523 : s = format (s, "%d", vid);
88 15523 : if (pri != 0)
89 417 : s = format (s, " priority %d", pri);
90 15523 : if (cfi != 0)
91 50 : s = format (s, " cfi");
92 :
93 15523 : return s;
94 : }
95 :
96 : u8 *
97 904122 : format_ethernet_header_with_length (u8 * s, va_list * args)
98 : {
99 904122 : ethernet_pbb_header_packed_t *ph =
100 : va_arg (*args, ethernet_pbb_header_packed_t *);
101 904122 : ethernet_max_header_t *m = (ethernet_max_header_t *) ph;
102 904122 : u32 max_header_bytes = va_arg (*args, u32);
103 904122 : ethernet_main_t *em = ðernet_main;
104 904122 : ethernet_header_t *e = &m->ethernet;
105 : ethernet_vlan_header_t *v;
106 904122 : ethernet_type_t type = clib_net_to_host_u16 (e->type);
107 : ethernet_type_t vlan_type[ARRAY_LEN (m->vlan)];
108 904122 : u32 n_vlan = 0, i, header_bytes;
109 : u32 indent;
110 :
111 919645 : while ((type == ETHERNET_TYPE_VLAN || type == ETHERNET_TYPE_DOT1AD
112 919645 : || type == ETHERNET_TYPE_DOT1AH) && n_vlan < ARRAY_LEN (m->vlan))
113 : {
114 15523 : vlan_type[n_vlan] = type;
115 15523 : if (type != ETHERNET_TYPE_DOT1AH)
116 : {
117 15523 : v = m->vlan + n_vlan;
118 15523 : type = clib_net_to_host_u16 (v->type);
119 : }
120 15523 : n_vlan++;
121 : }
122 :
123 904122 : header_bytes = sizeof (e[0]) + n_vlan * sizeof (v[0]);
124 904122 : if (max_header_bytes != 0 && header_bytes > max_header_bytes)
125 0 : return format (s, "ethernet header truncated");
126 :
127 904122 : indent = format_get_indent (s);
128 :
129 904122 : s = format (s, "%U: %U -> %U",
130 : format_ethernet_type, type,
131 904122 : format_ethernet_address, e->src_address,
132 904122 : format_ethernet_address, e->dst_address);
133 :
134 904122 : if (type != ETHERNET_TYPE_DOT1AH)
135 : {
136 919645 : for (i = 0; i < n_vlan; i++)
137 : {
138 15523 : u32 v = clib_net_to_host_u16 (m->vlan[i].priority_cfi_and_id);
139 15523 : if (*vlan_type == ETHERNET_TYPE_VLAN)
140 11917 : s = format (s, " 802.1q vlan %U", format_ethernet_vlan_tci, v);
141 : else
142 3606 : s = format (s, " 802.1ad vlan %U", format_ethernet_vlan_tci, v);
143 : }
144 :
145 904122 : if (max_header_bytes != 0 && header_bytes < max_header_bytes)
146 : {
147 : ethernet_type_info_t *ti;
148 572287 : vlib_node_t *node = 0;
149 :
150 572287 : ti = ethernet_get_type_info (em, type);
151 572287 : if (ti && ti->node_index != ~0)
152 570294 : node = vlib_get_node (em->vlib_main, ti->node_index);
153 572287 : if (node && node->format_buffer)
154 570060 : s = format (s, "\n%U%U",
155 : format_white_space, indent,
156 : node->format_buffer, (void *) m + header_bytes,
157 : max_header_bytes - header_bytes);
158 : }
159 : }
160 : else
161 : {
162 : s =
163 0 : format (s, " %s b-tag %04X",
164 0 : (clib_net_to_host_u16 (ph->b_type) ==
165 : ETHERNET_TYPE_DOT1AD) ? "802.1ad" : "",
166 0 : clib_net_to_host_u16 (ph->priority_dei_id));
167 : s =
168 0 : format (s, " %s i-tag %08X",
169 0 : (clib_net_to_host_u16 (ph->i_type) ==
170 : ETHERNET_TYPE_DOT1AH) ? "802.1ah" : "",
171 : clib_net_to_host_u32 (ph->priority_dei_uca_res_sid));
172 : }
173 :
174 904122 : return s;
175 : }
176 :
177 : u8 *
178 331835 : format_ethernet_header (u8 * s, va_list * args)
179 : {
180 331835 : ethernet_max_header_t *m = va_arg (*args, ethernet_max_header_t *);
181 331835 : return format (s, "%U", format_ethernet_header_with_length, m, 0);
182 : }
183 :
184 : /* Parse X:X:X:X:X:X unix style ethernet address. */
185 : static uword
186 19 : unformat_ethernet_address_unix (unformat_input_t * input, va_list * args)
187 : {
188 19 : u8 *result = va_arg (*args, u8 *);
189 : u32 i, a[6];
190 :
191 19 : if (!unformat (input, "%_%x:%x:%x:%x:%x:%x%_",
192 : &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
193 16 : return 0;
194 :
195 : /* Check range. */
196 21 : for (i = 0; i < ARRAY_LEN (a); i++)
197 18 : if (a[i] >= (1 << 8))
198 0 : return 0;
199 :
200 21 : for (i = 0; i < ARRAY_LEN (a); i++)
201 18 : result[i] = a[i];
202 :
203 3 : return 1;
204 : }
205 :
206 : /* Parse X.X.X cisco style ethernet address. */
207 : static uword
208 16 : unformat_ethernet_address_cisco (unformat_input_t * input, va_list * args)
209 : {
210 16 : u8 *result = va_arg (*args, u8 *);
211 : u32 i, a[3];
212 :
213 16 : if (!unformat (input, "%_%x.%x.%x%_", &a[0], &a[1], &a[2]))
214 6 : return 0;
215 :
216 : /* Check range. */
217 40 : for (i = 0; i < ARRAY_LEN (a); i++)
218 30 : if (a[i] >= (1 << 16))
219 0 : return 0;
220 :
221 10 : result[0] = (a[0] >> 8) & 0xff;
222 10 : result[1] = (a[0] >> 0) & 0xff;
223 10 : result[2] = (a[1] >> 8) & 0xff;
224 10 : result[3] = (a[1] >> 0) & 0xff;
225 10 : result[4] = (a[2] >> 8) & 0xff;
226 10 : result[5] = (a[2] >> 0) & 0xff;
227 :
228 10 : return 1;
229 : }
230 :
231 : /* Parse ethernet address; accept either unix or style addresses. */
232 : uword
233 19 : unformat_ethernet_address (unformat_input_t * input, va_list * args)
234 : {
235 19 : u8 *result = va_arg (*args, u8 *);
236 19 : return (unformat_user (input, unformat_ethernet_address_unix, result)
237 19 : || unformat_user (input, unformat_ethernet_address_cisco, result));
238 : }
239 :
240 : uword
241 1 : unformat_mac_address (unformat_input_t * input, va_list * args)
242 : {
243 1 : return (unformat_ethernet_address (input, args));
244 : }
245 :
246 :
247 : /* Returns ethernet type as an int in host byte order. */
248 : uword
249 6 : unformat_ethernet_type_host_byte_order (unformat_input_t * input,
250 : va_list * args)
251 : {
252 6 : u16 *result = va_arg (*args, u16 *);
253 6 : ethernet_main_t *em = ðernet_main;
254 : int type, i;
255 :
256 : /* Numeric type. */
257 6 : if (unformat (input, "0x%x", &type) || unformat (input, "%d", &type))
258 : {
259 0 : if (type >= (1 << 16))
260 0 : return 0;
261 0 : *result = type;
262 0 : return 1;
263 : }
264 :
265 : /* Named type. */
266 6 : if (unformat_user (input, unformat_vlib_number_by_name,
267 : em->type_info_by_name, &i))
268 : {
269 6 : ethernet_type_info_t *ti = vec_elt_at_index (em->type_infos, i);
270 6 : *result = ti->type;
271 6 : return 1;
272 : }
273 :
274 0 : return 0;
275 : }
276 :
277 : uword
278 6 : unformat_ethernet_type_net_byte_order (unformat_input_t * input,
279 : va_list * args)
280 : {
281 6 : u16 *result = va_arg (*args, u16 *);
282 6 : if (!unformat_user (input, unformat_ethernet_type_host_byte_order, result))
283 0 : return 0;
284 :
285 6 : *result = clib_host_to_net_u16 ((u16) * result);
286 6 : return 1;
287 : }
288 :
289 : uword
290 0 : unformat_ethernet_header (unformat_input_t * input, va_list * args)
291 : {
292 0 : u8 **result = va_arg (*args, u8 **);
293 0 : ethernet_max_header_t _m, *m = &_m;
294 0 : ethernet_header_t *e = &m->ethernet;
295 : u16 type;
296 : u32 n_vlan;
297 :
298 0 : if (!unformat (input, "%U: %U -> %U",
299 : unformat_ethernet_type_host_byte_order, &type,
300 : unformat_ethernet_address, &e->src_address,
301 : unformat_ethernet_address, &e->dst_address))
302 0 : return 0;
303 :
304 0 : n_vlan = 0;
305 0 : while (unformat (input, "vlan"))
306 : {
307 : u32 id, priority;
308 :
309 0 : if (!unformat_user (input, unformat_vlib_number, &id)
310 0 : || id >= ETHERNET_N_VLAN)
311 0 : return 0;
312 :
313 0 : if (unformat (input, "priority %d", &priority))
314 : {
315 0 : if (priority >= 8)
316 0 : return 0;
317 0 : id |= priority << 13;
318 : }
319 :
320 0 : if (unformat (input, "cfi"))
321 0 : id |= 1 << 12;
322 :
323 : /* Too many vlans given. */
324 0 : if (n_vlan >= ARRAY_LEN (m->vlan))
325 0 : return 0;
326 :
327 0 : m->vlan[n_vlan].priority_cfi_and_id = clib_host_to_net_u16 (id);
328 0 : n_vlan++;
329 : }
330 :
331 0 : if (n_vlan == 0)
332 0 : e->type = clib_host_to_net_u16 (type);
333 : else
334 : {
335 : int i;
336 :
337 0 : e->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
338 0 : for (i = 0; i < n_vlan - 1; i++)
339 0 : m->vlan[i].type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
340 0 : m->vlan[n_vlan - 1].type = clib_host_to_net_u16 (type);
341 : }
342 :
343 : /* Add header to result. */
344 : {
345 : void *p;
346 0 : u32 n_bytes = sizeof (e[0]) + n_vlan * sizeof (m->vlan[0]);
347 :
348 0 : vec_add2 (*result, p, n_bytes);
349 0 : clib_memcpy (p, m, n_bytes);
350 : }
351 :
352 0 : return 1;
353 : }
354 :
355 : /*
356 : * fd.io coding-style-patch-verification: ON
357 : *
358 : * Local Variables:
359 : * eval: (c-set-style "gnu")
360 : * End:
361 : */
|