blob: 6f13a1f5c3621213e54e52154d511ab36b4ba973 [file] [log] [blame]
Mohsin Kazmie347acb2020-09-28 10:26:33 +00001/*
2 *------------------------------------------------------------------
3 * Copyright (c) 2020 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
16 */
17
18#ifndef _VNET_DEVICES_VIRTIO_VIRTIO_BUFFERING_H_
19#define _VNET_DEVICES_VIRTIO_VIRTIO_BUFFERING_H_
20
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +000021#include <vnet/interface.h>
22
Mohsin Kazmie347acb2020-09-28 10:26:33 +000023#define VIRTIO_BUFFERING_DEFAULT_SIZE 1024
24#define VIRTIO_BUFFERING_TIMEOUT 1e-5
25
26typedef struct
27{
28 f64 timeout_ts;
29 u32 *buffers;
30 u32 node_index;
31 u16 size;
32 u16 free_size;
33 u16 front;
34 u16 back;
35 u8 is_enable;
36} virtio_vring_buffering_t;
37
38static_always_inline clib_error_t *
39virtio_vring_buffering_init (virtio_vring_buffering_t ** buffering,
40 u32 node_index, u16 size)
41{
42 if (*buffering)
43 return clib_error_return (0, "buffering: already initialized");
44
45 if (!is_pow2 (size))
46 return clib_error_return (0, "buffering: size must be power of 2");
47
48 if (size > 32768)
49 return clib_error_return (0, "buffering: size must be 32768 or lower");
50
51 if (size == 0)
52 size = VIRTIO_BUFFERING_DEFAULT_SIZE;
53
54 virtio_vring_buffering_t *b_temp = 0;
55 b_temp =
56 (virtio_vring_buffering_t *)
57 clib_mem_alloc (sizeof (virtio_vring_buffering_t));
58 if (!b_temp)
59 return clib_error_return (0, "buffering: memory allocation failed");
60
61 clib_memset (b_temp, 0, sizeof (virtio_vring_buffering_t));
62
63 b_temp->node_index = node_index;
64 b_temp->free_size = size;
65 b_temp->size = size;
66
67 vec_validate_aligned (b_temp->buffers, size, CLIB_CACHE_LINE_BYTES);
68 b_temp->is_enable = 1;
69
70 *buffering = b_temp;
71 return 0;
72}
73
74static_always_inline void
75virtio_vring_buffering_buffers_free (vlib_main_t * vm,
76 virtio_vring_buffering_t * buffering)
77{
78 u16 n_buffers = buffering->size - buffering->free_size;
79 if (n_buffers)
80 {
81 vlib_buffer_free_from_ring (vm, buffering->buffers, buffering->front,
82 buffering->size, n_buffers);
83 buffering->free_size += n_buffers;
84 }
85}
86
87static_always_inline void
88virtio_vring_buffering_free (vlib_main_t * vm,
89 virtio_vring_buffering_t * buffering)
90{
91 if (buffering)
92 {
93 virtio_vring_buffering_buffers_free (vm, buffering);
94 vec_free (buffering->buffers);
95 clib_mem_free (buffering);
96 }
97}
98
99static_always_inline u8
100virtio_vring_buffering_is_enable (virtio_vring_buffering_t * buffering)
101{
102 if (buffering)
103 return buffering->is_enable;
104
105 return 0;
106}
107
108static_always_inline void
109virtio_vring_buffering_set_is_enable (virtio_vring_buffering_t * buffering,
110 u8 is_enable)
111{
112 if (buffering)
113 buffering->is_enable = is_enable;
114}
115
116static_always_inline void
117virtio_vring_buffering_set_timeout (vlib_main_t * vm,
118 virtio_vring_buffering_t * buffering,
119 f64 timeout_expire)
120{
121 if (buffering)
122 buffering->timeout_ts = vlib_time_now (vm) + timeout_expire;
123}
124
125static_always_inline u8
126virtio_vring_buffering_is_timeout (vlib_main_t * vm,
127 virtio_vring_buffering_t * buffering)
128{
129 if (buffering && (buffering->timeout_ts < vlib_time_now (vm)))
130 return 1;
131 return 0;
132}
133
134static_always_inline u8
135virtio_vring_buffering_is_empty (virtio_vring_buffering_t * buffering)
136{
137 if (buffering->size == buffering->free_size)
138 return 1;
139 return 0;
140}
141
142static_always_inline u8
143virtio_vring_buffering_is_full (virtio_vring_buffering_t * buffering)
144{
145 if (buffering->free_size == 0)
146 return 1;
147 return 0;
148}
149
150static_always_inline u16
151virtio_vring_n_buffers (virtio_vring_buffering_t * buffering)
152{
153 return (buffering->size - buffering->free_size);
154}
155
156static_always_inline u16
157virtio_vring_buffering_store_packets (virtio_vring_buffering_t * buffering,
158 u32 * bi, u16 n_store)
159{
160 u16 mask, n_s = 0, i = 0;
161
162 if (!virtio_vring_buffering_is_enable (buffering)
163 || virtio_vring_buffering_is_full (buffering))
164 return 0;
165
166 mask = buffering->size - 1;
167 n_s = clib_min (n_store, buffering->free_size);
168
169 while (i < n_s)
170 {
171 buffering->buffers[buffering->back] = bi[i];
172 buffering->back = (buffering->back + 1) & mask;
173 buffering->free_size--;
174 i++;
175 }
176 return n_s;
177}
178
179static_always_inline u32
180virtio_vring_buffering_read_from_front (virtio_vring_buffering_t * buffering)
181{
182 u32 bi = ~0;
183 u16 mask = buffering->size - 1;
184 if (virtio_vring_buffering_is_empty (buffering))
185 return bi;
186
187 bi = buffering->buffers[buffering->front];
188 buffering->buffers[buffering->front] = ~0;
189 buffering->front = (buffering->front + 1) & mask;
190 buffering->free_size++;
191 return bi;
192}
193
194static_always_inline u32
195virtio_vring_buffering_read_from_back (virtio_vring_buffering_t * buffering)
196{
197 u32 bi = ~0;
198 u16 mask = buffering->size - 1;
199 if (virtio_vring_buffering_is_empty (buffering))
200 return bi;
201
202 buffering->back = (buffering->back - 1) & mask;
203 bi = buffering->buffers[buffering->back];
204 buffering->buffers[buffering->back] = ~0;
205 buffering->free_size++;
206 return bi;
207}
208
209static_always_inline void
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +0000210virtio_vring_buffering_schedule_node_on_dispatcher (
211 vlib_main_t *vm, vnet_hw_if_tx_queue_t *txq,
212 virtio_vring_buffering_t *buffering)
Mohsin Kazmie347acb2020-09-28 10:26:33 +0000213{
214 if (buffering && virtio_vring_buffering_is_timeout (vm, buffering)
215 && virtio_vring_n_buffers (buffering))
216 {
217 vlib_frame_t *f = vlib_get_frame_to_node (vm, buffering->node_index);
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +0000218 vnet_hw_if_tx_frame_t *ft = vlib_frame_scalar_args (f);
Mohsin Kazmie347acb2020-09-28 10:26:33 +0000219 u32 *f_to = vlib_frame_vector_args (f);
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +0000220 ft->shared_queue = txq->shared_queue;
221 ft->queue_id = txq->queue_id;
Mohsin Kazmie347acb2020-09-28 10:26:33 +0000222 f_to[f->n_vectors] = virtio_vring_buffering_read_from_back (buffering);
223 f->n_vectors++;
224 vlib_put_frame_to_node (vm, buffering->node_index, f);
225 virtio_vring_buffering_set_timeout (vm, buffering,
226 VIRTIO_BUFFERING_TIMEOUT);
227 }
228}
229
230static_always_inline u8 *
231virtio_vring_buffering_format (u8 * s, va_list * args)
232{
233 virtio_vring_buffering_t *buffering =
234 va_arg (*args, virtio_vring_buffering_t *);
235 u32 indent = format_get_indent (s);
236
237 if (!buffering)
238 return s;
239
240 indent += 2;
241
242 if (buffering->is_enable)
243 s = format (s, "packet-buffering: enable\n");
244 else
245 s = format (s, "packet-buffering: disable\n");
246 s =
247 format (s,
248 "%Usize %u n_buffers %u front %u back %u",
249 format_white_space, indent, buffering->size,
250 virtio_vring_n_buffers (buffering), buffering->front,
251 buffering->back);
252
253 return s;
254}
255
256#endif /* _VNET_DEVICES_VIRTIO_VIRTIO_BUFFERING_H_ */
257
258/*
259 * fd.io coding-style-patch-verification: ON
260 *
261 * Local Variables:
262 * eval: (c-set-style "gnu")
263 * End:
264 */