FD.io VPP  v16.06
Vector Packet Processing
flow_report_sample.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 #include <vnet/flow/flow_report.h>
17 #include <vnet/api_errno.h>
18 
19 typedef struct {
22 
24 
26  flow_report_t * fr,
27  ip4_address_t * collector_address,
28  ip4_address_t * src_address)
29 {
30  vnet_classify_table_t * tblp;
34  ip4_header_t * ip;
35  udp_header_t * udp;
40  ipfix_field_specifier_t * first_field;
41  u8 * rewrite = 0;
43  i32 l3_offset = -2; /* sizeof (ethernet_header_t) - sizeof (u32x4) */
44  u32 field_count = 0;
45  u32 field_index = 0;
46 
47  tblp = pool_elt_at_index (vcm->tables, fsm->classify_table_index);
48 
49  /*
50  * Mumble, assumes that we're not classifying on L2 or first 2 octets
51  * of L3..
52  */
53 
54  ip = (ip4_header_t *)(((u8 *)(tblp->mask)) + l3_offset);
55  udp = (udp_header_t *)(ip+1);
56 
57  /* Determine field count */
58 #define _(field,mask,item,length) \
59  if ((field) == (mask)) \
60  { \
61  field_count++; \
62  \
63  fr->fields_to_send = clib_bitmap_set (fr->fields_to_send, \
64  field_index, 1); \
65  } \
66  field_index++;
67 
69 #undef _
70  /* Add packetTotalCount manually */
71  field_count += 1;
72 
73  /* $$$ enterprise fields, at some later date */
74 
75  /* allocate rewrite space */
76  vec_validate_aligned (rewrite,
78  + field_count * sizeof (ipfix_field_specifier_t) - 1,
80 
81  tp = (ip4_ipfix_template_packet_t *) rewrite;
82  ip = (ip4_header_t *) &tp->ip4;
83  udp = (udp_header_t *) (ip+1);
84  h = (ipfix_message_header_t *)(udp+1);
85  s = (ipfix_set_header_t *)(h+1);
86  t = (ipfix_template_header_t *)(s+1);
87  first_field = f = (ipfix_field_specifier_t *)(t+1);
88 
89  ip->ip_version_and_header_length = 0x45;
90  ip->ttl = 254;
91  ip->protocol = IP_PROTOCOL_UDP;
92  ip->src_address.as_u32 = src_address->as_u32;
93  ip->dst_address.as_u32 = collector_address->as_u32;
94  udp->src_port = clib_host_to_net_u16 (4739 /* $$FIXME */);
95  udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix);
96  udp->length = clib_host_to_net_u16 (vec_len(rewrite) - sizeof (*ip));
97 
98  /* FIXUP: message header export_time */
99  /* FIXUP: message header sequence_number */
100  h->domain_id = clib_host_to_net_u32 (fr->domain_id);
101 
102  /* Take another trip through the mask and build the template */
103  ip = (ip4_header_t *)(((u8 *)(tblp->mask)) + l3_offset);
104  udp = (udp_header_t *)(ip+1);
105 #define _(field,mask,item,length) \
106  if ((field) == (mask)) \
107  { \
108  f->e_id_length = ipfix_e_id_length (0 /* enterprise */, \
109  item, length); \
110  f++; \
111  }
113 #undef _
114 
115  /* Add packetTotalCount manually */
116  f->e_id_length = ipfix_e_id_length (0 /* enterprise */, packetTotalCount, 8);
117  f++;
118 
119  /* Back to the template packet... */
120  ip = (ip4_header_t *) &tp->ip4;
121  udp = (udp_header_t *) (ip+1);
122 
123  ASSERT (f - first_field);
124  /* Field count in this template */
125  t->id_count = ipfix_id_count (256 /* template_id */, f - first_field);
126 
127  /* set length in octets*/
128  s->set_id_length = ipfix_set_id_length (2 /* set_id */, (u8 *) f - (u8 *)s);
129 
130  /* message length in octets */
131  h->version_length = version_length ((u8 *)f - (u8 *)h);
132 
133  ip->length = clib_host_to_net_u16 ((u8 *)f - (u8 *)ip);
134  ip->checksum = ip4_header_checksum (ip);
135 
136  return rewrite;
137 }
138 
140  flow_report_t * fr,
141  vlib_frame_t * f, u32 * to_next,
142  u32 node_index)
143 {
147  vnet_classify_table_t * t =
148  pool_elt_at_index (vcm->tables, fsm->classify_table_index);
150  vnet_classify_entry_t * v, * save_v;
151  vlib_buffer_t *b0 = 0;
152  u32 next_offset = 0;
153  u32 bi0 = ~0;
154  int i, j, k;
157  ipfix_set_header_t * s = 0;
158  ip4_header_t * ip;
159  udp_header_t * udp;
160  int field_index;
161  ip4_header_t * match;
162  u32 records_this_buffer;
163  u16 new_l0, old_l0;
164  ip_csum_t sum0;
165  vlib_main_t * vm = frm->vlib_main;
166 
167  while (__sync_lock_test_and_set (t->writer_lock, 1))
168  ;
169 
170  for (i = 0; i < t->nbuckets; i++)
171  {
172  b = &t->buckets [i];
173  if (b->offset == 0)
174  continue;
175 
176  save_v = vnet_classify_get_entry (t, b->offset);
177  for (j = 0; j < (1<<b->log2_pages); j++)
178  {
179  for (k = 0; k < t->entries_per_page; k++)
180  {
182  (t, save_v, j*t->entries_per_page + k);
183 
185  continue;
186 
187  /* OK, we have something to send... */
188  if (PREDICT_FALSE (b0 == 0))
189  {
190  if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
191  goto flush;
192  b0 = vlib_get_buffer (vm, bi0);
193 
194  clib_memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite));
195  b0->current_data = 0;
196  b0->current_length = vec_len (fr->rewrite);
198  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
199  /* $$$ for now, look up in fib-0. Later: arbitrary TX fib */
200  vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
201 
202  tp = vlib_buffer_get_current (b0);
203  ip = (ip4_header_t *) &tp->ip4;
204  udp = (udp_header_t *) (ip+1);
205  h = (ipfix_message_header_t *)(udp+1);
206  s = (ipfix_set_header_t *)(h+1);
207 
208  /* FIXUP: message header export_time */
209  h->export_time = (u32)
210  (((f64)frm->unix_time_0) +
211  (vlib_time_now(frm->vlib_main) - frm->vlib_time_0));
212  h->export_time = clib_host_to_net_u32(h->export_time);
213 
214  /* FIXUP: message header sequence_number */
215  h->sequence_number = fr->sequence_number++;
216  h->sequence_number = clib_host_to_net_u32 (h->sequence_number);
217  next_offset = (u32) (((u8 *)(s+1)) - (u8 *)tp);
218  records_this_buffer = 0;
219  }
220 
221  field_index = 0;
222  match = (ip4_header_t *) (((u8 *)v->key) - 2);
223  ip = match;
224  udp = (udp_header_t * )(ip+1);
225 
226 #define _(field,mask,item,length) \
227  if (clib_bitmap_get (fr->fields_to_send, field_index)) \
228  { \
229  clib_memcpy (b0->data + next_offset, &field, \
230  length); \
231  next_offset += length; \
232  } \
233  field_index++;
235 #undef _
236 
237  /* Add packetTotalCount manually */
238  {
239  u64 packets = clib_host_to_net_u64 (v->hits);
240  clib_memcpy (b0->data + next_offset, &packets, sizeof (packets));
241  next_offset += sizeof (packets);
242  }
243  records_this_buffer++;
244 
245  if (next_offset > 1450)
246  {
247  s->set_id_length = ipfix_set_id_length (256 /* template ID*/,
248  next_offset -
249  (sizeof (*ip) + sizeof (*udp) +
250  sizeof (*h)));
251  b0->current_length = next_offset;
253 
254  tp = vlib_buffer_get_current (b0);
255  ip = (ip4_header_t *) &tp->ip4;
256  udp = (udp_header_t *) (ip+1);
257 
258  sum0 = ip->checksum;
259  old_l0 = clib_net_to_host_u16 (ip->length);
260  new_l0 =
261  clib_host_to_net_u16 ((u16)next_offset);
262 
263  sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
264  length /* changed member */);
265 
266  ip->checksum = ip_csum_fold (sum0);
267  ip->length = new_l0;
268  udp->length =
269  clib_host_to_net_u16 (b0->current_length - sizeof (ip));
270 
271  to_next[0] = bi0;
272  f->n_vectors++;
273  to_next++;
274 
275  if (f->n_vectors == VLIB_FRAME_SIZE)
276  {
277  vlib_put_frame_to_node (vm, node_index, f);
278  f = vlib_get_frame_to_node (vm, node_index);
279  f->n_vectors = 0;
280  to_next = vlib_frame_vector_args (f);
281  }
282  b0 = 0;
283  bi0 = ~0;
284  }
285  }
286  }
287  }
288 
289  flush:
290  if (b0)
291  {
292  s->set_id_length = ipfix_set_id_length (256 /* template ID*/,
293  next_offset -
294  (sizeof (*ip) + sizeof (*udp) +
295  sizeof (*h)));
296  b0->current_length = next_offset;
298 
299  tp = vlib_buffer_get_current (b0);
300  ip = (ip4_header_t *) &tp->ip4;
301  udp = (udp_header_t *) (ip+1);
302 
303  sum0 = ip->checksum;
304  old_l0 = ip->length;
305  new_l0 = clib_host_to_net_u16 ((u16)next_offset);
306 
307  sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
308  length /* changed member */);
309 
310  ip->checksum = ip_csum_fold (sum0);
311  ip->length = new_l0;
312  udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
313 
314  ASSERT (ip->checksum == ip4_header_checksum (ip));
315 
316  to_next[0] = bi0;
317  f->n_vectors++;
318 
319  b0 = 0;
320  bi0 = ~0;
321  }
322 
323  *(t->writer_lock) = 0;
324  return f;
325 }
326 
327 
328 static clib_error_t *
330  unformat_input_t * input,
331  vlib_cli_command_t * cmd)
332 {
336  int rv;
337  int is_add = 1;
338  u32 domain_id = 0;
339 
340  domain_id = 0;
341  fsm->classify_table_index = ~0;
342  memset (&args, 0, sizeof (args));
343 
344  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
345  if (unformat (input, "table %d", &fsm->classify_table_index))
346  ;
347  else if (unformat (input, "domain %d", &domain_id))
348  ;
349  else if (unformat (input, "del"))
350  is_add = 0;
351  else
352  return clib_error_return (0, "unknown input `%U'",
353  format_unformat_error, input);
354  }
355 
356  if (fsm->classify_table_index == ~0)
357  return clib_error_return (0, "classifier table not specified");
358 
359  args.opaque = (void *) fsm;
362  args.is_add = is_add;
363  args.domain_id = domain_id;
364 
365  rv = vnet_flow_report_add_del (frm, &args);
366 
367  switch (rv)
368  {
369  case 0:
370  break;
371  case VNET_API_ERROR_NO_SUCH_ENTRY:
372  return clib_error_return (0, "registration not found...");
373  default:
374  return clib_error_return (0, "vnet_flow_report_add_del returned %d", rv);
375  }
376 
377  return 0;
378 }
379 
380 VLIB_CLI_COMMAND (flow_sample_command, static) = {
381  .path = "flow sample",
382  .short_help = "flow sample",
383  .function = flow_sample_command_fn,
384 };
385 
386 static clib_error_t *
388 {
389  clib_error_t * error;
390 
391  if ((error = vlib_call_init_function (vm, flow_report_init)))
392  return error;
393 
394  return 0;
395 }
396 
flow_report_main_t flow_report_main
Definition: flow_report.h:90
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
static u32 ipfix_e_id_length(int e, u16 id, u16 length)
Definition: ipfix_packet.h:72
void * opaque
Definition: flow_report.h:65
uword ip_csum_t
Definition: ip_packet.h:86
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:405
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:77
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
vnet_flow_rewrite_callback_t * rewrite_callback
Definition: flow_report.h:98
int i32
Definition: types.h:81
unsigned long u64
Definition: types.h:89
#define vlib_call_init_function(vm, x)
Definition: init.h:159
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
flow_report_sample_main_t flow_report_sample_main
static int vnet_classify_entry_is_free(vnet_classify_entry_t *e)
Definition: vnet_classify.h:89
always_inline u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:138
#define pool_elt_at_index(p, i)
Definition: pool.h:346
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
u8 * rewrite
Definition: flow_report.h:55
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_FRAME_SIZE
Definition: node.h:292
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:191
static u32 version_length(u16 length)
Definition: ipfix_packet.h:31
static vnet_classify_entry_t * vnet_classify_entry_at_index(vnet_classify_table_t *t, vnet_classify_entry_t *e, u32 index)
always_inline u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
u32 sequence_number
Definition: flow_report.h:56
u16 n_vectors
Definition: node.h:307
static clib_error_t * flow_report_sample_init(vlib_main_t *vm)
static u32 ipfix_id_count(u16 id, u16 count)
Definition: ipfix_packet.h:175
static u8 * template_rewrite(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address)
#define clib_memcpy(a, b, c)
Definition: string.h:63
#define VLIB_BUFFER_TOTAL_LENGTH_VALID
Definition: buffer.h:95
static vlib_frame_t * send_flows(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:150
struct _vnet_classify_main vnet_classify_main_t
Definition: vnet_classify.h:50
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
vlib_main_t * vlib_main
Definition: flow_report.h:86
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
#define vnet_buffer(b)
Definition: buffer.h:300
vnet_classify_main_t vnet_classify_main
Definition: vnet_classify.c:21
u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer.c:770
static u32 ipfix_set_id_length(u16 set_id, u16 length)
Definition: ipfix_packet.h:114
Definition: defs.h:46
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:140
unsigned char u8
Definition: types.h:56
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:133
vnet_flow_data_callback_t * flow_data_callback
Definition: flow_report.h:97
#define foreach_ipfix_field
static clib_error_t * flow_sample_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u8 data[0]
Packet data.
Definition: buffer.h:150
always_inline f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
#define clib_error_return(e, args...)
Definition: error.h:112
struct _unformat_input_t unformat_input_t
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:184
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
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
static clib_error_t * flow_report_init(vlib_main_t *vm)
Definition: flow_report.c:256
Definition: defs.h:45
static vnet_classify_entry_t * vnet_classify_get_entry(vnet_classify_table_t *t, uword offset)
int vnet_flow_report_add_del(flow_report_main_t *frm, vnet_flow_report_add_del_args_t *a)
Definition: flow_report.c:169