FD.io VPP  v18.07-rc0-415-g6c78436
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, u32 flags)
51 {
52  ASSERT (flags != 0);
53 
54  while (n_packets >= 2)
55  {
56  u32 pi0, pi1;
57  vlib_buffer_t *p0, *p1;
58  ip4_header_t *ip0, *ip1;
59  ip_csum_t sum0, sum1;
60 
61  pi0 = packets[0];
62  pi1 = packets[1];
63  p0 = vlib_get_buffer (vm, pi0);
64  p1 = vlib_get_buffer (vm, pi1);
65  n_packets -= 2;
66  packets += 2;
67 
68  ip0 = (void *) (p0->data + ip_header_offset);
69  ip1 = (void *) (p1->data + ip_header_offset);
70 
71  if (flags & IP4_PG_EDIT_LENGTH)
72  {
73  ip0->length =
74  clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0) -
75  ip_header_offset);
76  ip1->length =
77  clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p1) -
78  ip_header_offset);
79  }
80 
81  if (flags & IP4_PG_EDIT_CHECKSUM)
82  {
83  ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
84  ASSERT (ip4_header_bytes (ip1) == sizeof (ip1[0]));
85 
86  ip0->checksum = 0;
87  ip1->checksum = 0;
88 
89  ip4_partial_header_checksum_x2 (ip0, ip1, sum0, sum1);
90  ip0->checksum = ~ip_csum_fold (sum0);
91  ip1->checksum = ~ip_csum_fold (sum1);
92 
93  ASSERT (ip0->checksum == ip4_header_checksum (ip0));
94  ASSERT (ip1->checksum == ip4_header_checksum (ip1));
95  }
96  }
97 
98  while (n_packets >= 1)
99  {
100  u32 pi0;
101  vlib_buffer_t *p0;
102  ip4_header_t *ip0;
103  ip_csum_t sum0;
104 
105  pi0 = packets[0];
106  p0 = vlib_get_buffer (vm, pi0);
107  n_packets -= 1;
108  packets += 1;
109 
110  ip0 = (void *) (p0->data + ip_header_offset);
111 
112  if (flags & IP4_PG_EDIT_LENGTH)
113  ip0->length =
114  clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0) -
115  ip_header_offset);
116 
117  if (flags & IP4_PG_EDIT_CHECKSUM)
118  {
119  ASSERT (ip4_header_bytes (ip0) == sizeof (ip0[0]));
120 
121  ip0->checksum = 0;
122 
123  ip4_partial_header_checksum_x1 (ip0, sum0);
124  ip0->checksum = ~ip_csum_fold (sum0);
125 
126  ASSERT (ip0->checksum == ip4_header_checksum (ip0));
127  }
128  }
129 }
130 
131 static void
133  pg_stream_t * s,
134  pg_edit_group_t * g, u32 * packets, u32 n_packets)
135 {
137  u32 ip_offset;
138 
139  ip_offset = g->start_byte_offset;
140 
141  switch (g->edit_function_opaque)
142  {
143  case IP4_PG_EDIT_LENGTH:
144  compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
146  break;
147 
149  compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
151  break;
152 
154  compute_length_and_or_checksum (vm, packets, n_packets, ip_offset,
157  break;
158 
159  default:
160  ASSERT (0);
161  break;
162  }
163 }
164 
165 typedef struct
166 {
167  pg_edit_t ip_version, header_length;
170 
172 
173  /* Flags together with fragment offset. */
174  pg_edit_t mf_flag, df_flag, ce_flag;
175 
177 
179 
181 
182  pg_edit_t src_address, dst_address;
184 
185 static inline void
187 {
188  /* Initialize fields that are not bit fields in the IP header. */
189 #define _(f) pg_edit_init (&p->f, ip4_header_t, f);
190  _(tos);
191  _(length);
192  _(fragment_id);
193  _(ttl);
194  _(protocol);
195  _(checksum);
196  _(src_address);
197  _(dst_address);
198 #undef _
199 
200  /* Initialize bit fields. */
202  ip_version_and_header_length, 0, 4);
204  ip_version_and_header_length, 4, 4);
205 
207  flags_and_fragment_offset, 0, 13);
209  flags_and_fragment_offset, 13, 1);
211  flags_and_fragment_offset, 14, 1);
213  flags_and_fragment_offset, 15, 1);
214 }
215 
216 uword
217 unformat_pg_ip4_header (unformat_input_t * input, va_list * args)
218 {
219  pg_stream_t *s = va_arg (*args, pg_stream_t *);
220  pg_ip4_header_t *p;
221  u32 group_index;
222 
223  p = pg_create_edit_group (s, sizeof (p[0]), sizeof (ip4_header_t),
224  &group_index);
225  pg_ip4_header_init (p);
226 
227  /* Defaults. */
228  pg_edit_set_fixed (&p->ip_version, 4);
229  pg_edit_set_fixed (&p->header_length, sizeof (ip4_header_t) / sizeof (u32));
230 
231  pg_edit_set_fixed (&p->tos, 0);
232  pg_edit_set_fixed (&p->ttl, 64);
233 
236  pg_edit_set_fixed (&p->mf_flag, 0);
237  pg_edit_set_fixed (&p->df_flag, 0);
238  pg_edit_set_fixed (&p->ce_flag, 0);
239 
242 
243  if (unformat (input, "%U: %U -> %U",
249  goto found;
250 
251  if (!unformat (input, "%U:",
253  goto error;
254 
255 found:
256  /* Parse options. */
257  while (1)
258  {
259  if (unformat (input, "version %U",
261  ;
262 
263  else if (unformat (input, "header-length %U",
266  ;
267 
268  else if (unformat (input, "tos %U",
270  ;
271 
272  else if (unformat (input, "length %U",
274  ;
275 
276  else if (unformat (input, "checksum %U",
278  ;
279 
280  else if (unformat (input, "ttl %U",
282  ;
283 
284  else if (unformat (input, "fragment id %U offset %U",
289  {
290  int i;
291  for (i = 0; i < ARRAY_LEN (p->fragment_offset.values); i++)
294  i) / 8);
295 
296  }
297 
298  /* Flags. */
299  else if (unformat (input, "mf") || unformat (input, "MF"))
300  pg_edit_set_fixed (&p->mf_flag, 1);
301 
302  else if (unformat (input, "df") || unformat (input, "DF"))
303  pg_edit_set_fixed (&p->df_flag, 1);
304 
305  else if (unformat (input, "ce") || unformat (input, "CE"))
306  pg_edit_set_fixed (&p->ce_flag, 1);
307 
308  /* Can't parse input: try next protocol level. */
309  else
310  break;
311  }
312 
313  {
314  ip_main_t *im = &ip_main;
315  ip_protocol_t protocol;
316  ip_protocol_info_t *pi;
317 
318  pi = 0;
319  if (p->protocol.type == PG_EDIT_FIXED)
320  {
321  protocol = pg_edit_get_value (&p->protocol, PG_EDIT_LO);
322  pi = ip_get_protocol_info (im, protocol);
323  }
324 
325  if (pi && pi->unformat_pg_edit
326  && unformat_user (input, pi->unformat_pg_edit, s))
327  ;
328 
329  else if (!unformat_user (input, unformat_pg_payload, s))
330  goto error;
331 
334  && group_index + 1 < vec_len (s->edit_groups))
335  {
337  pg_edit_group_n_bytes (s, group_index));
338  }
339 
340  /* Compute IP header checksum if all edits are fixed. */
342  {
343  ip4_header_t fixed_header, fixed_mask, cmp_mask;
344 
345  /* See if header is all fixed and specified except for
346  checksum field. */
347  memset (&cmp_mask, ~0, sizeof (cmp_mask));
348  cmp_mask.checksum = 0;
349 
350  pg_edit_group_get_fixed_packet_data (s, group_index,
351  &fixed_header, &fixed_mask);
352  if (!memcmp (&fixed_mask, &cmp_mask, sizeof (cmp_mask)))
354  clib_net_to_host_u16 (ip4_header_checksum
355  (&fixed_header)));
356  }
357 
358  p = pg_get_edit_group (s, group_index);
361  {
362  pg_edit_group_t *g = pg_stream_get_group (s, group_index);
364  g->edit_function_opaque = 0;
365  if (p->length.type == PG_EDIT_UNSPECIFIED)
369  }
370 
371  return 1;
372  }
373 
374 error:
375  /* Free up any edits we may have added. */
376  pg_free_edit_group (s);
377  return 0;
378 }
379 
380 
381 /*
382  * fd.io coding-style-patch-verification: ON
383  *
384  * Local Variables:
385  * eval: (c-set-style "gnu")
386  * End:
387  */
pg_edit_t mf_flag
Definition: ip4_pg.c:174
Definition: edit.h:64
unformat_function_t unformat_ip_protocol
Definition: format.h:46
#define PG_EDIT_LO
Definition: edit.h:83
pg_edit_t ttl
Definition: ip4_pg.c:176
#define ip4_partial_header_checksum_x2(ip0, ip1, sum0, sum1)
Definition: ip4_packet.h:288
static void * pg_get_edit_group(pg_stream_t *s, u32 group_index)
Definition: pg.h:265
Definition: pg.h:316
static void pg_edit_set_fixed(pg_edit_t *e, u64 value)
Definition: edit.h:153
pg_edit_t tos
Definition: ip4_pg.c:168
pg_edit_t dst_address
Definition: ip4_pg.c:182
pg_edit_group_t * edit_groups
Definition: pg.h:109
static int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:232
pg_edit_t fragment_offset
Definition: ip4_pg.c:171
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:73
pg_edit_t ip_version
Definition: ip4_pg.c:167
pg_edit_t protocol
Definition: ip4_pg.c:178
int i
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
uword unformat_pg_edit(unformat_input_t *input, va_list *args)
Definition: edit.c:106
uword ip_csum_t
Definition: ip_packet.h:90
Definition: ip.h:109
static 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:250
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:67
static pg_edit_group_t * pg_stream_get_group(pg_stream_t *s, u32 group_index)
Definition: pg.h:225
unformat_function_t * unformat_pg_edit
Definition: ip.h:90
#define static_always_inline
Definition: clib.h:93
unformat_function_t unformat_ip4_address
Definition: format.h:76
uword unformat_pg_payload(unformat_input_t *input, va_list *args)
Definition: edit.c:127
pg_edit_type_t type
Definition: edit.h:66
pg_edit_t header_length
Definition: ip4_pg.c:167
unsigned int u32
Definition: types.h:88
static void * pg_create_edit_group(pg_stream_t *s, int n_edit_bytes, int n_packet_bytes, u32 *group_index)
Definition: pg.h:231
void pg_edit_set_value(pg_edit_t *e, int hi_or_lo, u64 value)
Definition: edit.c:77
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:326
u8 * values[2]
Definition: edit.h:82
static ip_protocol_info_t * ip_get_protocol_info(ip_main_t *im, u32 protocol)
Definition: ip.h:136
pg_edit_t fragment_id
Definition: ip4_pg.c:171
struct _unformat_input_t unformat_input_t
static u64 pg_edit_get_value(pg_edit_t *e, int hi_or_lo)
Definition: edit.h:173
#define pg_edit_init_bitfield(e, type, field, field_offset, field_n_bits)
Definition: edit.h:98
enum ip_protocol ip_protocol_t
pg_edit_t src_address
Definition: ip4_pg.c:182
vlib_main_t * vm
Definition: buffer.c:294
ip_main_t ip_main
Definition: ip_init.c:42
u32 min_packet_bytes
Definition: pg.h:114
u32 max_packet_bytes
Definition: pg.h:114
static uword pg_edit_group_n_bytes(pg_stream_t *s, u32 group_index)
Definition: pg.h:273
#define ARRAY_LEN(x)
Definition: clib.h:59
pg_edit_t checksum
Definition: ip4_pg.c:180
pg_edit_t df_flag
Definition: ip4_pg.c:174
#define ASSERT(truth)
uword unformat_pg_ip4_header(unformat_input_t *input, va_list *args)
Definition: ip4_pg.c:217
static void pg_free_edit_group(pg_stream_t *s)
Definition: pg.h:284
pg_edit_t ce_flag
Definition: ip4_pg.c:174
uword edit_function_opaque
Definition: pg.h:79
Definition: pg.h:96
#define IP4_PG_EDIT_CHECKSUM
Definition: ip4_pg.c:43
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define ip4_partial_header_checksum_x1(ip0, sum0)
Definition: ip4_packet.h:270
pg_edit_t length
Definition: ip4_pg.c:169
u64 uword
Definition: types.h:112
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:132
uword unformat_pg_number(unformat_input_t *input, va_list *args)
Definition: edit.c:85
u8 data[0]
Packet data.
Definition: buffer.h:172
static void pg_ip4_header_init(pg_ip4_header_t *p)
Definition: ip4_pg.c:186
#define IP4_PG_EDIT_LENGTH
Definition: ip4_pg.c:44
u32 flags
Definition: vhost-user.h:77
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:244
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972