cb2e32b83258e1746c94e3ebd754a6ddb07d3129
[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  * Struct.
25  */
26 struct field {
27         char name[RTE_SWX_NAME_SIZE];
28         uint32_t n_bits;
29         uint32_t offset;
30 };
31
32 struct struct_type {
33         TAILQ_ENTRY(struct_type) node;
34         char name[RTE_SWX_NAME_SIZE];
35         struct field *fields;
36         uint32_t n_fields;
37         uint32_t n_bits;
38 };
39
40 TAILQ_HEAD(struct_type_tailq, struct_type);
41
42 /*
43  * Input port.
44  */
45 struct port_in_type {
46         TAILQ_ENTRY(port_in_type) node;
47         char name[RTE_SWX_NAME_SIZE];
48         struct rte_swx_port_in_ops ops;
49 };
50
51 TAILQ_HEAD(port_in_type_tailq, port_in_type);
52
53 struct port_in {
54         TAILQ_ENTRY(port_in) node;
55         struct port_in_type *type;
56         void *obj;
57         uint32_t id;
58 };
59
60 TAILQ_HEAD(port_in_tailq, port_in);
61
62 struct port_in_runtime {
63         rte_swx_port_in_pkt_rx_t pkt_rx;
64         void *obj;
65 };
66
67 /*
68  * Output port.
69  */
70 struct port_out_type {
71         TAILQ_ENTRY(port_out_type) node;
72         char name[RTE_SWX_NAME_SIZE];
73         struct rte_swx_port_out_ops ops;
74 };
75
76 TAILQ_HEAD(port_out_type_tailq, port_out_type);
77
78 struct port_out {
79         TAILQ_ENTRY(port_out) node;
80         struct port_out_type *type;
81         void *obj;
82         uint32_t id;
83 };
84
85 TAILQ_HEAD(port_out_tailq, port_out);
86
87 struct port_out_runtime {
88         rte_swx_port_out_pkt_tx_t pkt_tx;
89         rte_swx_port_out_flush_t flush;
90         void *obj;
91 };
92
93 /*
94  * Header.
95  */
96 struct header {
97         TAILQ_ENTRY(header) node;
98         char name[RTE_SWX_NAME_SIZE];
99         struct struct_type *st;
100         uint32_t struct_id;
101         uint32_t id;
102 };
103
104 TAILQ_HEAD(header_tailq, header);
105
106 struct header_runtime {
107         uint8_t *ptr0;
108 };
109
110 struct header_out_runtime {
111         uint8_t *ptr0;
112         uint8_t *ptr;
113         uint32_t n_bytes;
114 };
115
116 /*
117  * Pipeline.
118  */
119 struct thread {
120         /* Structures. */
121         uint8_t **structs;
122
123         /* Packet headers. */
124         struct header_runtime *headers; /* Extracted or generated headers. */
125         struct header_out_runtime *headers_out; /* Emitted headers. */
126         uint8_t *header_storage;
127         uint8_t *header_out_storage;
128         uint64_t valid_headers;
129         uint32_t n_headers_out;
130
131         /* Packet meta-data. */
132         uint8_t *metadata;
133 };
134
135 #ifndef RTE_SWX_PIPELINE_THREADS_MAX
136 #define RTE_SWX_PIPELINE_THREADS_MAX 16
137 #endif
138
139 struct rte_swx_pipeline {
140         struct struct_type_tailq struct_types;
141         struct port_in_type_tailq port_in_types;
142         struct port_in_tailq ports_in;
143         struct port_out_type_tailq port_out_types;
144         struct port_out_tailq ports_out;
145         struct header_tailq headers;
146         struct struct_type *metadata_st;
147         uint32_t metadata_struct_id;
148
149         struct port_in_runtime *in;
150         struct port_out_runtime *out;
151         struct thread threads[RTE_SWX_PIPELINE_THREADS_MAX];
152
153         uint32_t n_structs;
154         uint32_t n_ports_in;
155         uint32_t n_ports_out;
156         uint32_t n_headers;
157         int build_done;
158         int numa_node;
159 };
160
161 /*
162  * Struct.
163  */
164 static struct struct_type *
165 struct_type_find(struct rte_swx_pipeline *p, const char *name)
166 {
167         struct struct_type *elem;
168
169         TAILQ_FOREACH(elem, &p->struct_types, node)
170                 if (strcmp(elem->name, name) == 0)
171                         return elem;
172
173         return NULL;
174 }
175
176 int
177 rte_swx_pipeline_struct_type_register(struct rte_swx_pipeline *p,
178                                       const char *name,
179                                       struct rte_swx_field_params *fields,
180                                       uint32_t n_fields)
181 {
182         struct struct_type *st;
183         uint32_t i;
184
185         CHECK(p, EINVAL);
186         CHECK_NAME(name, EINVAL);
187         CHECK(fields, EINVAL);
188         CHECK(n_fields, EINVAL);
189
190         for (i = 0; i < n_fields; i++) {
191                 struct rte_swx_field_params *f = &fields[i];
192                 uint32_t j;
193
194                 CHECK_NAME(f->name, EINVAL);
195                 CHECK(f->n_bits, EINVAL);
196                 CHECK(f->n_bits <= 64, EINVAL);
197                 CHECK((f->n_bits & 7) == 0, EINVAL);
198
199                 for (j = 0; j < i; j++) {
200                         struct rte_swx_field_params *f_prev = &fields[j];
201
202                         CHECK(strcmp(f->name, f_prev->name), EINVAL);
203                 }
204         }
205
206         CHECK(!struct_type_find(p, name), EEXIST);
207
208         /* Node allocation. */
209         st = calloc(1, sizeof(struct struct_type));
210         CHECK(st, ENOMEM);
211
212         st->fields = calloc(n_fields, sizeof(struct field));
213         if (!st->fields) {
214                 free(st);
215                 CHECK(0, ENOMEM);
216         }
217
218         /* Node initialization. */
219         strcpy(st->name, name);
220         for (i = 0; i < n_fields; i++) {
221                 struct field *dst = &st->fields[i];
222                 struct rte_swx_field_params *src = &fields[i];
223
224                 strcpy(dst->name, src->name);
225                 dst->n_bits = src->n_bits;
226                 dst->offset = st->n_bits;
227
228                 st->n_bits += src->n_bits;
229         }
230         st->n_fields = n_fields;
231
232         /* Node add to tailq. */
233         TAILQ_INSERT_TAIL(&p->struct_types, st, node);
234
235         return 0;
236 }
237
238 static int
239 struct_build(struct rte_swx_pipeline *p)
240 {
241         uint32_t i;
242
243         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
244                 struct thread *t = &p->threads[i];
245
246                 t->structs = calloc(p->n_structs, sizeof(uint8_t *));
247                 CHECK(t->structs, ENOMEM);
248         }
249
250         return 0;
251 }
252
253 static void
254 struct_build_free(struct rte_swx_pipeline *p)
255 {
256         uint32_t i;
257
258         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
259                 struct thread *t = &p->threads[i];
260
261                 free(t->structs);
262                 t->structs = NULL;
263         }
264 }
265
266 static void
267 struct_free(struct rte_swx_pipeline *p)
268 {
269         struct_build_free(p);
270
271         /* Struct types. */
272         for ( ; ; ) {
273                 struct struct_type *elem;
274
275                 elem = TAILQ_FIRST(&p->struct_types);
276                 if (!elem)
277                         break;
278
279                 TAILQ_REMOVE(&p->struct_types, elem, node);
280                 free(elem->fields);
281                 free(elem);
282         }
283 }
284
285 /*
286  * Input port.
287  */
288 static struct port_in_type *
289 port_in_type_find(struct rte_swx_pipeline *p, const char *name)
290 {
291         struct port_in_type *elem;
292
293         if (!name)
294                 return NULL;
295
296         TAILQ_FOREACH(elem, &p->port_in_types, node)
297                 if (strcmp(elem->name, name) == 0)
298                         return elem;
299
300         return NULL;
301 }
302
303 int
304 rte_swx_pipeline_port_in_type_register(struct rte_swx_pipeline *p,
305                                        const char *name,
306                                        struct rte_swx_port_in_ops *ops)
307 {
308         struct port_in_type *elem;
309
310         CHECK(p, EINVAL);
311         CHECK_NAME(name, EINVAL);
312         CHECK(ops, EINVAL);
313         CHECK(ops->create, EINVAL);
314         CHECK(ops->free, EINVAL);
315         CHECK(ops->pkt_rx, EINVAL);
316         CHECK(ops->stats_read, EINVAL);
317
318         CHECK(!port_in_type_find(p, name), EEXIST);
319
320         /* Node allocation. */
321         elem = calloc(1, sizeof(struct port_in_type));
322         CHECK(elem, ENOMEM);
323
324         /* Node initialization. */
325         strcpy(elem->name, name);
326         memcpy(&elem->ops, ops, sizeof(*ops));
327
328         /* Node add to tailq. */
329         TAILQ_INSERT_TAIL(&p->port_in_types, elem, node);
330
331         return 0;
332 }
333
334 static struct port_in *
335 port_in_find(struct rte_swx_pipeline *p, uint32_t port_id)
336 {
337         struct port_in *port;
338
339         TAILQ_FOREACH(port, &p->ports_in, node)
340                 if (port->id == port_id)
341                         return port;
342
343         return NULL;
344 }
345
346 int
347 rte_swx_pipeline_port_in_config(struct rte_swx_pipeline *p,
348                                 uint32_t port_id,
349                                 const char *port_type_name,
350                                 void *args)
351 {
352         struct port_in_type *type = NULL;
353         struct port_in *port = NULL;
354         void *obj = NULL;
355
356         CHECK(p, EINVAL);
357
358         CHECK(!port_in_find(p, port_id), EINVAL);
359
360         CHECK_NAME(port_type_name, EINVAL);
361         type = port_in_type_find(p, port_type_name);
362         CHECK(type, EINVAL);
363
364         obj = type->ops.create(args);
365         CHECK(obj, ENODEV);
366
367         /* Node allocation. */
368         port = calloc(1, sizeof(struct port_in));
369         CHECK(port, ENOMEM);
370
371         /* Node initialization. */
372         port->type = type;
373         port->obj = obj;
374         port->id = port_id;
375
376         /* Node add to tailq. */
377         TAILQ_INSERT_TAIL(&p->ports_in, port, node);
378         if (p->n_ports_in < port_id + 1)
379                 p->n_ports_in = port_id + 1;
380
381         return 0;
382 }
383
384 static int
385 port_in_build(struct rte_swx_pipeline *p)
386 {
387         struct port_in *port;
388         uint32_t i;
389
390         CHECK(p->n_ports_in, EINVAL);
391         CHECK(rte_is_power_of_2(p->n_ports_in), EINVAL);
392
393         for (i = 0; i < p->n_ports_in; i++)
394                 CHECK(port_in_find(p, i), EINVAL);
395
396         p->in = calloc(p->n_ports_in, sizeof(struct port_in_runtime));
397         CHECK(p->in, ENOMEM);
398
399         TAILQ_FOREACH(port, &p->ports_in, node) {
400                 struct port_in_runtime *in = &p->in[port->id];
401
402                 in->pkt_rx = port->type->ops.pkt_rx;
403                 in->obj = port->obj;
404         }
405
406         return 0;
407 }
408
409 static void
410 port_in_build_free(struct rte_swx_pipeline *p)
411 {
412         free(p->in);
413         p->in = NULL;
414 }
415
416 static void
417 port_in_free(struct rte_swx_pipeline *p)
418 {
419         port_in_build_free(p);
420
421         /* Input ports. */
422         for ( ; ; ) {
423                 struct port_in *port;
424
425                 port = TAILQ_FIRST(&p->ports_in);
426                 if (!port)
427                         break;
428
429                 TAILQ_REMOVE(&p->ports_in, port, node);
430                 port->type->ops.free(port->obj);
431                 free(port);
432         }
433
434         /* Input port types. */
435         for ( ; ; ) {
436                 struct port_in_type *elem;
437
438                 elem = TAILQ_FIRST(&p->port_in_types);
439                 if (!elem)
440                         break;
441
442                 TAILQ_REMOVE(&p->port_in_types, elem, node);
443                 free(elem);
444         }
445 }
446
447 /*
448  * Output port.
449  */
450 static struct port_out_type *
451 port_out_type_find(struct rte_swx_pipeline *p, const char *name)
452 {
453         struct port_out_type *elem;
454
455         if (!name)
456                 return NULL;
457
458         TAILQ_FOREACH(elem, &p->port_out_types, node)
459                 if (!strcmp(elem->name, name))
460                         return elem;
461
462         return NULL;
463 }
464
465 int
466 rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p,
467                                         const char *name,
468                                         struct rte_swx_port_out_ops *ops)
469 {
470         struct port_out_type *elem;
471
472         CHECK(p, EINVAL);
473         CHECK_NAME(name, EINVAL);
474         CHECK(ops, EINVAL);
475         CHECK(ops->create, EINVAL);
476         CHECK(ops->free, EINVAL);
477         CHECK(ops->pkt_tx, EINVAL);
478         CHECK(ops->stats_read, EINVAL);
479
480         CHECK(!port_out_type_find(p, name), EEXIST);
481
482         /* Node allocation. */
483         elem = calloc(1, sizeof(struct port_out_type));
484         CHECK(elem, ENOMEM);
485
486         /* Node initialization. */
487         strcpy(elem->name, name);
488         memcpy(&elem->ops, ops, sizeof(*ops));
489
490         /* Node add to tailq. */
491         TAILQ_INSERT_TAIL(&p->port_out_types, elem, node);
492
493         return 0;
494 }
495
496 static struct port_out *
497 port_out_find(struct rte_swx_pipeline *p, uint32_t port_id)
498 {
499         struct port_out *port;
500
501         TAILQ_FOREACH(port, &p->ports_out, node)
502                 if (port->id == port_id)
503                         return port;
504
505         return NULL;
506 }
507
508 int
509 rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p,
510                                  uint32_t port_id,
511                                  const char *port_type_name,
512                                  void *args)
513 {
514         struct port_out_type *type = NULL;
515         struct port_out *port = NULL;
516         void *obj = NULL;
517
518         CHECK(p, EINVAL);
519
520         CHECK(!port_out_find(p, port_id), EINVAL);
521
522         CHECK_NAME(port_type_name, EINVAL);
523         type = port_out_type_find(p, port_type_name);
524         CHECK(type, EINVAL);
525
526         obj = type->ops.create(args);
527         CHECK(obj, ENODEV);
528
529         /* Node allocation. */
530         port = calloc(1, sizeof(struct port_out));
531         CHECK(port, ENOMEM);
532
533         /* Node initialization. */
534         port->type = type;
535         port->obj = obj;
536         port->id = port_id;
537
538         /* Node add to tailq. */
539         TAILQ_INSERT_TAIL(&p->ports_out, port, node);
540         if (p->n_ports_out < port_id + 1)
541                 p->n_ports_out = port_id + 1;
542
543         return 0;
544 }
545
546 static int
547 port_out_build(struct rte_swx_pipeline *p)
548 {
549         struct port_out *port;
550         uint32_t i;
551
552         CHECK(p->n_ports_out, EINVAL);
553
554         for (i = 0; i < p->n_ports_out; i++)
555                 CHECK(port_out_find(p, i), EINVAL);
556
557         p->out = calloc(p->n_ports_out, sizeof(struct port_out_runtime));
558         CHECK(p->out, ENOMEM);
559
560         TAILQ_FOREACH(port, &p->ports_out, node) {
561                 struct port_out_runtime *out = &p->out[port->id];
562
563                 out->pkt_tx = port->type->ops.pkt_tx;
564                 out->flush = port->type->ops.flush;
565                 out->obj = port->obj;
566         }
567
568         return 0;
569 }
570
571 static void
572 port_out_build_free(struct rte_swx_pipeline *p)
573 {
574         free(p->out);
575         p->out = NULL;
576 }
577
578 static void
579 port_out_free(struct rte_swx_pipeline *p)
580 {
581         port_out_build_free(p);
582
583         /* Output ports. */
584         for ( ; ; ) {
585                 struct port_out *port;
586
587                 port = TAILQ_FIRST(&p->ports_out);
588                 if (!port)
589                         break;
590
591                 TAILQ_REMOVE(&p->ports_out, port, node);
592                 port->type->ops.free(port->obj);
593                 free(port);
594         }
595
596         /* Output port types. */
597         for ( ; ; ) {
598                 struct port_out_type *elem;
599
600                 elem = TAILQ_FIRST(&p->port_out_types);
601                 if (!elem)
602                         break;
603
604                 TAILQ_REMOVE(&p->port_out_types, elem, node);
605                 free(elem);
606         }
607 }
608
609 /*
610  * Header.
611  */
612 static struct header *
613 header_find(struct rte_swx_pipeline *p, const char *name)
614 {
615         struct header *elem;
616
617         TAILQ_FOREACH(elem, &p->headers, node)
618                 if (strcmp(elem->name, name) == 0)
619                         return elem;
620
621         return NULL;
622 }
623
624 int
625 rte_swx_pipeline_packet_header_register(struct rte_swx_pipeline *p,
626                                         const char *name,
627                                         const char *struct_type_name)
628 {
629         struct struct_type *st;
630         struct header *h;
631         size_t n_headers_max;
632
633         CHECK(p, EINVAL);
634         CHECK_NAME(name, EINVAL);
635         CHECK_NAME(struct_type_name, EINVAL);
636
637         CHECK(!header_find(p, name), EEXIST);
638
639         st = struct_type_find(p, struct_type_name);
640         CHECK(st, EINVAL);
641
642         n_headers_max = RTE_SIZEOF_FIELD(struct thread, valid_headers) * 8;
643         CHECK(p->n_headers < n_headers_max, ENOSPC);
644
645         /* Node allocation. */
646         h = calloc(1, sizeof(struct header));
647         CHECK(h, ENOMEM);
648
649         /* Node initialization. */
650         strcpy(h->name, name);
651         h->st = st;
652         h->struct_id = p->n_structs;
653         h->id = p->n_headers;
654
655         /* Node add to tailq. */
656         TAILQ_INSERT_TAIL(&p->headers, h, node);
657         p->n_headers++;
658         p->n_structs++;
659
660         return 0;
661 }
662
663 static int
664 header_build(struct rte_swx_pipeline *p)
665 {
666         struct header *h;
667         uint32_t n_bytes = 0, i;
668
669         TAILQ_FOREACH(h, &p->headers, node) {
670                 n_bytes += h->st->n_bits / 8;
671         }
672
673         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
674                 struct thread *t = &p->threads[i];
675                 uint32_t offset = 0;
676
677                 t->headers = calloc(p->n_headers,
678                                     sizeof(struct header_runtime));
679                 CHECK(t->headers, ENOMEM);
680
681                 t->headers_out = calloc(p->n_headers,
682                                         sizeof(struct header_out_runtime));
683                 CHECK(t->headers_out, ENOMEM);
684
685                 t->header_storage = calloc(1, n_bytes);
686                 CHECK(t->header_storage, ENOMEM);
687
688                 t->header_out_storage = calloc(1, n_bytes);
689                 CHECK(t->header_out_storage, ENOMEM);
690
691                 TAILQ_FOREACH(h, &p->headers, node) {
692                         uint8_t *header_storage;
693
694                         header_storage = &t->header_storage[offset];
695                         offset += h->st->n_bits / 8;
696
697                         t->headers[h->id].ptr0 = header_storage;
698                         t->structs[h->struct_id] = header_storage;
699                 }
700         }
701
702         return 0;
703 }
704
705 static void
706 header_build_free(struct rte_swx_pipeline *p)
707 {
708         uint32_t i;
709
710         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
711                 struct thread *t = &p->threads[i];
712
713                 free(t->headers_out);
714                 t->headers_out = NULL;
715
716                 free(t->headers);
717                 t->headers = NULL;
718
719                 free(t->header_out_storage);
720                 t->header_out_storage = NULL;
721
722                 free(t->header_storage);
723                 t->header_storage = NULL;
724         }
725 }
726
727 static void
728 header_free(struct rte_swx_pipeline *p)
729 {
730         header_build_free(p);
731
732         for ( ; ; ) {
733                 struct header *elem;
734
735                 elem = TAILQ_FIRST(&p->headers);
736                 if (!elem)
737                         break;
738
739                 TAILQ_REMOVE(&p->headers, elem, node);
740                 free(elem);
741         }
742 }
743
744 /*
745  * Meta-data.
746  */
747 int
748 rte_swx_pipeline_packet_metadata_register(struct rte_swx_pipeline *p,
749                                           const char *struct_type_name)
750 {
751         struct struct_type *st = NULL;
752
753         CHECK(p, EINVAL);
754
755         CHECK_NAME(struct_type_name, EINVAL);
756         st  = struct_type_find(p, struct_type_name);
757         CHECK(st, EINVAL);
758         CHECK(!p->metadata_st, EINVAL);
759
760         p->metadata_st = st;
761         p->metadata_struct_id = p->n_structs;
762
763         p->n_structs++;
764
765         return 0;
766 }
767
768 static int
769 metadata_build(struct rte_swx_pipeline *p)
770 {
771         uint32_t n_bytes = p->metadata_st->n_bits / 8;
772         uint32_t i;
773
774         /* Thread-level initialization. */
775         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
776                 struct thread *t = &p->threads[i];
777                 uint8_t *metadata;
778
779                 metadata = calloc(1, n_bytes);
780                 CHECK(metadata, ENOMEM);
781
782                 t->metadata = metadata;
783                 t->structs[p->metadata_struct_id] = metadata;
784         }
785
786         return 0;
787 }
788
789 static void
790 metadata_build_free(struct rte_swx_pipeline *p)
791 {
792         uint32_t i;
793
794         for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
795                 struct thread *t = &p->threads[i];
796
797                 free(t->metadata);
798                 t->metadata = NULL;
799         }
800 }
801
802 static void
803 metadata_free(struct rte_swx_pipeline *p)
804 {
805         metadata_build_free(p);
806 }
807
808 /*
809  * Pipeline.
810  */
811 int
812 rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
813 {
814         struct rte_swx_pipeline *pipeline;
815
816         /* Check input parameters. */
817         CHECK(p, EINVAL);
818
819         /* Memory allocation. */
820         pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
821         CHECK(pipeline, ENOMEM);
822
823         /* Initialization. */
824         TAILQ_INIT(&pipeline->struct_types);
825         TAILQ_INIT(&pipeline->port_in_types);
826         TAILQ_INIT(&pipeline->ports_in);
827         TAILQ_INIT(&pipeline->port_out_types);
828         TAILQ_INIT(&pipeline->ports_out);
829         TAILQ_INIT(&pipeline->headers);
830
831         pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */
832         pipeline->numa_node = numa_node;
833
834         *p = pipeline;
835         return 0;
836 }
837
838 void
839 rte_swx_pipeline_free(struct rte_swx_pipeline *p)
840 {
841         if (!p)
842                 return;
843
844         metadata_free(p);
845         header_free(p);
846         port_out_free(p);
847         port_in_free(p);
848         struct_free(p);
849
850         free(p);
851 }
852
853 int
854 rte_swx_pipeline_build(struct rte_swx_pipeline *p)
855 {
856         int status;
857
858         CHECK(p, EINVAL);
859         CHECK(p->build_done == 0, EEXIST);
860
861         status = port_in_build(p);
862         if (status)
863                 goto error;
864
865         status = port_out_build(p);
866         if (status)
867                 goto error;
868
869         status = struct_build(p);
870         if (status)
871                 goto error;
872
873         status = header_build(p);
874         if (status)
875                 goto error;
876
877         status = metadata_build(p);
878         if (status)
879                 goto error;
880
881         p->build_done = 1;
882         return 0;
883
884 error:
885         metadata_build_free(p);
886         header_build_free(p);
887         port_out_build_free(p);
888         port_in_build_free(p);
889         struct_build_free(p);
890
891         return status;
892 }