FD.io VPP  v17.07-30-g839fa73
Vector Packet Processing
udp_ping_util.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 #include <vnet/vnet.h>
17 #include <vnet/ip/ip.h>
18 #include <vnet/ip/ip6_hop_by_hop.h>
22 #include <ioam/udp-ping/udp_ping.h>
23 
24 #define UDP_PING_REWRITE_LEN 1000
25 
26 u16
28  u16 src_port, u16 dst_port, u8 msg_type, u16 ctx)
29 {
30  /* Populate udp ping header */
31  udp_ping->udp.src_port = clib_host_to_net_u16 (src_port);
32  udp_ping->udp.dst_port = clib_host_to_net_u16 (dst_port);
33  udp_ping->udp.length = clib_host_to_net_u16 (sizeof (udp_ping_t));
34  udp_ping->udp.checksum = 0;
35  udp_ping->ping_data.probe_marker1 =
36  clib_host_to_net_u32 (UDP_PING_PROBE_MARKER1);
37  udp_ping->ping_data.probe_marker2 =
38  clib_host_to_net_u32 (UDP_PING_PROBE_MARKER2);
39  udp_ping->ping_data.version = 1;
40  udp_ping->ping_data.msg_type = msg_type;
41  udp_ping->ping_data.flags = clib_host_to_net_u16 (0);
42  udp_ping->ping_data.tel_req_vec = clib_host_to_net_u16 (0);
43  udp_ping->ping_data.hop_limit = 254;
44  udp_ping->ping_data.hop_count = 0;
45  udp_ping->ping_data.reserve = clib_host_to_net_u16 (0);
46  udp_ping->ping_data.max_len =
47  udp_ping->ping_data.cur_len = clib_host_to_net_u16 (0);
48  udp_ping->ping_data.sender_handle = clib_host_to_net_u16 (ctx);
49  udp_ping->ping_data.seq_no = clib_host_to_net_u16 (0);
50 
51  return (sizeof (udp_ping_t));
52 }
53 
54 /**
55  * @brief Frame IPv6 udp-ping probe packet.
56  *
57  * Creates IPv6 UDP-Ping probe packet along with iOAM headers.
58  *
59  */
60 int
61 udp_ping_create_ip6_pak (u8 * buf, /*u16 len, */
63  u16 src_port, u16 dst_port, u8 msg_type, u16 ctx)
64 {
65  ip6_header_t *ip0;
67  //trace_profile *profile = NULL;
68  u16 hbh_len = 0, rnd_size = 0, ip0_len = 0, udp_len = 0;
69  u16 trace_len = 0, trace_data_size = 0;
70  u16 e2e_len = sizeof (ioam_e2e_option_t) - sizeof (ip6_hop_by_hop_option_t);
71  u8 *current = NULL;
72  ioam_trace_option_t *trace_option;
73  ioam_e2e_option_t *e2e;
74 
75  ip0 = (ip6_header_t *) buf;
76 
78  clib_host_to_net_u32 (0x6 << 28);
79 
80  ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
81  ip0->hop_limit = 255;
82 
83  ip0->src_address = src;
84  ip0->dst_address = dst;
85 
86  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
87 
88  /* Calculate hbh header len */
89  //profile = trace_profile_find();
90  trace_data_size = fetch_trace_data_size (TRACE_TYPE_IF_TS_APP);
91  /* We need 2 times data for trace as packet traverse back to source */
92  trace_len = sizeof (ioam_trace_option_t) +
93  (5 * trace_data_size * 2) - sizeof (ip6_hop_by_hop_option_t);
94  //(profile->num_elts * trace_data_size * 2);
95  hbh_len = e2e_len + trace_len + sizeof (ip6_hop_by_hop_header_t);
96  rnd_size = (hbh_len + 7) & ~7;
97 
98  /* Length of header in 8 octet units, not incl first 8 octets */
99  hbh0->length = (rnd_size >> 3) - 1;
100  hbh0->protocol = IP_PROTOCOL_UDP;
101 
102  /* Populate hbh header */
103  current = (u8 *) (hbh0 + 1);
104 
105  /* Populate trace */
106  trace_option = (ioam_trace_option_t *) current;
107  trace_option->hdr.type = HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST |
109  trace_option->hdr.length = trace_len;
110  trace_option->trace_hdr.ioam_trace_type =
112 
113  trace_option->trace_hdr.data_list_elts_left = 5 * 2;
114  //profile->num_elts * 2;
115 
116  current += trace_option->hdr.length + sizeof (ip6_hop_by_hop_option_t);
117 
118  /* Populate e2e */
119  e2e = (ioam_e2e_option_t *) current;
120  e2e->hdr.type = HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE;
121  e2e->hdr.length = e2e_len;
122 
123  /* Move past hbh header */
124  current = ((u8 *) hbh0) + ((hbh0->length + 1) << 3);
125 
126  /* Populate udp ping header */
127  udp_len = udp_ping_fill_udp_data ((udp_ping_t *) current,
128  src_port, dst_port, msg_type, ctx);
129 
130  /* Calculate total length and set it in ip6 header */
131  ip0_len = ((hbh0->length + 1) << 3) + udp_len;
132  //ip0_len = (len > ip0_len) ? len : ip0_len;
133  ip0->payload_length = clib_host_to_net_u16 (ip0_len);
134 
135  return (ip0_len + sizeof (ip6_header_t));
136 }
137 
138 int
139 udp_ping_compare_flow (ip46_address_t src, ip46_address_t dst,
140  u16 start_src_port, u16 end_src_port,
141  u16 start_dst_port, u16 end_dst_port,
142  ip46_udp_ping_flow * flow)
143 {
144  if ((0 == ip46_address_cmp (&flow->src, &src)) &&
145  (0 == ip46_address_cmp (&flow->dst, &dst)) &&
146  (flow->udp_data.start_src_port == start_src_port) &&
147  (flow->udp_data.end_src_port == end_src_port) &&
148  (flow->udp_data.start_dst_port == start_dst_port) &&
149  (flow->udp_data.end_dst_port == end_dst_port))
150  {
151  return 0;
152  }
153 
154  return -1;
155 }
156 
157 void
158 udp_ping_populate_flow (ip46_address_t src, ip46_address_t dst,
159  u16 start_src_port, u16 end_src_port,
160  u16 start_dst_port, u16 end_dst_port,
161  u16 interval, u8 fault_det, ip46_udp_ping_flow * flow)
162 {
163  flow->src = src;
164  flow->dst = dst;
165  flow->udp_data.start_src_port = start_src_port;
166  flow->udp_data.end_src_port = end_src_port;
167  flow->udp_data.start_dst_port = start_dst_port;
168  flow->udp_data.end_dst_port = end_dst_port;
169  flow->udp_data.interval = interval;
170  flow->udp_data.next_send_time = 0;
171  flow->fault_det = fault_det;
172 }
173 
174 void
176 {
177  u16 src_port;
178  u16 dst_port;
179  u16 no_flows;
180  int i;
181  udp_ping_flow_data *stats;
182 
183  no_flows =
184  (flow->udp_data.end_dst_port - flow->udp_data.start_dst_port) + 1;
185  no_flows *=
186  ((flow->udp_data.end_src_port - flow->udp_data.start_src_port) + 1);
187 
189  no_flows - 1, CLIB_CACHE_LINE_BYTES);
190 
191  i = 0;
192  for (src_port = flow->udp_data.start_src_port;
193  src_port <= flow->udp_data.end_src_port; src_port++)
194  {
195  for (dst_port = flow->udp_data.start_dst_port;
196  dst_port <= flow->udp_data.end_dst_port; dst_port++)
197  {
198  u8 *rewrite = NULL;
199 
200  stats = flow->udp_data.stats + i;
202  stats->analyse_data.is_free = 0;
203 
204  vec_validate (rewrite, UDP_PING_REWRITE_LEN - 1);
205  stats->ping_rewrite = rewrite;
206  stats->rewrite_len =
207  udp_ping_create_ip6_pak (rewrite,
208  flow->src.ip6, flow->dst.ip6,
209  src_port, dst_port, UDP_PING_PROBE, ctx);
210  /* For each flow we need to create ioam e2e flow */
211  stats->flow_ctx = ioam_flow_add (1, (u8 *) "udp_ping"); //FIXME
212  i++;
213  }
214  }
215 }
216 
217 void
219 {
220  int i;
221  udp_ping_flow_data *stats;
222 
223  for (i = 0; i < vec_len (flow->udp_data.stats); i++)
224  {
225  stats = flow->udp_data.stats + i;
226  vec_free (stats->ping_rewrite);
227  stats->ping_rewrite = NULL;
228  stats->rewrite_len = 0;
229  }
230 
231  vec_free (flow->udp_data.stats);
232  flow->udp_data.stats = NULL;
233 }
234 
235 /**
236  * @brief Create and send ipv6 udp-ping probe packet.
237  *
238  */
239 void
241 {
242  u16 no_pak;
243  u32 *buffers = NULL;
244  int i;
245  vlib_buffer_t *b0;
246  udp_ping_flow_data *stats;
247  vlib_frame_t *nf = 0;
248  u32 *to_next;
249  vlib_node_t *next_node;
250 
251  next_node = vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
252  nf = vlib_get_frame_to_node (vm, next_node->index);
253  nf->n_vectors = 0;
254  to_next = vlib_frame_vector_args (nf);
255 
256  no_pak = vec_len (flow->udp_data.stats);
257  vec_validate (buffers, (no_pak - 1));
258  if (vlib_buffer_alloc (vm, buffers, vec_len (buffers)) != no_pak)
259  {
260  //Error
261  return;
262  }
263 
264  for (i = 0; i < no_pak; i++)
265  {
266  int bogus;
267  b0 = vlib_get_buffer (vm, buffers[i]);
268  stats = flow->udp_data.stats + i;
269  clib_memcpy (b0->data, stats->ping_rewrite, stats->rewrite_len);
270  b0->current_data = 0;
271  b0->current_length = stats->rewrite_len;
273 
274  /* If session is going down, then set path down */
275  if ((stats->retry != 0) && ((stats->retry % MAX_PING_RETRIES) == 0))
277 
278  stats->retry++;
279  stats->analyse_data.pkt_sent++;
280  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
281  vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
282  vnet_buffer (b0)->l2_classify.opaque_index = stats->flow_ctx;
283 
286  udp_header_t *udp =
287  (udp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
288 
289  /* If session is down, then set loopback flag in probe.
290  * This is for fault isolation.
291  */
292  if (flow->fault_det && (stats->retry > MAX_PING_RETRIES))
293  {
294  ioam_trace_option_t *opt = (ioam_trace_option_t *)
297  }
298 
299  /* Checksum not pre-computed as we intend to vary packet length for every
300  * probe. its isnt done yet, but to be taken up later.
301  */
302  udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip6, &bogus);
303  ASSERT (bogus == 0);
304  if (udp->checksum == 0)
305  udp->checksum = 0xffff;
306 
307  if (nf->n_vectors == VLIB_FRAME_SIZE)
308  {
309  vlib_put_frame_to_node (vm, next_node->index, nf);
310  nf = vlib_get_frame_to_node (vm, next_node->index);
311  nf->n_vectors = 0;
312  to_next = vlib_frame_vector_args (nf);
313  }
314  *to_next = buffers[i];
315  nf->n_vectors++;
316  to_next++;
317  }
318  vlib_put_frame_to_node (vm, next_node->index, nf);
319 
320  flow->udp_data.next_send_time =
321  vlib_time_now (vm) + flow->udp_data.interval;
322 }
323 
324 /*
325  * fd.io coding-style-patch-verification: ON
326  *
327  * Local Variables:
328  * eval: (c-set-style "gnu")
329  * End:
330  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
udp_ping_data ping_data
#define UDP_PING_REWRITE_LEN
Definition: udp_ping_util.c:24
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
ioam_analyser_data_t analyse_data
Analysed data.
Definition: udp_ping.h:44
static void ip6_hbh_ioam_trace_set_bit(ioam_trace_option_t *trace, u8 trace_bit)
#define UDP_PING_PROBE_MARKER2
#define TRACE_TYPE_IF_TS_APP
Definition: trace_util.h:116
u16 start_dst_port
Defines start port of the dest port range.
Definition: udp_ping.h:73
static void ioam_analyse_init_data(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:498
#define NULL
Definition: clib.h:55
u32 index
Definition: node.h:238
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:192
u32 pkt_sent
Num of pkts sent for this flow.
Definition: ioam_analyse.h:103
static u8 fetch_trace_data_size(u16 trace_type)
Definition: trace_util.h:209
void udp_ping_free_flow_data(ip46_udp_ping_flow *flow)
int udp_ping_create_ip6_pak(u8 *buf, ip6_address_t src, ip6_address_t dst, u16 src_port, u16 dst_port, u8 msg_type, u16 ctx)
Frame IPv6 udp-ping probe packet.
Definition: udp_ping_util.c:61
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:447
u16 interval
Interval for which ping packet to be sent.
Definition: udp_ping.h:62
udp_ping_flow udp_data
Per flow data.
Definition: udp_ping.h:94
int udp_ping_compare_flow(ip46_address_t src, ip46_address_t dst, u16 start_src_port, u16 end_src_port, u16 start_dst_port, u16 end_dst_port, ip46_udp_ping_flow *flow)
ip6_address_t src_address
Definition: ip6_packet.h:341
#define ip46_address_cmp(ip46_1, ip46_2)
Definition: ip6_packet.h:80
u16 end_src_port
Defines end port of the src port range.
Definition: udp_ping.h:70
u16 udp_ping_fill_udp_data(udp_ping_t *udp_ping, u16 src_port, u16 dst_port, u8 msg_type, u16 ctx)
Definition: udp_ping_util.c:27
#define MAX_PING_RETRIES
Definition: udp_ping.h:21
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:67
f64 next_send_time
Time at which next udp-ping probe has to be sent out.
Definition: udp_ping.h:59
static void ip6_ioam_analyse_set_paths_down(ioam_analyser_data_t *data)
Definition: ioam_analyse.h:185
#define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE
void udp_ping_send_ip6_pak(vlib_main_t *vm, ip46_udp_ping_flow *flow)
Create and send ipv6 udp-ping probe packet.
udp-ping data.
Definition: udp_ping.h:85
#define VLIB_BUFFER_TOTAL_LENGTH_VALID
Definition: buffer.h:89
u16 start_src_port
Defines start port of the src port range.
Definition: udp_ping.h:67
u8 * ping_rewrite
UDP ping packet.
Definition: udp_ping.h:31
udp_header_t udp
void udp_ping_create_rewrite(ip46_udp_ping_flow *flow, u16 ctx)
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:71
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
ip46_address_t dst
Remote destination IPv4/6 address to be used.
Definition: udp_ping.h:91
#define VLIB_FRAME_SIZE
Definition: node.h:329
#define BIT_LOOPBACK
Definition: trace_util.h:94
u32 flow_ctx
This is used by ioam e2e for identifying flow and add seq number.
Definition: udp_ping.h:47
u16 n_vectors
Definition: node.h:345
void udp_ping_populate_flow(ip46_address_t src, ip46_address_t dst, u16 start_src_port, u16 end_src_port, u16 start_dst_port, u16 end_dst_port, u16 interval, u8 fault_det, ip46_udp_ping_flow *flow)
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
static u32 ioam_flow_add(u8 encap, u8 *flow_name)
#define clib_memcpy(a, b, c)
Definition: string.h:69
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
#define UDP_PING_PROBE
#define TRACE_TYPE_MASK
Definition: trace_util.h:96
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: ip6_forward.c:1195
u16 end_dst_port
Defines end port of the dest port range.
Definition: udp_ping.h:76
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 fault_det
To enable fault detection/isolation in network.
Definition: udp_ping.h:97
udp-ping session data.
Definition: udp_ping.h:28
ip46_address_t src
Local source IPv4/6 address to be used.
Definition: udp_ping.h:88
#define HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST
u16 rewrite_len
Ping packet rewrite string len.
Definition: udp_ping.h:34
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:328
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
u16 payload_length
Definition: ip6_packet.h:332
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static ip6_hop_by_hop_option_t * ip6_hbh_get_option(ip6_hop_by_hop_header_t *hbh0, u8 option_to_search)
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:269
#define HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE
#define vnet_buffer(b)
Definition: buffer.h:303
u8 data[0]
Packet data.
Definition: buffer.h:152
u16 retry
Number of times ping response was dropped.
Definition: udp_ping.h:39
udp_ping_flow_data * stats
Ping statistics.
Definition: udp_ping.h:79
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:245
#define UDP_PING_PROBE_MARKER1
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
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:341