FD.io VPP  v16.12-rc0-308-g931be3a
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 #include <vnet/fib/ip6_fib.h>
36 
37 #include <vppinfra/hash.h>
38 #include <vppinfra/error.h>
39 #include <vppinfra/elog.h>
40 
41 /**
42  * @brief sr_replicate state.
43  *
44 */
45 typedef struct
46 {
47  /* convenience */
51 
53 
54 /**
55  * @brief Information to display in packet trace.
56  *
57 */
58 typedef struct
59 {
64  u8 sr[256];
66 
67 /**
68  * @brief packet trace format function.
69  *
70  * @param *s u8 used for string output
71  * @param *args va_list structured input to va_arg to output @ref sr_replicate_trace_t
72  * @return *s u8 - formatted trace output
73 */
74 static u8 *
75 format_sr_replicate_trace (u8 * s, va_list * args)
76 {
77  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
78  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
79  sr_replicate_trace_t *t = va_arg (*args, sr_replicate_trace_t *);
80  ip6_sr_main_t *sm = &sr_main;
82  ip6_fib_t *rx_fib, *tx_fib;
83 
84  rx_fib = ip6_fib_get (tun->rx_fib_index);
85  tx_fib = ip6_fib_get (tun->tx_fib_index);
86 
87  s = format
88  (s, "SR-REPLICATE: next %s ip6 src %U dst %U len %u\n"
89  " rx-fib-id %d tx-fib-id %d\n%U",
90  "ip6-lookup",
92  format_ip6_address, &t->dst, t->length,
93  rx_fib->table_id, tx_fib->table_id,
94  format_ip6_sr_header, t->sr, 0 /* print_hmac */ );
95  return s;
96 
97 }
98 
99 #define foreach_sr_replicate_error \
100 _(REPLICATED, "sr packets replicated") \
101 _(NO_BUFFERS, "error allocating buffers for replicas") \
102 _(NO_REPLICAS, "no replicas were needed") \
103 _(NO_BUFFER_DROPS, "sr no buffer drops")
104 
105 /**
106  * @brief Struct for SR replicate errors
107  */
108 typedef enum
109 {
110 #define _(sym,str) SR_REPLICATE_ERROR_##sym,
112 #undef _
115 
116 /**
117  * @brief Error strings for SR replicate
118  */
119 static char *sr_replicate_error_strings[] = {
120 #define _(sym,string) string,
122 #undef _
123 };
124 
125 /**
126  * @brief Defines next-nodes for packet processing.
127  *
128 */
129 typedef enum
130 {
134 
135 /**
136  * @brief Single loop packet replicator.
137  *
138  * @node sr-replicate
139  * @param vm vlib_main_t
140  * @return frame->n_vectors uword
141 */
142 static uword
144  vlib_node_runtime_t * node, vlib_frame_t * frame)
145 {
146  u32 n_left_from, *from, *to_next;
147  sr_replicate_next_t next_index;
148  int pkts_replicated = 0;
149  ip6_sr_main_t *sm = &sr_main;
150  int no_buffer_drops = 0;
152  unsigned socket_id = rte_socket_id ();
154 
155  from = vlib_frame_vector_args (frame);
156  n_left_from = frame->n_vectors;
157  next_index = node->cached_next_index;
158 
160 
161  while (n_left_from > 0)
162  {
163  u32 n_left_to_next;
164 
165  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
166 
167  while (n_left_from > 0 && n_left_to_next > 0)
168  {
169  u32 bi0, hdr_bi0;
170  vlib_buffer_t *b0, *orig_b0;
171  struct rte_mbuf *orig_mb0 = 0, *hdr_mb0 = 0, *clone0 = 0;
172  struct rte_mbuf **hdr_vec = 0, **rte_mbuf_vec = 0;
173  ip6_sr_policy_t *pol0 = 0;
174  ip6_sr_tunnel_t *t0 = 0;
175  ip6_sr_header_t *hdr_sr0 = 0;
176  ip6_header_t *ip0 = 0, *hdr_ip0 = 0;
177  int num_replicas = 0;
178  int i;
179 
180  bi0 = from[0];
181 
182  b0 = vlib_get_buffer (vm, bi0);
183  orig_b0 = b0;
184 
185  pol0 = pool_elt_at_index (sm->policies,
186  vnet_buffer (b0)->ip.save_protocol);
187 
188  ip0 = vlib_buffer_get_current (b0);
189  /* Skip forward to the punch-in point */
190  vlib_buffer_advance (b0, sizeof (*ip0));
191 
192  orig_mb0 = rte_mbuf_from_vlib_buffer (b0);
193 
194  i16 delta0 = vlib_buffer_length_in_chain (vm, orig_b0)
195  - (i16) orig_mb0->pkt_len;
196 
197  u16 new_data_len0 = (u16) ((i16) orig_mb0->data_len + delta0);
198  u16 new_pkt_len0 = (u16) ((i16) orig_mb0->pkt_len + delta0);
199 
200  orig_mb0->data_len = new_data_len0;
201  orig_mb0->pkt_len = new_pkt_len0;
202  orig_mb0->data_off =
203  (u16) (RTE_PKTMBUF_HEADROOM + b0->current_data);
204 
205  /*
206  Before entering loop determine if we can allocate:
207  - all the new HEADER RTE_MBUFs and assign them to a vector
208  - all the clones
209 
210  if successful, then iterate over vectors of resources
211 
212  */
213  num_replicas = vec_len (pol0->tunnel_indices);
214 
215  if (PREDICT_FALSE (num_replicas == 0))
216  {
217  b0->error = node->errors[SR_REPLICATE_ERROR_NO_REPLICAS];
218  goto do_trace0;
219  }
220 
221  vec_reset_length (hdr_vec);
222  vec_reset_length (rte_mbuf_vec);
223 
224  for (i = 0; i < num_replicas; i++)
225  {
226  hdr_mb0 = rte_pktmbuf_alloc (bm->pktmbuf_pools[socket_id]);
227 
228  if (i < (num_replicas - 1))
229  /* Not the last tunnel to process */
230  clone0 = rte_pktmbuf_clone
231  (orig_mb0, bm->pktmbuf_pools[socket_id]);
232  else
233  /* Last tunnel to process, use original MB */
234  clone0 = orig_mb0;
235 
236 
237  if (PREDICT_FALSE (!clone0 || !hdr_mb0))
238  {
239  b0->error = node->errors[SR_REPLICATE_ERROR_NO_BUFFERS];
240 
241  vec_foreach_index (i, rte_mbuf_vec)
242  {
243  rte_pktmbuf_free (rte_mbuf_vec[i]);
244  }
245  vec_free (rte_mbuf_vec);
246 
247  vec_foreach_index (i, hdr_vec)
248  {
249  rte_pktmbuf_free (hdr_vec[i]);
250  }
251  vec_free (hdr_vec);
252 
253  goto do_trace0;
254  }
255 
256  vec_add1 (hdr_vec, hdr_mb0);
257  vec_add1 (rte_mbuf_vec, clone0);
258 
259  }
260 
261  for (i = 0; i < num_replicas; i++)
262  {
263  vlib_buffer_t *hdr_b0;
264 
265  t0 = vec_elt_at_index (sm->tunnels, pol0->tunnel_indices[i]);
266 
267  /* Our replicas */
268  hdr_mb0 = hdr_vec[i];
269  clone0 = rte_mbuf_vec[i];
270 
271  hdr_mb0->data_len = sizeof (*ip0) + vec_len (t0->rewrite);
272  hdr_mb0->pkt_len = hdr_mb0->data_len +
273  vlib_buffer_length_in_chain (vm, orig_b0);
274 
275  hdr_b0 = vlib_buffer_from_rte_mbuf (hdr_mb0);
276 
277  vlib_buffer_init_for_free_list (hdr_b0, fl);
278 
279  memcpy (hdr_b0->data, ip0, sizeof (*ip0));
280  memcpy (hdr_b0->data + sizeof (*ip0), t0->rewrite,
281  vec_len (t0->rewrite));
282 
283  hdr_b0->current_data = 0;
284  hdr_b0->current_length = sizeof (*ip0) + vec_len (t0->rewrite);
285  hdr_b0->flags = orig_b0->flags | VLIB_BUFFER_NEXT_PRESENT;
286 
287 
289  hdr_mb0->pkt_len - hdr_b0->current_length;
290 
291  hdr_ip0 = (ip6_header_t *) hdr_b0->data;
292  hdr_ip0->payload_length =
293  clib_host_to_net_u16 (hdr_mb0->data_len);
294  hdr_sr0 = (ip6_sr_header_t *) (hdr_ip0 + 1);
295  hdr_sr0->protocol = hdr_ip0->protocol;
296  hdr_ip0->protocol = 43;
297 
298  /* Rewrite the ip6 dst address */
299  hdr_ip0->dst_address.as_u64[0] = t0->first_hop.as_u64[0];
300  hdr_ip0->dst_address.as_u64[1] = t0->first_hop.as_u64[1];
301 
302  sr_fix_hmac (sm, hdr_ip0, hdr_sr0);
303 
304  /* prepend new header to invariant piece */
305  hdr_mb0->next = clone0;
306  hdr_b0->next_buffer =
308  vlib_buffer_from_rte_mbuf (clone0));
309 
310  /* update header's fields */
311  hdr_mb0->pkt_len =
312  (uint16_t) (hdr_mb0->data_len + clone0->pkt_len);
313  hdr_mb0->nb_segs = (uint8_t) (clone0->nb_segs + 1);
314 
315  /* copy metadata from source packet */
316  hdr_mb0->port = clone0->port;
317  hdr_mb0->vlan_tci = clone0->vlan_tci;
318  hdr_mb0->vlan_tci_outer = clone0->vlan_tci_outer;
319  hdr_mb0->tx_offload = clone0->tx_offload;
320  hdr_mb0->hash = clone0->hash;
321 
322  hdr_mb0->ol_flags = clone0->ol_flags;
323 
324  __rte_mbuf_sanity_check (hdr_mb0, 1);
325 
326  hdr_bi0 = vlib_get_buffer_index (vm, hdr_b0);
327 
328  to_next[0] = hdr_bi0;
329  to_next += 1;
330  n_left_to_next -= 1;
331 
332  if (n_left_to_next == 0)
333  {
334  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
335  vlib_get_next_frame (vm, node, next_index,
336  to_next, n_left_to_next);
337 
338  }
339  pkts_replicated++;
340  }
341 
342  from += 1;
343  n_left_from -= 1;
344 
345  do_trace0:
347  {
348  sr_replicate_trace_t *tr = vlib_add_trace (vm, node,
349  b0, sizeof (*tr));
350  tr->tunnel_index = t0 - sm->tunnels;
351  tr->length = 0;
352  if (hdr_ip0)
353  {
354  memcpy (tr->src.as_u8, hdr_ip0->src_address.as_u8,
355  sizeof (tr->src.as_u8));
356  memcpy (tr->dst.as_u8, hdr_ip0->dst_address.as_u8,
357  sizeof (tr->dst.as_u8));
358  if (hdr_ip0->payload_length)
359  tr->length = clib_net_to_host_u16
360  (hdr_ip0->payload_length);
361  }
362  tr->next_index = next_index;
363  if (hdr_sr0)
364  memcpy (tr->sr, hdr_sr0, sizeof (tr->sr));
365  }
366 
367  }
368 
369  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
370  }
371 
373  SR_REPLICATE_ERROR_REPLICATED,
374  pkts_replicated);
375 
377  SR_REPLICATE_ERROR_NO_BUFFER_DROPS,
378  no_buffer_drops);
379 
380  return frame->n_vectors;
381 }
382 
383 /* *INDENT-OFF* */
385  .function = sr_replicate_node_fn,
386  .name = "sr-replicate",
387  .vector_size = sizeof (u32),
388  .format_trace = format_sr_replicate_trace,
390 
392  .error_strings = sr_replicate_error_strings,
393 
394  .n_next_nodes = SR_REPLICATE_N_NEXT,
395 
396  .next_nodes = {
397  [SR_REPLICATE_NEXT_IP6_LOOKUP] = "ip6-lookup",
398  },
399 };
400 
402 /* *INDENT-ON* */
403 
404 clib_error_t *
406 {
408 
409  msm->vlib_main = vm;
410  msm->vnet_main = vnet_get_main ();
411 
412  return 0;
413 }
414 
416 
417 #endif /* DPDK */
418 
419 /*
420  * fd.io coding-style-patch-verification: ON
421  *
422  * Local Variables:
423  * eval: (c-set-style "gnu")
424  * End:
425  */
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:30
clib_error_t * sr_replicate_init(vlib_main_t *vm)
Definition: sr_replicate.c:405
#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:385
ip6_address_t src
Definition: sr_replicate.c:60
u32 tx_fib_index
TX Fib index.
Definition: sr.h:66
static ip6_fib_t * ip6_fib_get(fib_node_index_t index)
Definition: ip6_fib.h:108
format_function_t format_ip6_address
Definition: format.h:94
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:143
vlib_error_t * errors
Definition: node.h:419
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:46
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:60
#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:190
#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:58
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:97
vlib_main_t * vlib_main
Definition: sr_replicate.c:48
#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
#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:350
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:121
static u8 * format_sr_replicate_trace(u8 *s, va_list *args)
packet trace format function.
Definition: sr_replicate.c:75
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1113
u8 * rewrite
The actual ip6 SR header.
Definition: sr.h:69
struct rte_mempool ** pktmbuf_pools
Definition: buffer.h:324
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:66
static char * sr_replicate_error_strings[]
Error strings for SR replicate.
Definition: sr_replicate.c:119
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:203
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:45
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:46
Segment Route tunnel.
Definition: sr.h:49
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:306
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:463
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:333
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:117
ip6_sr_tunnel_t * tunnels
pool of tunnel instances, sr entry only
Definition: sr.h:185
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:95
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:112
format_function_t format_ip6_sr_header
Definition: sr.h:236
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:253
sr_replicate_error_t
Struct for SR replicate errors.
Definition: sr_replicate.c:108
#define foreach_sr_replicate_error
Definition: sr_replicate.c:99
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
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define vlib_buffer_from_rte_mbuf(x)
Definition: buffer.h:386
u8 data[0]
Packet data.
Definition: buffer.h:154
sr_replicate_main_t sr_replicate_main
Definition: sr_replicate.c:52
vnet_main_t * vnet_main
Definition: sr_replicate.c:49
u32 table_id
Definition: ip6.h:68
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:384
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:129