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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 * ip/ip4_pg: IP v4 packet-generator interface
18 * Copyright (c) 2008 Eliot Dresselhaus
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:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
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.
40 #include <vnet/ip/ip.h>
41 #include <vnet/pg/pg.h>
43 #define IP4_PG_EDIT_CHECKSUM (1 << 0)
44 #define IP4_PG_EDIT_LENGTH (1 << 1)
46 static_always_inline void
47 compute_length_and_or_checksum (vlib_main_t * vm,
55 while (n_packets >= 2)
58 vlib_buffer_t * p0, * p1;
59 ip4_header_t * ip0, * ip1;
64 p0 = vlib_get_buffer (vm, pi0);
65 p1 = vlib_get_buffer (vm, pi1);
69 ip0 = (void *) (p0->data + ip_header_offset);
70 ip1 = (void *) (p1->data + ip_header_offset);
72 if (flags & IP4_PG_EDIT_LENGTH)
74 ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0) - ip_header_offset);
75 ip1->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p1) - ip_header_offset);
78 if (flags & IP4_PG_EDIT_CHECKSUM)
80 ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
81 ASSERT (ip4_header_bytes (ip1) == sizeof (ip1[0]));
86 ip4_partial_header_checksum_x2 (ip0, ip1, sum0, sum1);
87 ip0->checksum = ~ ip_csum_fold (sum0);
88 ip1->checksum = ~ ip_csum_fold (sum1);
90 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
91 ASSERT (ip1->checksum == ip4_header_checksum (ip1));
95 while (n_packets >= 1)
103 p0 = vlib_get_buffer (vm, pi0);
107 ip0 = (void *) (p0->data + ip_header_offset);
109 if (flags & IP4_PG_EDIT_LENGTH)
110 ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0) - ip_header_offset);
112 if (flags & IP4_PG_EDIT_CHECKSUM)
114 ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
118 ip4_partial_header_checksum_x1 (ip0, sum0);
119 ip0->checksum = ~ ip_csum_fold (sum0);
121 ASSERT (ip0->checksum == ip4_header_checksum (ip0));
127 ip4_pg_edit_function (pg_main_t * pg,
133 vlib_main_t * vm = pg->vlib_main;
136 ip_offset = g->start_byte_offset;
138 switch (g->edit_function_opaque)
140 case IP4_PG_EDIT_LENGTH:
141 compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
145 case IP4_PG_EDIT_CHECKSUM:
146 compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
147 IP4_PG_EDIT_CHECKSUM);
150 case IP4_PG_EDIT_LENGTH | IP4_PG_EDIT_CHECKSUM:
151 compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
153 | IP4_PG_EDIT_CHECKSUM);
163 pg_edit_t ip_version, header_length;
167 pg_edit_t fragment_id, fragment_offset;
169 /* Flags together with fragment offset. */
170 pg_edit_t mf_flag, df_flag, ce_flag;
178 pg_edit_t src_address, dst_address;
182 pg_ip4_header_init (pg_ip4_header_t * p)
184 /* Initialize fields that are not bit fields in the IP header. */
185 #define _(f) pg_edit_init (&p->f, ip4_header_t, f);
196 /* Initialize bit fields. */
197 pg_edit_init_bitfield (&p->header_length, ip4_header_t,
198 ip_version_and_header_length,
200 pg_edit_init_bitfield (&p->ip_version, ip4_header_t,
201 ip_version_and_header_length,
204 pg_edit_init_bitfield (&p->fragment_offset, ip4_header_t,
205 flags_and_fragment_offset,
207 pg_edit_init_bitfield (&p->mf_flag, ip4_header_t,
208 flags_and_fragment_offset,
210 pg_edit_init_bitfield (&p->df_flag, ip4_header_t,
211 flags_and_fragment_offset,
213 pg_edit_init_bitfield (&p->ce_flag, ip4_header_t,
214 flags_and_fragment_offset,
219 unformat_pg_ip4_header (unformat_input_t * input, va_list * args)
221 pg_stream_t * s = va_arg (*args, pg_stream_t *);
225 p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ip4_header_t),
227 pg_ip4_header_init (p);
230 pg_edit_set_fixed (&p->ip_version, 4);
231 pg_edit_set_fixed (&p->header_length,
232 sizeof (ip4_header_t) / sizeof (u32));
234 pg_edit_set_fixed (&p->tos, 0);
235 pg_edit_set_fixed (&p->ttl, 64);
237 pg_edit_set_fixed (&p->fragment_id, 0);
238 pg_edit_set_fixed (&p->fragment_offset, 0);
239 pg_edit_set_fixed (&p->mf_flag, 0);
240 pg_edit_set_fixed (&p->df_flag, 0);
241 pg_edit_set_fixed (&p->ce_flag, 0);
243 p->length.type = PG_EDIT_UNSPECIFIED;
244 p->checksum.type = PG_EDIT_UNSPECIFIED;
246 if (unformat (input, "%U: %U -> %U",
248 unformat_ip_protocol, &p->protocol,
250 unformat_ip4_address, &p->src_address,
252 unformat_ip4_address, &p->dst_address))
255 if (! unformat (input, "%U:",
257 unformat_ip_protocol, &p->protocol))
264 if (unformat (input, "version %U",
266 unformat_pg_number, &p->ip_version))
269 else if (unformat (input, "header-length %U",
271 unformat_pg_number, &p->header_length))
274 else if (unformat (input, "tos %U",
276 unformat_pg_number, &p->tos))
279 else if (unformat (input, "length %U",
281 unformat_pg_number, &p->length))
284 else if (unformat (input, "checksum %U",
286 unformat_pg_number, &p->checksum))
289 else if (unformat (input, "ttl %U",
291 unformat_pg_number, &p->ttl))
294 else if (unformat (input, "fragment id %U offset %U",
296 unformat_pg_number, &p->fragment_id,
298 unformat_pg_number, &p->fragment_offset))
301 for (i = 0; i< ARRAY_LEN (p->fragment_offset.values); i++)
302 pg_edit_set_value (&p->fragment_offset, i,
303 pg_edit_get_value (&p->fragment_offset, i) / 8);
308 else if (unformat (input, "mf") || unformat (input, "MF"))
309 pg_edit_set_fixed (&p->mf_flag, 1);
311 else if (unformat (input, "df") || unformat (input, "DF"))
312 pg_edit_set_fixed (&p->df_flag, 1);
314 else if (unformat (input, "ce") || unformat (input, "CE"))
315 pg_edit_set_fixed (&p->ce_flag, 1);
317 /* Can't parse input: try next protocol level. */
323 ip_main_t * im = &ip_main;
324 ip_protocol_t protocol;
325 ip_protocol_info_t * pi;
328 if (p->protocol.type == PG_EDIT_FIXED)
330 protocol = pg_edit_get_value (&p->protocol, PG_EDIT_LO);
331 pi = ip_get_protocol_info (im, protocol);
334 if (pi && pi->unformat_pg_edit
335 && unformat_user (input, pi->unformat_pg_edit, s))
338 else if (! unformat_user (input, unformat_pg_payload, s))
341 if (p->length.type == PG_EDIT_UNSPECIFIED
342 && s->min_packet_bytes == s->max_packet_bytes
343 && group_index + 1 < vec_len (s->edit_groups))
345 pg_edit_set_fixed (&p->length,
346 pg_edit_group_n_bytes (s, group_index));
349 /* Compute IP header checksum if all edits are fixed. */
350 if (p->checksum.type == PG_EDIT_UNSPECIFIED)
352 ip4_header_t fixed_header, fixed_mask, cmp_mask;
354 /* See if header is all fixed and specified except for
356 memset (&cmp_mask, ~0, sizeof (cmp_mask));
357 cmp_mask.checksum = 0;
359 pg_edit_group_get_fixed_packet_data (s, group_index,
360 &fixed_header, &fixed_mask);
361 if (! memcmp (&fixed_mask, &cmp_mask, sizeof (cmp_mask)))
362 pg_edit_set_fixed (&p->checksum,
363 clib_net_to_host_u16 (ip4_header_checksum (&fixed_header)));
366 p = pg_get_edit_group (s, group_index);
367 if (p->length.type == PG_EDIT_UNSPECIFIED
368 || p->checksum.type == PG_EDIT_UNSPECIFIED)
370 pg_edit_group_t * g = pg_stream_get_group (s, group_index);
371 g->edit_function = ip4_pg_edit_function;
372 g->edit_function_opaque = 0;
373 if (p->length.type == PG_EDIT_UNSPECIFIED)
374 g->edit_function_opaque |= IP4_PG_EDIT_LENGTH;
375 if (p->checksum.type == PG_EDIT_UNSPECIFIED)
376 g->edit_function_opaque |= IP4_PG_EDIT_CHECKSUM;
383 /* Free up any edits we may have added. */
384 pg_free_edit_group (s);