blob: 3a695b1d8c0d3e95775860f47a7442d8b3f6f97e [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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 "ssvm_eth.h"
16
17vlib_node_registration_t ssvm_eth_input_node;
18
Damjan Marion00a9dca2016-08-17 17:05:46 +020019typedef struct
20{
Ed Warnickecb9cada2015-12-08 15:45:58 -070021 u32 next_index;
22 u32 sw_if_index;
23} ssvm_eth_input_trace_t;
24
25/* packet trace format function */
Damjan Marion00a9dca2016-08-17 17:05:46 +020026static u8 *
27format_ssvm_eth_input_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070028{
29 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
30 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Damjan Marion00a9dca2016-08-17 17:05:46 +020031 ssvm_eth_input_trace_t *t = va_arg (*args, ssvm_eth_input_trace_t *);
32
Ed Warnickecb9cada2015-12-08 15:45:58 -070033 s = format (s, "SSVM_ETH_INPUT: sw_if_index %d, next index %d",
Damjan Marion00a9dca2016-08-17 17:05:46 +020034 t->sw_if_index, t->next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -070035 return s;
36}
37
38vlib_node_registration_t ssvm_eth_input_node;
39
40#define foreach_ssvm_eth_input_error \
41_(NO_BUFFERS, "Rx packet drops (no buffers)")
42
Damjan Marion00a9dca2016-08-17 17:05:46 +020043typedef enum
44{
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#define _(sym,str) SSVM_ETH_INPUT_ERROR_##sym,
46 foreach_ssvm_eth_input_error
47#undef _
Damjan Marion00a9dca2016-08-17 17:05:46 +020048 SSVM_ETH_INPUT_N_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -070049} ssvm_eth_input_error_t;
50
Damjan Marion00a9dca2016-08-17 17:05:46 +020051static char *ssvm_eth_input_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -070052#define _(sym,string) string,
53 foreach_ssvm_eth_input_error
54#undef _
55};
56
Damjan Marion00a9dca2016-08-17 17:05:46 +020057typedef enum
58{
Ed Warnickecb9cada2015-12-08 15:45:58 -070059 SSVM_ETH_INPUT_NEXT_DROP,
60 SSVM_ETH_INPUT_NEXT_ETHERNET_INPUT,
61 SSVM_ETH_INPUT_NEXT_IP4_INPUT,
62 SSVM_ETH_INPUT_NEXT_IP6_INPUT,
63 SSVM_ETH_INPUT_NEXT_MPLS_INPUT,
64 SSVM_ETH_INPUT_N_NEXT,
65} ssvm_eth_input_next_t;
66
Damjan Marion00a9dca2016-08-17 17:05:46 +020067static inline uword
Ed Warnickecb9cada2015-12-08 15:45:58 -070068ssvm_eth_device_input (ssvm_eth_main_t * em,
Damjan Marion00a9dca2016-08-17 17:05:46 +020069 ssvm_private_t * intfc, vlib_node_runtime_t * node)
Ed Warnickecb9cada2015-12-08 15:45:58 -070070{
Damjan Marion00a9dca2016-08-17 17:05:46 +020071 ssvm_shared_header_t *sh = intfc->sh;
72 vlib_main_t *vm = em->vlib_main;
73 unix_shared_memory_queue_t *q;
74 ssvm_eth_queue_elt_t *elt, *elts;
Ed Warnickecb9cada2015-12-08 15:45:58 -070075 u32 elt_index;
76 u32 my_pid = intfc->my_pid;
77 int rx_queue_index;
78 u32 n_to_alloc = VLIB_FRAME_SIZE * 2;
79 u32 n_allocated, n_present_in_cache;
Damjan Marion8bdc63b2016-11-02 14:48:21 +010080 u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
Damjan Marion00a9dca2016-08-17 17:05:46 +020081 vlib_buffer_free_list_t *fl;
82 u32 n_left_to_next, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -070083 u32 next0;
84 u32 n_buffers;
85 u32 n_available;
86 u32 bi0, saved_bi0;
Damjan Marion00a9dca2016-08-17 17:05:46 +020087 vlib_buffer_t *b0, *prev;
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 u32 saved_cache_size = 0;
Damjan Marion00a9dca2016-08-17 17:05:46 +020089 ethernet_header_t *eh0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070090 u16 type0;
91 u32 n_rx_bytes = 0, l3_offset0;
Damjan Marion00a9dca2016-08-17 17:05:46 +020092 u32 cpu_index = os_get_cpu_number ();
93 u32 trace_cnt __attribute__ ((unused)) = vlib_get_trace_count (vm, node);
94 volatile u32 *lock;
95 u32 *elt_indices;
Dave Barachbfdedbd2016-01-20 09:11:55 -050096 uword n_trace = vlib_get_trace_count (vm, node);
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
98 /* Either side down? buh-bye... */
Damjan Marion00a9dca2016-08-17 17:05:46 +020099 if (pointer_to_uword (sh->opaque[MASTER_ADMIN_STATE_INDEX]) == 0 ||
100 pointer_to_uword (sh->opaque[SLAVE_ADMIN_STATE_INDEX]) == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101 return 0;
102
103 if (intfc->i_am_master)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200104 q = (unix_shared_memory_queue_t *) (sh->opaque[TO_MASTER_Q_INDEX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 else
Damjan Marion00a9dca2016-08-17 17:05:46 +0200106 q = (unix_shared_memory_queue_t *) (sh->opaque[TO_SLAVE_Q_INDEX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107
108 /* Nothing to do? */
109 if (q->cursize == 0)
110 return 0;
111
112 fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
113
114 vec_reset_length (intfc->rx_queue);
Damjan Marion00a9dca2016-08-17 17:05:46 +0200115
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 lock = (u32 *) q;
117 while (__sync_lock_test_and_set (lock, 1))
118 ;
119 while (q->cursize > 0)
120 {
Damjan Marion00a9dca2016-08-17 17:05:46 +0200121 unix_shared_memory_queue_sub_raw (q, (u8 *) & elt_index);
122 ASSERT (elt_index < 2048);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123 vec_add1 (intfc->rx_queue, elt_index);
124 }
Damjan Marion00a9dca2016-08-17 17:05:46 +0200125 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126 *lock = 0;
127
128 n_present_in_cache = vec_len (em->buffer_cache);
129
130 if (vec_len (em->buffer_cache) < vec_len (intfc->rx_queue) * 2)
131 {
Damjan Marion00a9dca2016-08-17 17:05:46 +0200132 vec_validate (em->buffer_cache,
133 n_to_alloc + vec_len (em->buffer_cache) - 1);
134 n_allocated =
135 vlib_buffer_alloc (vm, &em->buffer_cache[n_present_in_cache],
136 n_to_alloc);
137
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 n_present_in_cache += n_allocated;
139 _vec_len (em->buffer_cache) = n_present_in_cache;
140 }
141
Damjan Marion00a9dca2016-08-17 17:05:46 +0200142 elts = (ssvm_eth_queue_elt_t *) (sh->opaque[CHUNK_POOL_INDEX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143
144 n_buffers = vec_len (intfc->rx_queue);
145 rx_queue_index = 0;
146
147 while (n_buffers > 0)
148 {
149 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Damjan Marion00a9dca2016-08-17 17:05:46 +0200150
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 while (n_buffers > 0 && n_left_to_next > 0)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200152 {
153 elt = elts + intfc->rx_queue[rx_queue_index];
154
155 saved_cache_size = n_present_in_cache;
156 if (PREDICT_FALSE (saved_cache_size == 0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157 {
158 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
159 goto out;
160 }
Damjan Marion00a9dca2016-08-17 17:05:46 +0200161 saved_bi0 = bi0 = em->buffer_cache[--n_present_in_cache];
162 b0 = vlib_get_buffer (vm, bi0);
163 prev = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
Damjan Marion00a9dca2016-08-17 17:05:46 +0200165 while (1)
166 {
167 vlib_buffer_init_for_free_list (b0, fl);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168
Damjan Marion00a9dca2016-08-17 17:05:46 +0200169 b0->current_data = elt->current_data_hint;
170 b0->current_length = elt->length_this_buffer;
171 b0->total_length_not_including_first_buffer =
172 elt->total_length_not_including_first_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173
Damjan Marion00a9dca2016-08-17 17:05:46 +0200174 clib_memcpy (b0->data + b0->current_data, elt->data,
175 b0->current_length);
176
177 if (PREDICT_FALSE (prev != 0))
178 prev->next_buffer = bi0;
179
180 if (PREDICT_FALSE (elt->flags & SSVM_BUFFER_NEXT_PRESENT))
181 {
182 prev = b0;
183 if (PREDICT_FALSE (n_present_in_cache == 0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 {
Damjan Marion00a9dca2016-08-17 17:05:46 +0200185 vlib_put_next_frame (vm, node, next_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 n_left_to_next);
187 goto out;
188 }
Damjan Marion00a9dca2016-08-17 17:05:46 +0200189 bi0 = em->buffer_cache[--n_present_in_cache];
190 b0 = vlib_get_buffer (vm, bi0);
191 }
192 else
193 break;
194 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Damjan Marion00a9dca2016-08-17 17:05:46 +0200196 saved_cache_size = n_present_in_cache;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197
Damjan Marion00a9dca2016-08-17 17:05:46 +0200198 to_next[0] = saved_bi0;
199 to_next++;
200 n_left_to_next--;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201
Damjan Marion00a9dca2016-08-17 17:05:46 +0200202 b0 = vlib_get_buffer (vm, saved_bi0);
203 eh0 = vlib_buffer_get_current (b0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204
Damjan Marion00a9dca2016-08-17 17:05:46 +0200205 type0 = clib_net_to_host_u16 (eh0->type);
206
207 next0 = SSVM_ETH_INPUT_NEXT_ETHERNET_INPUT;
208
209 if (type0 == ETHERNET_TYPE_IP4)
210 next0 = SSVM_ETH_INPUT_NEXT_IP4_INPUT;
211 else if (type0 == ETHERNET_TYPE_IP6)
212 next0 = SSVM_ETH_INPUT_NEXT_IP6_INPUT;
213 else if (type0 == ETHERNET_TYPE_MPLS_UNICAST)
214 next0 = SSVM_ETH_INPUT_NEXT_MPLS_INPUT;
215
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 l3_offset0 = ((next0 == SSVM_ETH_INPUT_NEXT_IP4_INPUT ||
217 next0 == SSVM_ETH_INPUT_NEXT_IP6_INPUT ||
Damjan Marion00a9dca2016-08-17 17:05:46 +0200218 next0 == SSVM_ETH_INPUT_NEXT_MPLS_INPUT) ?
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219 sizeof (ethernet_header_t) : 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220
Damjan Marion00a9dca2016-08-17 17:05:46 +0200221 n_rx_bytes += b0->current_length
222 + b0->total_length_not_including_first_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223
Damjan Marion00a9dca2016-08-17 17:05:46 +0200224 b0->current_data += l3_offset0;
225 b0->current_length -= l3_offset0;
226 b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
Damjan Marion00a9dca2016-08-17 17:05:46 +0200228 vnet_buffer (b0)->sw_if_index[VLIB_RX] = intfc->vlib_hw_if_index;
229 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230
Damjan Marion00a9dca2016-08-17 17:05:46 +0200231 /*
232 * Turn this on if you run into
233 * "bad monkey" contexts, and you want to know exactly
234 * which nodes they've visited... See main.c...
235 */
236 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
Dave Barachbfdedbd2016-01-20 09:11:55 -0500237
Damjan Marion00a9dca2016-08-17 17:05:46 +0200238 if (PREDICT_FALSE (n_trace > 0))
239 {
240 ssvm_eth_input_trace_t *tr;
Dave Barachbfdedbd2016-01-20 09:11:55 -0500241
Damjan Marion00a9dca2016-08-17 17:05:46 +0200242 vlib_trace_buffer (vm, node, next0, b0, /* follow_chain */ 1);
243 vlib_set_trace_count (vm, node, --n_trace);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244
Damjan Marion00a9dca2016-08-17 17:05:46 +0200245 tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
246
247 tr->next_index = next0;
248 tr->sw_if_index = intfc->vlib_hw_if_index;
249 }
250
251 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
252 to_next, n_left_to_next,
253 bi0, next0);
254 n_buffers--;
255 rx_queue_index++;
256 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257
258 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
259 }
Damjan Marion00a9dca2016-08-17 17:05:46 +0200260
261out:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262 if (em->buffer_cache)
263 _vec_len (em->buffer_cache) = saved_cache_size;
264 else
265 ASSERT (saved_cache_size == 0);
266
267 ssvm_lock (sh, my_pid, 2);
268
Damjan Marion00a9dca2016-08-17 17:05:46 +0200269 ASSERT (vec_len (intfc->rx_queue) > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270
Damjan Marion00a9dca2016-08-17 17:05:46 +0200271 n_available = (u32) pointer_to_uword (sh->opaque[CHUNK_POOL_NFREE]);
272 elt_indices = (u32 *) (sh->opaque[CHUNK_POOL_FREELIST_INDEX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273
Damjan Marion00a9dca2016-08-17 17:05:46 +0200274 clib_memcpy (&elt_indices[n_available], intfc->rx_queue,
275 vec_len (intfc->rx_queue) * sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276
277 n_available += vec_len (intfc->rx_queue);
Damjan Marion00a9dca2016-08-17 17:05:46 +0200278 sh->opaque[CHUNK_POOL_NFREE] = uword_to_pointer (n_available, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
280 ssvm_unlock (sh);
281
282 vlib_error_count (vm, node->node_index, SSVM_ETH_INPUT_ERROR_NO_BUFFERS,
283 n_buffers);
284
Damjan Marion00a9dca2016-08-17 17:05:46 +0200285 vlib_increment_combined_counter
286 (vnet_get_main ()->interface_main.combined_sw_if_counters
287 + VNET_INTERFACE_COUNTER_RX, cpu_index,
288 intfc->vlib_hw_if_index, rx_queue_index, n_rx_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
290 return rx_queue_index;
291}
Damjan Marion00a9dca2016-08-17 17:05:46 +0200292
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293static uword
294ssvm_eth_input_node_fn (vlib_main_t * vm,
Damjan Marion00a9dca2016-08-17 17:05:46 +0200295 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296{
Damjan Marion00a9dca2016-08-17 17:05:46 +0200297 ssvm_eth_main_t *em = &ssvm_eth_main;
298 ssvm_private_t *intfc;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299 uword n_rx_packets = 0;
300
301 vec_foreach (intfc, em->intfcs)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200302 {
303 n_rx_packets += ssvm_eth_device_input (em, intfc, node);
304 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305
306 return n_rx_packets;
307}
308
Damjan Marion00a9dca2016-08-17 17:05:46 +0200309/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310VLIB_REGISTER_NODE (ssvm_eth_input_node) = {
311 .function = ssvm_eth_input_node_fn,
312 .name = "ssvm_eth_input",
313 .vector_size = sizeof (u32),
314 .format_trace = format_ssvm_eth_input_trace,
315 .type = VLIB_NODE_TYPE_INPUT,
316 .state = VLIB_NODE_STATE_DISABLED,
Damjan Marion00a9dca2016-08-17 17:05:46 +0200317
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 .n_errors = ARRAY_LEN(ssvm_eth_input_error_strings),
319 .error_strings = ssvm_eth_input_error_strings,
320
321 .n_next_nodes = SSVM_ETH_INPUT_N_NEXT,
322
323 /* edit / add dispositions here */
324 .next_nodes = {
325 [SSVM_ETH_INPUT_NEXT_DROP] = "error-drop",
326 [SSVM_ETH_INPUT_NEXT_ETHERNET_INPUT] = "ethernet-input",
327 [SSVM_ETH_INPUT_NEXT_IP4_INPUT] = "ip4-input",
328 [SSVM_ETH_INPUT_NEXT_IP6_INPUT] = "ip6-input",
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100329 [SSVM_ETH_INPUT_NEXT_MPLS_INPUT] = "mpls-input",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 },
331};
332
Damjan Marion1c80e832016-05-11 23:07:18 +0200333VLIB_NODE_FUNCTION_MULTIARCH (ssvm_eth_input_node, ssvm_eth_input_node_fn)
Damjan Marion00a9dca2016-08-17 17:05:46 +0200334/* *INDENT-ON* */
Damjan Marion1c80e832016-05-11 23:07:18 +0200335
Damjan Marion00a9dca2016-08-17 17:05:46 +0200336
337/*
338 * fd.io coding-style-patch-verification: ON
339 *
340 * Local Variables:
341 * eval: (c-set-style "gnu")
342 * End:
343 */