Line data Source code
1 : /*
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 :
21 : #include <vnet/interface.h>
22 :
23 : #define VIRTIO_BUFFERING_DEFAULT_SIZE 1024
24 : #define VIRTIO_BUFFERING_TIMEOUT 1e-5
25 :
26 : typedef 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 :
38 : static_always_inline clib_error_t *
39 0 : virtio_vring_buffering_init (virtio_vring_buffering_t ** buffering,
40 : u32 node_index, u16 size)
41 : {
42 0 : if (*buffering)
43 0 : return clib_error_return (0, "buffering: already initialized");
44 :
45 0 : if (!is_pow2 (size))
46 0 : return clib_error_return (0, "buffering: size must be power of 2");
47 :
48 0 : if (size > 32768)
49 0 : return clib_error_return (0, "buffering: size must be 32768 or lower");
50 :
51 0 : if (size == 0)
52 0 : size = VIRTIO_BUFFERING_DEFAULT_SIZE;
53 :
54 0 : virtio_vring_buffering_t *b_temp = 0;
55 : b_temp =
56 : (virtio_vring_buffering_t *)
57 0 : clib_mem_alloc (sizeof (virtio_vring_buffering_t));
58 0 : if (!b_temp)
59 0 : return clib_error_return (0, "buffering: memory allocation failed");
60 :
61 0 : clib_memset (b_temp, 0, sizeof (virtio_vring_buffering_t));
62 :
63 0 : b_temp->node_index = node_index;
64 0 : b_temp->free_size = size;
65 0 : b_temp->size = size;
66 :
67 0 : vec_validate_aligned (b_temp->buffers, size, CLIB_CACHE_LINE_BYTES);
68 0 : b_temp->is_enable = 1;
69 :
70 0 : *buffering = b_temp;
71 0 : return 0;
72 : }
73 :
74 : static_always_inline void
75 0 : virtio_vring_buffering_buffers_free (vlib_main_t * vm,
76 : virtio_vring_buffering_t * buffering)
77 : {
78 0 : u16 n_buffers = buffering->size - buffering->free_size;
79 0 : if (n_buffers)
80 : {
81 0 : vlib_buffer_free_from_ring (vm, buffering->buffers, buffering->front,
82 0 : buffering->size, n_buffers);
83 0 : buffering->free_size += n_buffers;
84 : }
85 0 : }
86 :
87 : static_always_inline void
88 300 : virtio_vring_buffering_free (vlib_main_t * vm,
89 : virtio_vring_buffering_t * buffering)
90 : {
91 300 : if (buffering)
92 : {
93 0 : virtio_vring_buffering_buffers_free (vm, buffering);
94 0 : vec_free (buffering->buffers);
95 0 : clib_mem_free (buffering);
96 : }
97 300 : }
98 :
99 : static_always_inline u8
100 0 : virtio_vring_buffering_is_enable (virtio_vring_buffering_t * buffering)
101 : {
102 0 : if (buffering)
103 0 : return buffering->is_enable;
104 :
105 0 : return 0;
106 : }
107 :
108 : static_always_inline void
109 : virtio_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 :
116 : static_always_inline void
117 0 : virtio_vring_buffering_set_timeout (vlib_main_t * vm,
118 : virtio_vring_buffering_t * buffering,
119 : f64 timeout_expire)
120 : {
121 0 : if (buffering)
122 0 : buffering->timeout_ts = vlib_time_now (vm) + timeout_expire;
123 0 : }
124 :
125 : static_always_inline u8
126 0 : virtio_vring_buffering_is_timeout (vlib_main_t * vm,
127 : virtio_vring_buffering_t * buffering)
128 : {
129 0 : if (buffering && (buffering->timeout_ts < vlib_time_now (vm)))
130 0 : return 1;
131 0 : return 0;
132 : }
133 :
134 : static_always_inline u8
135 0 : virtio_vring_buffering_is_empty (virtio_vring_buffering_t * buffering)
136 : {
137 0 : if (buffering->size == buffering->free_size)
138 0 : return 1;
139 0 : return 0;
140 : }
141 :
142 : static_always_inline u8
143 0 : virtio_vring_buffering_is_full (virtio_vring_buffering_t * buffering)
144 : {
145 0 : if (buffering->free_size == 0)
146 0 : return 1;
147 0 : return 0;
148 : }
149 :
150 : static_always_inline u16
151 0 : virtio_vring_n_buffers (virtio_vring_buffering_t * buffering)
152 : {
153 0 : return (buffering->size - buffering->free_size);
154 : }
155 :
156 : static_always_inline u16
157 0 : virtio_vring_buffering_store_packets (virtio_vring_buffering_t * buffering,
158 : u32 * bi, u16 n_store)
159 : {
160 0 : u16 mask, n_s = 0, i = 0;
161 :
162 0 : if (!virtio_vring_buffering_is_enable (buffering)
163 0 : || virtio_vring_buffering_is_full (buffering))
164 0 : return 0;
165 :
166 0 : mask = buffering->size - 1;
167 0 : n_s = clib_min (n_store, buffering->free_size);
168 :
169 0 : while (i < n_s)
170 : {
171 0 : buffering->buffers[buffering->back] = bi[i];
172 0 : buffering->back = (buffering->back + 1) & mask;
173 0 : buffering->free_size--;
174 0 : i++;
175 : }
176 0 : return n_s;
177 : }
178 :
179 : static_always_inline u32
180 0 : virtio_vring_buffering_read_from_front (virtio_vring_buffering_t * buffering)
181 : {
182 0 : u32 bi = ~0;
183 0 : u16 mask = buffering->size - 1;
184 0 : if (virtio_vring_buffering_is_empty (buffering))
185 0 : return bi;
186 :
187 0 : bi = buffering->buffers[buffering->front];
188 0 : buffering->buffers[buffering->front] = ~0;
189 0 : buffering->front = (buffering->front + 1) & mask;
190 0 : buffering->free_size++;
191 0 : return bi;
192 : }
193 :
194 : static_always_inline u32
195 0 : virtio_vring_buffering_read_from_back (virtio_vring_buffering_t * buffering)
196 : {
197 0 : u32 bi = ~0;
198 0 : u16 mask = buffering->size - 1;
199 0 : if (virtio_vring_buffering_is_empty (buffering))
200 0 : return bi;
201 :
202 0 : buffering->back = (buffering->back - 1) & mask;
203 0 : bi = buffering->buffers[buffering->back];
204 0 : buffering->buffers[buffering->back] = ~0;
205 0 : buffering->free_size++;
206 0 : return bi;
207 : }
208 :
209 : static_always_inline void
210 0 : virtio_vring_buffering_schedule_node_on_dispatcher (
211 : vlib_main_t *vm, vnet_hw_if_tx_queue_t *txq,
212 : virtio_vring_buffering_t *buffering)
213 : {
214 0 : if (buffering && virtio_vring_buffering_is_timeout (vm, buffering)
215 0 : && virtio_vring_n_buffers (buffering))
216 : {
217 0 : vlib_frame_t *f = vlib_get_frame_to_node (vm, buffering->node_index);
218 0 : vnet_hw_if_tx_frame_t *ft = vlib_frame_scalar_args (f);
219 0 : u32 *f_to = vlib_frame_vector_args (f);
220 0 : ft->shared_queue = txq->shared_queue;
221 0 : ft->queue_id = txq->queue_id;
222 0 : f_to[f->n_vectors] = virtio_vring_buffering_read_from_back (buffering);
223 0 : f->n_vectors++;
224 0 : vlib_put_frame_to_node (vm, buffering->node_index, f);
225 0 : virtio_vring_buffering_set_timeout (vm, buffering,
226 : VIRTIO_BUFFERING_TIMEOUT);
227 : }
228 0 : }
229 :
230 : static_always_inline u8 *
231 0 : virtio_vring_buffering_format (u8 * s, va_list * args)
232 : {
233 0 : virtio_vring_buffering_t *buffering =
234 : va_arg (*args, virtio_vring_buffering_t *);
235 0 : u32 indent = format_get_indent (s);
236 :
237 0 : if (!buffering)
238 0 : return s;
239 :
240 0 : indent += 2;
241 :
242 0 : if (buffering->is_enable)
243 0 : s = format (s, "packet-buffering: enable\n");
244 : else
245 0 : s = format (s, "packet-buffering: disable\n");
246 : s =
247 0 : format (s,
248 : "%Usize %u n_buffers %u front %u back %u",
249 0 : format_white_space, indent, buffering->size,
250 0 : virtio_vring_n_buffers (buffering), buffering->front,
251 0 : buffering->back);
252 :
253 0 : 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 : */
|