5b155920906276d3546c44e85ee67c76596fd2b6
[dpdk.git] / lib / librte_pipeline / rte_swx_pipeline.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <errno.h>
8 #include <sys/queue.h>
9
10 #include <rte_common.h>
11
12 #include "rte_swx_pipeline.h"
13
14 #define CHECK(condition, err_code)                                             \
15 do {                                                                           \
16         if (!(condition))                                                      \
17                 return -(err_code);                                            \
18 } while (0)
19
20 #define CHECK_NAME(name, err_code)                                             \
21         CHECK((name) && (name)[0], err_code)
22
23 /*
24  * Input port.
25  */
26 struct port_in_type {
27         TAILQ_ENTRY(port_in_type) node;
28         char name[RTE_SWX_NAME_SIZE];
29         struct rte_swx_port_in_ops ops;
30 };
31
32 TAILQ_HEAD(port_in_type_tailq, port_in_type);
33
34 struct port_in {
35         TAILQ_ENTRY(port_in) node;
36         struct port_in_type *type;
37         void *obj;
38         uint32_t id;
39 };
40
41 TAILQ_HEAD(port_in_tailq, port_in);
42
43 struct port_in_runtime {
44         rte_swx_port_in_pkt_rx_t pkt_rx;
45         void *obj;
46 };
47
48 /*
49  * Pipeline.
50  */
51 struct rte_swx_pipeline {
52         struct port_in_type_tailq port_in_types;
53         struct port_in_tailq ports_in;
54
55         struct port_in_runtime *in;
56
57         uint32_t n_ports_in;
58         int build_done;
59         int numa_node;
60 };
61
62 /*
63  * Input port.
64  */
65 static struct port_in_type *
66 port_in_type_find(struct rte_swx_pipeline *p, const char *name)
67 {
68         struct port_in_type *elem;
69
70         if (!name)
71                 return NULL;
72
73         TAILQ_FOREACH(elem, &p->port_in_types, node)
74                 if (strcmp(elem->name, name) == 0)
75                         return elem;
76
77         return NULL;
78 }
79
80 int
81 rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
82                                        const char *name,
83                                        struct rte_swx_port_in_ops *ops)
84 {
85         struct port_in_type *elem;
86
87         CHECK(p, EINVAL);
88         CHECK_NAME(name, EINVAL);
89         CHECK(ops, EINVAL);
90         CHECK(ops->create, EINVAL);
91         CHECK(ops->free, EINVAL);
92         CHECK(ops->pkt_rx, EINVAL);
93         CHECK(ops->stats_read, EINVAL);
94
95         CHECK(!port_in_type_find(p, name), EEXIST);
96
97         /* Node allocation. */
98         elem = calloc(1, sizeof(struct port_in_type));
99         CHECK(elem, ENOMEM);
100
101         /* Node initialization. */
102         strcpy(elem->name, name);
103         memcpy(&elem->ops, ops, sizeof(*ops));
104
105         /* Node add to tailq. */
106         TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
107
108         return 0;
109 }
110
111 static struct port_in *
112 port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
113 {
114         struct port_in *port;
115
116         TAILQ_FOREACH(port, &p->ports_in, node)
117                 if (port->id == port_id)
118                         return port;
119
120         return NULL;
121 }
122
123 int
124 rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
125                                 uint32_t port_id,
126                                 const char *port_type_name,
127                                 void *args)
128 {
129         struct port_in_type *type = NULL;
130         struct port_in *port = NULL;
131         void *obj = NULL;
132
133         CHECK(p, EINVAL);
134
135         CHECK(!port_in_find(p, port_id), EINVAL);
136
137         CHECK_NAME(port_type_name, EINVAL);
138         type = port_in_type_find(p, port_type_name);
139         CHECK(type, EINVAL);
140
141         obj = type->ops.create(args);
142         CHECK(obj, ENODEV);
143
144         /* Node allocation. */
145         port = calloc(1, sizeof(struct port_in));
146         CHECK(port, ENOMEM);
147
148         /* Node initialization. */
149         port->type = type;
150         port->obj = obj;
151         port->id = port_id;
152
153         /* Node add to tailq. */
154         TAILQ_INSERT_TAIL(&p->ports_in, port, node);
155         if (p->n_ports_in < port_id + 1)
156                 p->n_ports_in = port_id + 1;
157
158         return 0;
159 }
160
161 static int
162 port_in_build(struct rte_swx_pipeline *p)
163 {
164         struct port_in *port;
165         uint32_t i;
166
167         CHECK(p->n_ports_in, EINVAL);
168         CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
169
170         for (i = 0; i < p->n_ports_in; i++)
171                 CHECK(port_in_find(p, i), EINVAL);
172
173         p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
174         CHECK(p->in, ENOMEM);
175
176         TAILQ_FOREACH(port, &p->ports_in, node) {
177                 struct port_in_runtime *in = &p->in[port->id];
178
179                 in->pkt_rx = port->type->ops.pkt_rx;
180                 in->obj = port->obj;
181         }
182
183         return 0;
184 }
185
186 static void
187 port_in_build_free(struct rte_swx_pipeline *p)
188 {
189         free(p->in);
190         p->in = NULL;
191 }
192
193 static void
194 port_in_free(struct rte_swx_pipeline *p)
195 {
196         port_in_build_free(p);
197
198         /* Input ports. */
199         for ( ; ; ) {
200                 struct port_in *port;
201
202                 port = TAILQ_FIRST(&p->ports_in);
203                 if (!port)
204                         break;
205
206                 TAILQ_REMOVE(&p->ports_in, port, node);
207                 port->type->ops.free(port->obj);
208                 free(port);
209         }
210
211         /* Input port types. */
212         for ( ; ; ) {
213                 struct port_in_type *elem;
214
215                 elem = TAILQ_FIRST(&p->port_in_types);
216                 if (!elem)
217                         break;
218
219                 TAILQ_REMOVE(&p->port_in_types, elem, node);
220                 free(elem);
221         }
222 }
223
224 /*
225  * Pipeline.
226  */
227 int
228 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
229 {
230         struct rte_swx_pipeline *pipeline;
231
232         /* Check input parameters. */
233         CHECK(p, EINVAL);
234
235         /* Memory allocation. */
236         pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
237         CHECK(pipeline, ENOMEM);
238
239         /* Initialization. */
240         TAILQ_INIT(&pipeline->port_in_types);
241         TAILQ_INIT(&pipeline->ports_in);
242
243         pipeline->numa_node = numa_node;
244
245         *p = pipeline;
246         return 0;
247 }
248
249 void
250 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
251 {
252         if (!p)
253                 return;
254
255         port_in_free(p);
256
257         free(p);
258 }
259
260 int
261 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
262 {
263         int status;
264
265         CHECK(p, EINVAL);
266         CHECK(p->build_done == 0, EEXIST);
267
268         status = port_in_build(p);
269         if (status)
270                 goto error;
271
272         p->build_done = 1;
273         return 0;
274
275 error:
276         port_in_build_free(p);
277
278         return status;
279 }