FD.io VPP  v16.09
Vector Packet Processing
sr_replicate.c
Go to the documentation of this file.
1 /*
2  * sr_replicate.c: ipv6 segment routing replicator for multicast
3  *
4  * Copyright (c) 2016 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /**
18  * @file
19  * @brief Functions for replicating packets across SR tunnels.
20  *
21  * Leverages rte_pktmbuf_clone() so there is no memcpy for
22  * invariant parts of the packet.
23  *
24  * @note Currently requires DPDK
25 */
26 
27 #if DPDK > 0 /* Cannot run replicate without DPDK */
28 #include <vlib/vlib.h>
29 #include <vnet/vnet.h>
30 #include <vnet/pg/pg.h>
31 #include <vnet/sr/sr.h>
32 #include <vnet/devices/dpdk/dpdk.h>
33 #include <vnet/dpdk_replication.h>
34 #include <vnet/ip/ip.h>
35 
36 #include <vppinfra/hash.h>
37 #include <vppinfra/error.h>
38 #include <vppinfra/elog.h>
39 
40 /**
41  * @brief sr_replicate state.
42  *
43 */
44 typedef struct
45 {
46  /* convenience */
50 
52 
53 /**
54  * @brief Information to display in packet trace.
55  *
56 */
57 typedef struct
58 {
63  u8 sr[256];
65 
66 /**
67  * @brief packet trace format function.
68  *
69  * @param *s u8 used for string output
70  * @param *args va_list structured input to va_arg to output @ref sr_replicate_trace_t
71  * @return *s u8 - formatted trace output
72 */
73 static u8 *
74 format_sr_replicate_trace (u8 * s, va_list * args)
75 {
76  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
77  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
78  sr_replicate_trace_t *t = va_arg (*args, sr_replicate_trace_t *);
79  ip6_main_t *im = &ip6_main;
80  ip6_sr_main_t *sm = &sr_main;
82  ip6_fib_t *rx_fib, *tx_fib;
83 
86 
89 
90  s = format
91  (s, "SR-REPLICATE: next %s ip6 src %U dst %U len %u\n"
92  " rx-fib-id %d tx-fib-id %d\n%U",
93  "ip6-lookup",
95  format_ip6_address, &t->dst, t->length,
96  rx_fib->table_id, tx_fib->table_id,
97  format_ip6_sr_header, t->sr, 0 /* print_hmac */ );
98  return s;
99 
100 }
101 
102 #define foreach_sr_replicate_error \
103 _(REPLICATED, "sr packets replicated") \
104 _(NO_BUFFERS, "error allocating buffers for replicas") \
105 _(NO_REPLICAS, "no replicas were needed") \
106 _(NO_BUFFER_DROPS, "sr no buffer drops")
107 
108 /**
109  * @brief Struct for SR replicate errors
110  */
111 typedef enum
112 {
113 #define _(sym,str) SR_REPLICATE_ERROR_##sym,
115 #undef _
118 
119 /**
120  * @brief Error strings for SR replicate
121  */
122 static char *sr_replicate_error_strings[] = {
123 #define _(sym,string) string,
125 #undef _
126 };
127 
128 /**
129  * @brief Defines next-nodes for packet processing.
130  *
131 */
132 typedef enum
133 {
137 
138 /**
139  * @brief Single loop packet replicator.
140  *
141  * @node sr-replicate
142  * @param vm vlib_main_t
143  * @return frame->n_vectors uword
144 */
145 static uword
147  vlib_node_runtime_t * node, vlib_frame_t * frame)
148 {
149  u32 n_left_from, *from, *to_next;
150  sr_replicate_next_t next_index;
151  int pkts_replicated = 0;
152  ip6_sr_main_t *sm = &sr_main;
153  int no_buffer_drops = 0;
155  unsigned socket_id = rte_socket_id ();
157 
158  from = vlib_frame_vector_args (frame);
159  n_left_from = frame->n_vectors;
160  next_index = node->cached_next_index;
161 
163 
164  while (n_left_from > 0)
165  {
166  u32 n_left_to_next;
167 
168  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
169 
170  while (n_left_from > 0 && n_left_to_next > 0)
171  {
172  u32 bi0, hdr_bi0;
173  vlib_buffer_t *b0, *orig_b0;
174  struct rte_mbuf *orig_mb0 = 0, *hdr_mb0 = 0, *clone0 = 0;
175  struct rte_mbuf **hdr_vec = 0, **rte_mbuf_vec = 0;
176  ip6_sr_policy_t *pol0 = 0;
177  ip6_sr_tunnel_t *t0 = 0;
178  ip6_sr_header_t *hdr_sr0 = 0;
179  ip6_header_t *ip0 = 0, *hdr_ip0 = 0;
180  int num_replicas = 0;
181  int i;
182 
183  bi0 = from[0];
184 
185  b0 = vlib_get_buffer (vm, bi0);
186  orig_b0 = b0;
187 
188  pol0 = pool_elt_at_index (sm->policies,
189  vnet_buffer (b0)->ip.save_protocol);
190 
191  ip0 = vlib_buffer_get_current (b0);
192  /* Skip forward to the punch-in point */
193  vlib_buffer_advance (b0, sizeof (*ip0));
194 
195  orig_mb0 = rte_mbuf_from_vlib_buffer (b0);
196 
197  i16 delta0 = vlib_buffer_length_in_chain (vm, orig_b0)
198  - (i16) orig_mb0->pkt_len;
199 
200  u16 new_data_len0 = (u16) ((i16) orig_mb0->data_len + delta0);
201  u16 new_pkt_len0 = (u16) ((i16) orig_mb0->pkt_len + delta0);
202 
203  orig_mb0->data_len = new_data_len0;
204  orig_mb0->pkt_len = new_pkt_len0;
205  orig_mb0->data_off =
206  (u16) (RTE_PKTMBUF_HEADROOM + b0->current_data);
207 
208  /*
209  Before entering loop determine if we can allocate:
210  - all the new HEADER RTE_MBUFs and assign them to a vector
211  - all the clones
212 
213  if successful, then iterate over vectors of resources
214 
215  */
216  num_replicas = vec_len (pol0->tunnel_indices);
217 
218  if (PREDICT_FALSE (num_replicas == 0))
219  {
220  b0->error = node->errors[SR_REPLICATE_ERROR_NO_REPLICAS];
221  goto do_trace0;
222  }
223 
224  vec_reset_length (hdr_vec);
225  vec_reset_length (rte_mbuf_vec);
226 
227  for (i = 0; i < num_replicas; i++)
228  {
229  hdr_mb0 = rte_pktmbuf_alloc (bm->pktmbuf_pools[socket_id]);
230 
231  if (i < (num_replicas - 1))
232  /* Not the last tunnel to process */
233  clone0 = rte_pktmbuf_clone
234  (orig_mb0, bm->pktmbuf_pools[socket_id]);
235  else
236  /* Last tunnel to process, use original MB */
237  clone0 = orig_mb0;
238 
239 
240  if (PREDICT_FALSE (!clone0 || !hdr_mb0))
241  {
242  b0->error = node->errors[SR_REPLICATE_ERROR_NO_BUFFERS];
243 
244  vec_foreach_index (i, rte_mbuf_vec)
245  {
246  rte_pktmbuf_free (rte_mbuf_vec[i]);
247  }
248  vec_free (rte_mbuf_vec);
249 
250  vec_foreach_index (i, hdr_vec)
251  {
252  rte_pktmbuf_free (hdr_vec[i]);
253  }
254  vec_free (hdr_vec);
255 
256  goto do_trace0;
257  }
258 
259  vec_add1 (hdr_vec, hdr_mb0);
260  vec_add1 (rte_mbuf_vec, clone0);
261 
262  }
263 
264  for (i = 0; i < num_replicas; i++)
265  {
266  vlib_buffer_t *hdr_b0;
267 
268  t0 = vec_elt_at_index (sm->tunnels, pol0->tunnel_indices[i]);
269 
270  /* Our replicas */
271  hdr_mb0 = hdr_vec[i];
272  clone0 = rte_mbuf_vec[i];
273 
274  hdr_mb0->data_len = sizeof (*ip0) + vec_len (t0->rewrite);
275  hdr_mb0->pkt_len = hdr_mb0->data_len +
276  vlib_buffer_length_in_chain (vm, orig_b0);
277 
278  hdr_b0 = vlib_buffer_from_rte_mbuf (hdr_mb0);
279 
280  vlib_buffer_init_for_free_list (hdr_b0, fl);
281 
282  memcpy (hdr_b0->data, ip0, sizeof (*ip0));
283  memcpy (hdr_b0->data + sizeof (*ip0), t0->rewrite,
284  vec_len (t0->rewrite));
285 
286  hdr_b0->current_data = 0;
287  hdr_b0->current_length = sizeof (*ip0) + vec_len (t0->rewrite);
288  hdr_b0->flags = orig_b0->flags | VLIB_BUFFER_NEXT_PRESENT;
289 
290 
292  hdr_mb0->pkt_len - hdr_b0->current_length;
293 
294  hdr_ip0 = (ip6_header_t *) hdr_b0->data;
295  hdr_ip0->payload_length =
296  clib_host_to_net_u16 (hdr_mb0->data_len);
297  hdr_sr0 = (ip6_sr_header_t *) (hdr_ip0 + 1);
298  hdr_sr0->protocol = hdr_ip0->protocol;
299  hdr_ip0->protocol = 43;
300 
301  /* Rewrite the ip6 dst address */
302  hdr_ip0->dst_address.as_u64[0] = t0->first_hop.as_u64[0];
303  hdr_ip0->dst_address.as_u64[1] = t0->first_hop.as_u64[1];
304 
305  sr_fix_hmac (sm, hdr_ip0, hdr_sr0);
306 
307  /* prepend new header to invariant piece */
308  hdr_mb0->next = clone0;
309  hdr_b0->next_buffer =
311  vlib_buffer_from_rte_mbuf (clone0));
312 
313  /* update header's fields */
314  hdr_mb0->pkt_len =
315  (uint16_t) (hdr_mb0->data_len + clone0->pkt_len);
316  hdr_mb0->nb_segs = (uint8_t) (clone0->nb_segs + 1);
317 
318  /* copy metadata from source packet */
319  hdr_mb0->port = clone0->port;
320  hdr_mb0->vlan_tci = clone0->vlan_tci;
321  hdr_mb0->vlan_tci_outer = clone0->vlan_tci_outer;
322  hdr_mb0->tx_offload = clone0->tx_offload;
323  hdr_mb0->hash = clone0->hash;
324 
325  hdr_mb0->ol_flags = clone0->ol_flags;
326 
327  __rte_mbuf_sanity_check (hdr_mb0, 1);
328 
329  hdr_bi0 = vlib_get_buffer_index (vm, hdr_b0);
330 
331  to_next[0] = hdr_bi0;
332  to_next += 1;
333  n_left_to_next -= 1;
334 
335  if (n_left_to_next == 0)
336  {
337  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
338  vlib_get_next_frame (vm, node, next_index,
339  to_next, n_left_to_next);
340 
341  }
342  pkts_replicated++;
343  }
344 
345  from += 1;
346  n_left_from -= 1;
347 
348  do_trace0:
350  {
351  sr_replicate_trace_t *tr = vlib_add_trace (vm, node,
352  b0, sizeof (*tr));
353  tr->tunnel_index = t0 - sm->tunnels;
354  tr->length = 0;
355  if (hdr_ip0)
356  {
357  memcpy (tr->src.as_u8, hdr_ip0->src_address.as_u8,
358  sizeof (tr->src.as_u8));
359  memcpy (tr->dst.as_u8, hdr_ip0->dst_address.as_u8,
360  sizeof (tr->dst.as_u8));
361  if (hdr_ip0->payload_length)
362  tr->length = clib_net_to_host_u16
363  (hdr_ip0->payload_length);
364  }
365  tr->next_index = next_index;
366  if (hdr_sr0)
367  memcpy (tr->sr, hdr_sr0, sizeof (tr->sr));
368  }
369 
370  }
371 
372  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
373  }
374 
376  SR_REPLICATE_ERROR_REPLICATED,
377  pkts_replicated);
378 
380  SR_REPLICATE_ERROR_NO_BUFFER_DROPS,
381  no_buffer_drops);
382 
383  return frame->n_vectors;
384 }
385 
386 /* *INDENT-OFF* */
388  .function = sr_replicate_node_fn,
389  .name = "sr-replicate",
390  .vector_size = sizeof (u32),
391  .format_trace = format_sr_replicate_trace,
393 
395  .error_strings = sr_replicate_error_strings,
396 
397  .n_next_nodes = SR_REPLICATE_N_NEXT,
398 
399  .next_nodes = {
400  [SR_REPLICATE_NEXT_IP6_LOOKUP] = "ip6-lookup",
401  },
402 };
403 /* *INDENT-ON* */
404 
407 {
409 
410  msm->vlib_main = vm;
411  msm->vnet_main = vnet_get_main ();
412 
413  return 0;
414 }
415 
417 
418 #endif /* DPDK */
419 
420 /*
421  * fd.io coding-style-patch-verification: ON
422  *
423  * Local Variables:
424  * eval: (c-set-style "gnu")
425  * End:
426  */
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:457
ip6_sr_main_t sr_main
Definition: sr.c:28
clib_error_t * sr_replicate_init(vlib_main_t *vm)
Definition: sr_replicate.c:406
#define vec_foreach_index(var, v)
Iterate over vector indices.
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define CLIB_UNUSED(x)
Definition: clib.h:79
#define rte_mbuf_from_vlib_buffer(x)
Definition: buffer.h:382
ip6_address_t src
Definition: sr_replicate.c:59
u32 tx_fib_index
TX Fib index.
Definition: sr.h:66
format_function_t format_ip6_address
Definition: format.h:87
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
u8 as_u8[16]
Definition: ip6_packet.h:47
u64 as_u64[2]
Definition: ip6_packet.h:50
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
unsigned rte_socket_id()
vlib_buffer_main_t * buffer_main
Definition: main.h:104
u32 rx_fib_index
RX Fib index.
Definition: sr.h:64
static uword sr_replicate_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Single loop packet replicator.
Definition: sr_replicate.c:146
vlib_error_t * errors
Definition: node.h:418
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:112
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static void vlib_buffer_init_for_free_list(vlib_buffer_t *_dst, vlib_buffer_free_list_t *fl)
Definition: buffer_funcs.h:606
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:78
ip6_address_t dst
Definition: sr_replicate.c:59
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:187
ip6_fib_t * find_ip6_fib_by_table_index_or_id(ip6_main_t *im, u32 table_index_or_id, u32 flags)
Get or create an IPv6 fib.
Definition: ip6_forward.c:185
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u8 protocol
Protocol for next header.
Definition: sr_packet.h:180
Information to display in packet trace.
Definition: sr_replicate.c:57
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:82
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:95
unsigned char uint8_t
Definition: fix_types.h:27
vlib_main_t * vlib_main
Definition: sr_replicate.c:47
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
unsigned short int uint16_t
Definition: fix_types.h:28
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:348
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:118
static u8 * format_sr_replicate_trace(u8 *s, va_list *args)
packet trace format function.
Definition: sr_replicate.c:74
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1111
u8 * rewrite
The actual ip6 SR header.
Definition: sr.h:69
struct rte_mempool ** pktmbuf_pools
Definition: buffer.h:321
u16 n_vectors
Definition: node.h:344
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
Definition: ip6.h:64
static char * sr_replicate_error_strings[]
Error strings for SR replicate.
Definition: sr_replicate.c:122
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:200
u32 * tunnel_indices
vector to SR tunnel index
Definition: sr.h:155
#define ARRAY_LEN(x)
Definition: clib.h:59
sr_replicate state.
Definition: sr_replicate.c:44
void sr_fix_hmac(ip6_sr_main_t *sm, ip6_header_t *ip, ip6_sr_header_t *sr)
Use passed HMAC key in ip6_sr_header_t in OpenSSL HMAC routines.
Definition: sr.c:39
Segment Route tunnel.
Definition: sr.h:49
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:303
ip6_address_t first_hop
First hop, to save 1 elt in the segment list.
Definition: sr.h:61
u16 cached_next_index
Definition: node.h:462
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:335
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:114
ip6_sr_tunnel_t * tunnels
pool of tunnel instances, sr entry only
Definition: sr.h:185
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
#define IP6_ROUTE_FLAG_FIB_INDEX
Definition: ip6.h:354
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:109
format_function_t format_ip6_sr_header
Definition: sr.h:239
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
Segment Routing policy.
Definition: sr.h:149
ip6_sr_policy_t * policies
policy pool
Definition: sr.h:194
SR header struct.
Definition: sr_packet.h:177
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:251
sr_replicate_error_t
Struct for SR replicate errors.
Definition: sr_replicate.c:111
#define foreach_sr_replicate_error
Definition: sr_replicate.c:102
short i16
Definition: types.h:46
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
Segment Routing header.
Segment Routing state.
Definition: sr.h:182
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
#define vlib_buffer_from_rte_mbuf(x)
Definition: buffer.h:383
u8 data[0]
Packet data.
Definition: buffer.h:151
sr_replicate_main_t sr_replicate_main
Definition: sr_replicate.c:51
vnet_main_t * vnet_main
Definition: sr_replicate.c:48
u32 table_id
Definition: ip6.h:66
static vlib_buffer_free_list_t * vlib_buffer_get_free_list(vlib_main_t *vm, u32 free_list_index)
Definition: buffer_funcs.h:337
vlib_node_registration_t sr_replicate_node
(constructor) VLIB_REGISTER_NODE (sr_replicate_node)
Definition: sr_replicate.c:387
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
sr_replicate_next_t
Defines next-nodes for packet processing.
Definition: sr_replicate.c:132