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