Line data Source code
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>
19 : #include <ioam/encap/ip6_ioam_e2e.h>
20 : #include <ioam/encap/ip6_ioam_trace.h>
21 : #include <ioam/udp-ping/udp_ping_packet.h>
22 : #include <ioam/udp-ping/udp_ping.h>
23 :
24 : #define UDP_PING_REWRITE_LEN 1000
25 :
26 : u16
27 0 : udp_ping_fill_udp_data (udp_ping_t * udp_ping,
28 : u16 src_port, u16 dst_port, u8 msg_type, u16 ctx)
29 : {
30 : /* Populate udp ping header */
31 0 : udp_ping->udp.src_port = clib_host_to_net_u16 (src_port);
32 0 : udp_ping->udp.dst_port = clib_host_to_net_u16 (dst_port);
33 0 : udp_ping->udp.length = clib_host_to_net_u16 (sizeof (udp_ping_t));
34 0 : udp_ping->udp.checksum = 0;
35 0 : udp_ping->ping_data.probe_marker1 =
36 0 : clib_host_to_net_u32 (UDP_PING_PROBE_MARKER1);
37 0 : udp_ping->ping_data.probe_marker2 =
38 0 : clib_host_to_net_u32 (UDP_PING_PROBE_MARKER2);
39 0 : udp_ping->ping_data.version = 1;
40 0 : udp_ping->ping_data.msg_type = msg_type;
41 0 : udp_ping->ping_data.flags = clib_host_to_net_u16 (0);
42 0 : udp_ping->ping_data.tel_req_vec = clib_host_to_net_u16 (0);
43 0 : udp_ping->ping_data.hop_limit = 254;
44 0 : udp_ping->ping_data.hop_count = 0;
45 0 : udp_ping->ping_data.reserve = clib_host_to_net_u16 (0);
46 0 : udp_ping->ping_data.max_len =
47 0 : udp_ping->ping_data.cur_len = clib_host_to_net_u16 (0);
48 0 : udp_ping->ping_data.sender_handle = clib_host_to_net_u16 (ctx);
49 0 : udp_ping->ping_data.seq_no = clib_host_to_net_u16 (0);
50 :
51 0 : 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 0 : udp_ping_create_ip6_pak (u8 * buf, /*u16 len, */
62 : ip6_address_t src, ip6_address_t dst,
63 : u16 src_port, u16 dst_port, u8 msg_type, u16 ctx)
64 : {
65 : ip6_header_t *ip0;
66 : ip6_hop_by_hop_header_t *hbh0;
67 : //trace_profile *profile = NULL;
68 0 : u16 hbh_len = 0, rnd_size = 0, ip0_len = 0, udp_len = 0;
69 0 : u16 trace_len = 0, trace_data_size = 0;
70 0 : u16 e2e_len = sizeof (ioam_e2e_option_t) - sizeof (ip6_hop_by_hop_option_t);
71 0 : u8 *current = NULL;
72 : ioam_trace_option_t *trace_option;
73 : ioam_e2e_option_t *e2e;
74 :
75 0 : ip0 = (ip6_header_t *) buf;
76 :
77 0 : ip0->ip_version_traffic_class_and_flow_label =
78 0 : clib_host_to_net_u32 (0x6 << 28);
79 :
80 0 : ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
81 0 : ip0->hop_limit = 255;
82 :
83 0 : ip0->src_address = src;
84 0 : ip0->dst_address = dst;
85 :
86 0 : hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
87 :
88 : /* Calculate hbh header len */
89 : //profile = trace_profile_find();
90 0 : 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 0 : trace_len = sizeof (ioam_trace_option_t) +
93 0 : (5 * trace_data_size * 2) - sizeof (ip6_hop_by_hop_option_t);
94 : //(profile->num_elts * trace_data_size * 2);
95 0 : hbh_len = e2e_len + trace_len + sizeof (ip6_hop_by_hop_header_t);
96 0 : rnd_size = (hbh_len + 7) & ~7;
97 :
98 : /* Length of header in 8 octet units, not incl first 8 octets */
99 0 : hbh0->length = (rnd_size >> 3) - 1;
100 0 : hbh0->protocol = IP_PROTOCOL_UDP;
101 :
102 : /* Populate hbh header */
103 0 : current = (u8 *) (hbh0 + 1);
104 :
105 : /* Populate trace */
106 0 : trace_option = (ioam_trace_option_t *) current;
107 0 : trace_option->hdr.type = HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST |
108 : HBH_OPTION_TYPE_DATA_CHANGE_ENROUTE;
109 0 : trace_option->hdr.length = trace_len;
110 0 : trace_option->trace_hdr.ioam_trace_type =
111 : TRACE_TYPE_IF_TS_APP & TRACE_TYPE_MASK;
112 :
113 0 : trace_option->trace_hdr.data_list_elts_left = 5 * 2;
114 : //profile->num_elts * 2;
115 :
116 0 : current += trace_option->hdr.length + sizeof (ip6_hop_by_hop_option_t);
117 :
118 : /* Populate e2e */
119 0 : e2e = (ioam_e2e_option_t *) current;
120 0 : e2e->hdr.type = HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE;
121 0 : e2e->hdr.length = e2e_len;
122 :
123 : /* Move past hbh header */
124 0 : current = ((u8 *) hbh0) + ((hbh0->length + 1) << 3);
125 :
126 : /* Populate udp ping header */
127 0 : 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 0 : ip0_len = ((hbh0->length + 1) << 3) + udp_len;
132 : //ip0_len = (len > ip0_len) ? len : ip0_len;
133 0 : ip0->payload_length = clib_host_to_net_u16 (ip0_len);
134 :
135 0 : return (ip0_len + sizeof (ip6_header_t));
136 : }
137 :
138 : int
139 0 : 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 0 : if ((0 == ip46_address_cmp (&flow->src, &src)) &&
145 0 : (0 == ip46_address_cmp (&flow->dst, &dst)) &&
146 0 : (flow->udp_data.start_src_port == start_src_port) &&
147 0 : (flow->udp_data.end_src_port == end_src_port) &&
148 0 : (flow->udp_data.start_dst_port == start_dst_port) &&
149 0 : (flow->udp_data.end_dst_port == end_dst_port))
150 : {
151 0 : return 0;
152 : }
153 :
154 0 : return -1;
155 : }
156 :
157 : void
158 0 : 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 0 : flow->src = src;
164 0 : flow->dst = dst;
165 0 : flow->udp_data.start_src_port = start_src_port;
166 0 : flow->udp_data.end_src_port = end_src_port;
167 0 : flow->udp_data.start_dst_port = start_dst_port;
168 0 : flow->udp_data.end_dst_port = end_dst_port;
169 0 : flow->udp_data.interval = interval;
170 0 : flow->udp_data.next_send_time = 0;
171 0 : flow->fault_det = fault_det;
172 0 : }
173 :
174 : void
175 0 : udp_ping_create_rewrite (ip46_udp_ping_flow * flow, u16 ctx)
176 : {
177 : u16 src_port;
178 : u16 dst_port;
179 : u16 no_flows;
180 : int i;
181 : udp_ping_flow_data *stats;
182 :
183 0 : no_flows =
184 0 : (flow->udp_data.end_dst_port - flow->udp_data.start_dst_port) + 1;
185 0 : no_flows *=
186 0 : ((flow->udp_data.end_src_port - flow->udp_data.start_src_port) + 1);
187 :
188 0 : vec_validate_aligned (flow->udp_data.stats,
189 : no_flows - 1, CLIB_CACHE_LINE_BYTES);
190 :
191 0 : i = 0;
192 0 : for (src_port = flow->udp_data.start_src_port;
193 0 : src_port <= flow->udp_data.end_src_port; src_port++)
194 : {
195 0 : for (dst_port = flow->udp_data.start_dst_port;
196 0 : dst_port <= flow->udp_data.end_dst_port; dst_port++)
197 : {
198 0 : u8 *rewrite = NULL;
199 :
200 0 : stats = flow->udp_data.stats + i;
201 0 : ioam_analyse_init_data (&stats->analyse_data);
202 0 : stats->analyse_data.is_free = 0;
203 :
204 0 : vec_validate (rewrite, UDP_PING_REWRITE_LEN - 1);
205 0 : stats->ping_rewrite = rewrite;
206 0 : stats->rewrite_len =
207 0 : 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 0 : stats->flow_ctx = ioam_flow_add (1, (u8 *) "udp_ping"); //FIXME
212 0 : i++;
213 : }
214 : }
215 0 : }
216 :
217 : void
218 0 : udp_ping_free_flow_data (ip46_udp_ping_flow * flow)
219 : {
220 : int i;
221 : udp_ping_flow_data *stats;
222 :
223 0 : for (i = 0; i < vec_len (flow->udp_data.stats); i++)
224 : {
225 0 : stats = flow->udp_data.stats + i;
226 0 : vec_free (stats->ping_rewrite);
227 0 : stats->ping_rewrite = NULL;
228 0 : stats->rewrite_len = 0;
229 : }
230 :
231 0 : vec_free (flow->udp_data.stats);
232 0 : flow->udp_data.stats = NULL;
233 0 : }
234 :
235 : /**
236 : * @brief Create and send ipv6 udp-ping probe packet.
237 : *
238 : */
239 : void
240 0 : udp_ping_send_ip6_pak (vlib_main_t * vm, ip46_udp_ping_flow * flow)
241 : {
242 : u16 no_pak;
243 0 : u32 *buffers = NULL;
244 : int i;
245 : vlib_buffer_t *b0;
246 : udp_ping_flow_data *stats;
247 0 : vlib_frame_t *nf = 0;
248 : u32 *to_next;
249 : vlib_node_t *next_node;
250 :
251 0 : next_node = vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
252 0 : nf = vlib_get_frame_to_node (vm, next_node->index);
253 0 : nf->n_vectors = 0;
254 0 : to_next = vlib_frame_vector_args (nf);
255 :
256 0 : no_pak = vec_len (flow->udp_data.stats);
257 0 : vec_validate (buffers, (no_pak - 1));
258 0 : if (vlib_buffer_alloc (vm, buffers, vec_len (buffers)) != no_pak)
259 : {
260 : //Error
261 0 : return;
262 : }
263 :
264 0 : for (i = 0; i < no_pak; i++)
265 : {
266 : int bogus;
267 0 : b0 = vlib_get_buffer (vm, buffers[i]);
268 0 : stats = flow->udp_data.stats + i;
269 0 : clib_memcpy_fast (b0->data, stats->ping_rewrite, stats->rewrite_len);
270 0 : b0->current_data = 0;
271 0 : b0->current_length = stats->rewrite_len;
272 0 : b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
273 :
274 : /* If session is going down, then set path down */
275 0 : if ((stats->retry != 0) && ((stats->retry % MAX_PING_RETRIES) == 0))
276 0 : ip6_ioam_analyse_set_paths_down (&stats->analyse_data);
277 :
278 0 : stats->retry++;
279 0 : stats->analyse_data.pkt_sent++;
280 0 : vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
281 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
282 0 : vnet_buffer (b0)->l2_classify.opaque_index = stats->flow_ctx;
283 :
284 0 : ip6_header_t *ip6 = vlib_buffer_get_current (b0);
285 0 : ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip6 + 1);
286 0 : udp_header_t *udp =
287 0 : (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 0 : if (flow->fault_det && (stats->retry > MAX_PING_RETRIES))
293 : {
294 : ioam_trace_option_t *opt = (ioam_trace_option_t *)
295 0 : ip6_hbh_get_option (hbh, HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST);
296 0 : ip6_hbh_ioam_trace_set_bit (opt, BIT_LOOPBACK);
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 0 : udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip6, &bogus);
303 0 : ASSERT (bogus == 0);
304 0 : if (udp->checksum == 0)
305 0 : udp->checksum = 0xffff;
306 :
307 0 : if (nf->n_vectors == VLIB_FRAME_SIZE)
308 : {
309 0 : vlib_put_frame_to_node (vm, next_node->index, nf);
310 0 : nf = vlib_get_frame_to_node (vm, next_node->index);
311 0 : nf->n_vectors = 0;
312 0 : to_next = vlib_frame_vector_args (nf);
313 : }
314 0 : *to_next = buffers[i];
315 0 : nf->n_vectors++;
316 0 : to_next++;
317 : }
318 0 : vlib_put_frame_to_node (vm, next_node->index, nf);
319 :
320 0 : flow->udp_data.next_send_time =
321 0 : 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 : */
|