FD.io VPP  v16.06
Vector Packet Processing
ip4_pg.c
Go to the documentation of this file.
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  * ip/ip4_pg: IP v4 packet-generator interface
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 <vnet/ip/ip.h>
41 #include <vnet/pg/pg.h>
42 
43 #define IP4_PG_EDIT_CHECKSUM (1 << 0)
44 #define IP4_PG_EDIT_LENGTH (1 << 1)
45 
48  u32 * packets,
49  u32 n_packets,
50  u32 ip_header_offset,
51  u32 flags)
52 {
53  ASSERT (flags != 0);
54 
55  while (n_packets >= 2)
56  {
57  u32 pi0, pi1;
58  vlib_buffer_t * p0, * p1;
59  ip4_header_t * ip0, * ip1;
60  ip_csum_t sum0, sum1;
61 
62  pi0 = packets[0];
63  pi1 = packets[1];
64  p0 = vlib_get_buffer (vm, pi0);
65  p1 = vlib_get_buffer (vm, pi1);
66  n_packets -= 2;
67  packets += 2;
68 
69  ip0 = (void *) (p0->data + ip_header_offset);
70  ip1 = (void *) (p1->data + ip_header_offset);
71 
72  if (flags & IP4_PG_EDIT_LENGTH)
73  {
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);
76  }
77 
78  if (flags & IP4_PG_EDIT_CHECKSUM)
79  {
80  ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
81  ASSERT (ip4_header_bytes (ip1) == sizeof (ip1[0]));
82 
83  ip0->checksum = 0;
84  ip1->checksum = 0;
85 
86  ip4_partial_header_checksum_x2 (ip0, ip1, sum0, sum1);
87  ip0->checksum = ~ ip_csum_fold (sum0);
88  ip1->checksum = ~ ip_csum_fold (sum1);
89 
90  ASSERT (ip0->checksum == ip4_header_checksum (ip0));
91  ASSERT (ip1->checksum == ip4_header_checksum (ip1));
92  }
93  }
94 
95  while (n_packets >= 1)
96  {
97  u32 pi0;
98  vlib_buffer_t * p0;
99  ip4_header_t * ip0;
100  ip_csum_t sum0;
101 
102  pi0 = packets[0];
103  p0 = vlib_get_buffer (vm, pi0);
104  n_packets -= 1;
105  packets += 1;
106 
107  ip0 = (void *) (p0->data + ip_header_offset);
108 
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);
111 
112  if (flags & IP4_PG_EDIT_CHECKSUM)
113  {
114  ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
115 
116  ip0->checksum = 0;
117 
118  ip4_partial_header_checksum_x1 (ip0, sum0);
119  ip0->checksum = ~ ip_csum_fold (sum0);
120 
121  ASSERT (ip0->checksum == ip4_header_checksum (ip0));
122  }
123  }
124 }
125 
126 static void
128  pg_stream_t * s,
129  pg_edit_group_t * g,
130  u32 * packets,
131  u32 n_packets)
132 {
133  vlib_main_t * vm = pg->vlib_main;
134  u32 ip_offset;
135 
136  ip_offset = g->start_byte_offset;
137 
138  switch (g->edit_function_opaque)
139  {
140  case IP4_PG_EDIT_LENGTH:
141  compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
143  break;
144 
146  compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
148  break;
149 
151  compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
154  break;
155 
156  default:
157  ASSERT (0);
158  break;
159  }
160 }
161 
162 typedef struct {
163  pg_edit_t ip_version, header_length;
166 
168 
169  /* Flags together with fragment offset. */
170  pg_edit_t mf_flag, df_flag, ce_flag;
171 
173 
175 
177 
178  pg_edit_t src_address, dst_address;
180 
181 static inline void
183 {
184  /* Initialize fields that are not bit fields in the IP header. */
185 #define _(f) pg_edit_init (&p->f, ip4_header_t, f);
186  _ (tos);
187  _ (length);
188  _ (fragment_id);
189  _ (ttl);
190  _ (protocol);
191  _ (checksum);
192  _ (src_address);
193  _ (dst_address);
194 #undef _
195 
196  /* Initialize bit fields. */
198  ip_version_and_header_length,
199  0, 4);
201  ip_version_and_header_length,
202  4, 4);
203 
205  flags_and_fragment_offset,
206  0, 13);
208  flags_and_fragment_offset,
209  13, 1);
211  flags_and_fragment_offset,
212  14, 1);
214  flags_and_fragment_offset,
215  15, 1);
216 }
217 
218 uword
219 unformat_pg_ip4_header (unformat_input_t * input, va_list * args)
220 {
221  pg_stream_t * s = va_arg (*args, pg_stream_t *);
222  pg_ip4_header_t * p;
223  u32 group_index;
224 
225  p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ip4_header_t),
226  &group_index);
227  pg_ip4_header_init (p);
228 
229  /* Defaults. */
230  pg_edit_set_fixed (&p->ip_version, 4);
232  sizeof (ip4_header_t) / sizeof (u32));
233 
234  pg_edit_set_fixed (&p->tos, 0);
235  pg_edit_set_fixed (&p->ttl, 64);
236 
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);
242 
245 
246  if (unformat (input, "%U: %U -> %U",
253  goto found;
254 
255  if (! unformat (input, "%U:",
258  goto error;
259 
260 found:
261  /* Parse options. */
262  while (1)
263  {
264  if (unformat (input, "version %U",
267  ;
268 
269  else if (unformat (input, "header-length %U",
272  ;
273 
274  else if (unformat (input, "tos %U",
276  unformat_pg_number, &p->tos))
277  ;
278 
279  else if (unformat (input, "length %U",
282  ;
283 
284  else if (unformat (input, "checksum %U",
287  ;
288 
289  else if (unformat (input, "ttl %U",
291  unformat_pg_number, &p->ttl))
292  ;
293 
294  else if (unformat (input, "fragment id %U offset %U",
299  {
300  int i;
301  for (i = 0; i< ARRAY_LEN (p->fragment_offset.values); i++)
303  pg_edit_get_value (&p->fragment_offset, i) / 8);
304 
305  }
306 
307  /* Flags. */
308  else if (unformat (input, "mf") || unformat (input, "MF"))
309  pg_edit_set_fixed (&p->mf_flag, 1);
310 
311  else if (unformat (input, "df") || unformat (input, "DF"))
312  pg_edit_set_fixed (&p->df_flag, 1);
313 
314  else if (unformat (input, "ce") || unformat (input, "CE"))
315  pg_edit_set_fixed (&p->ce_flag, 1);
316 
317  /* Can't parse input: try next protocol level. */
318  else
319  break;
320  }
321 
322  {
323  ip_main_t * im = &ip_main;
324  ip_protocol_t protocol;
325  ip_protocol_info_t * pi;
326 
327  pi = 0;
328  if (p->protocol.type == PG_EDIT_FIXED)
329  {
330  protocol = pg_edit_get_value (&p->protocol, PG_EDIT_LO);
331  pi = ip_get_protocol_info (im, protocol);
332  }
333 
334  if (pi && pi->unformat_pg_edit
335  && unformat_user (input, pi->unformat_pg_edit, s))
336  ;
337 
338  else if (! unformat_user (input, unformat_pg_payload, s))
339  goto error;
340 
343  && group_index + 1 < vec_len (s->edit_groups))
344  {
346  pg_edit_group_n_bytes (s, group_index));
347  }
348 
349  /* Compute IP header checksum if all edits are fixed. */
351  {
352  ip4_header_t fixed_header, fixed_mask, cmp_mask;
353 
354  /* See if header is all fixed and specified except for
355  checksum field. */
356  memset (&cmp_mask, ~0, sizeof (cmp_mask));
357  cmp_mask.checksum = 0;
358 
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)))
363  clib_net_to_host_u16 (ip4_header_checksum (&fixed_header)));
364  }
365 
366  p = pg_get_edit_group (s, group_index);
369  {
370  pg_edit_group_t * g = pg_stream_get_group (s, group_index);
372  g->edit_function_opaque = 0;
373  if (p->length.type == PG_EDIT_UNSPECIFIED)
377  }
378 
379  return 1;
380  }
381 
382  error:
383  /* Free up any edits we may have added. */
384  pg_free_edit_group (s);
385  return 0;
386 }
387 
pg_edit_t mf_flag
Definition: ip4_pg.c:170
Definition: edit.h:63
#define PG_EDIT_LO
Definition: edit.h:81
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
pg_edit_t ttl
Definition: ip4_pg.c:172
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
#define ip4_partial_header_checksum_x2(ip0, ip1, sum0, sum1)
Definition: ip4_packet.h:236
Definition: pg.h:293
static void pg_edit_set_fixed(pg_edit_t *e, u64 value)
Definition: edit.h:149
pg_edit_t tos
Definition: ip4_pg.c:164
pg_edit_t dst_address
Definition: ip4_pg.c:178
pg_edit_group_t * edit_groups
Definition: pg.h:103
pg_edit_t fragment_offset
Definition: ip4_pg.c:167
pg_edit_t ip_version
Definition: ip4_pg.c:163
pg_edit_t protocol
Definition: ip4_pg.c:174
uword unformat_pg_edit(unformat_input_t *input, va_list *args)
Definition: edit.c:106
uword ip_csum_t
Definition: ip_packet.h:86
Definition: ip.h:108
static_always_inline void compute_length_and_or_checksum(vlib_main_t *vm, u32 *packets, u32 n_packets, u32 ip_header_offset, u32 flags)
Definition: ip4_pg.c:47
u32 start_byte_offset
Definition: pg.h:62
unformat_function_t * unformat_pg_edit
Definition: ip.h:90
always_inline pg_edit_group_t * pg_stream_get_group(pg_stream_t *s, u32 group_index)
Definition: pg.h:210
#define static_always_inline
Definition: clib.h:85
uword unformat_pg_payload(unformat_input_t *input, va_list *args)
Definition: edit.c:127
pg_edit_type_t type
Definition: edit.h:64
pg_edit_t header_length
Definition: ip4_pg.c:163
always_inline uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:112
always_inline int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:186
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:953
void pg_edit_set_value(pg_edit_t *e, int hi_or_lo, u64 value)
Definition: edit.c:77
unformat_function_t unformat_ip4_address
Definition: format.h:68
void pg_edit_group_get_fixed_packet_data(pg_stream_t *s, u32 group_index, void *fixed_packet_data, void *fixed_packet_data_mask)
Definition: stream.c:250
always_inline u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:138
always_inline uword pg_edit_group_n_bytes(pg_stream_t *s, u32 group_index)
Definition: pg.h:258
u8 * values[2]
Definition: edit.h:80
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
Definition: ip.h:135
pg_edit_t fragment_id
Definition: ip4_pg.c:167
static u64 pg_edit_get_value(pg_edit_t *e, int hi_or_lo)
Definition: edit.h:169
#define pg_edit_init_bitfield(e, type, field, field_offset, field_n_bits)
Definition: edit.h:96
enum ip_protocol ip_protocol_t
always_inline u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
always_inline void * pg_create_edit_group(pg_stream_t *s, int n_edit_bytes, int n_packet_bytes, u32 *group_index)
Definition: pg.h:214
always_inline void * pg_get_edit_group(pg_stream_t *s, u32 group_index)
Definition: pg.h:250
pg_edit_t src_address
Definition: ip4_pg.c:178
unformat_function_t unformat_ip_protocol
Definition: format.h:46
ip_main_t ip_main
Definition: ip_init.c:42
u32 min_packet_bytes
Definition: pg.h:108
u32 max_packet_bytes
Definition: pg.h:108
#define ARRAY_LEN(x)
Definition: clib.h:59
pg_edit_t checksum
Definition: ip4_pg.c:176
pg_edit_t df_flag
Definition: ip4_pg.c:170
#define ASSERT(truth)
vlib_main_t * vlib_main
Definition: pg.h:295
unsigned int u32
Definition: types.h:88
uword unformat_pg_ip4_header(unformat_input_t *input, va_list *args)
Definition: ip4_pg.c:219
pg_edit_t ce_flag
Definition: ip4_pg.c:170
uword edit_function_opaque
Definition: pg.h:75
Definition: pg.h:91
#define IP4_PG_EDIT_CHECKSUM
Definition: ip4_pg.c:43
u64 uword
Definition: types.h:112
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
void(* edit_function)(struct pg_main_t *pg, struct pg_stream_t *s, struct pg_edit_group_t *g, u32 *buffers, u32 n_buffers)
Definition: pg.h:68
#define ip4_partial_header_checksum_x1(ip0, sum0)
Definition: ip4_packet.h:218
pg_edit_t length
Definition: ip4_pg.c:165
static void ip4_pg_edit_function(pg_main_t *pg, pg_stream_t *s, pg_edit_group_t *g, u32 *packets, u32 n_packets)
Definition: ip4_pg.c:127
uword unformat_pg_number(unformat_input_t *input, va_list *args)
Definition: edit.c:84
u8 data[0]
Packet data.
Definition: buffer.h:150
static void pg_ip4_header_init(pg_ip4_header_t *p)
Definition: ip4_pg.c:182
struct _unformat_input_t unformat_input_t
#define IP4_PG_EDIT_LENGTH
Definition: ip4_pg.c:44
u32 flags
Definition: vhost-user.h:73
always_inline void pg_free_edit_group(pg_stream_t *s)
Definition: pg.h:269
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69