5b1dc47dd2d4071cd6c7a267f0bff8be42fa3eb7
[o-du/phy.git] / fhi_lib / lib / src / xran_app_frag.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2019 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19
20 /**
21  * @brief xRAN application frgamentation for U-plane packets
22  *
23  * @file xran_app_frag.c
24  * @ingroup group_source_xran
25  * @author Intel Corporation
26  **/
27
28 #include <stdio.h>
29 #include <stddef.h>
30 #include <errno.h>
31
32 #include <rte_mbuf.h>
33 #include <rte_memcpy.h>
34 #include <rte_mempool.h>
35 #include <rte_debug.h>
36
37 #include "xran_app_frag.h"
38 #include "xran_cp_api.h"
39 #include "xran_pkt_up.h"
40 #include "xran_printf.h"
41 #include "xran_common.h"
42
43 /* Fragment alignment */
44 #define    XRAN_PAYLOAD_RB_ALIGN  (N_SC_PER_PRB*(IQ_BITS/8)*2) /**< at least 12*4=48 bytes per one RB */
45
46 static inline void __fill_xranhdr_frag(struct xran_up_pkt_hdr *dst,
47         const struct xran_up_pkt_hdr *src, uint16_t rblen_bytes,
48         uint16_t rboff_bytes, struct xran_section_info *sectinfo, uint32_t mf, uint8_t *seqid)
49 {
50     struct data_section_hdr loc_data_sec_hdr;
51     struct xran_ecpri_hdr loc_ecpri_hdr;
52
53     rte_memcpy(dst, src, sizeof(*dst));
54
55     if(dst->ecpri_hdr.ecpri_seq_id.seq_id != *seqid - 1){
56         /* not first fragment, incease seq id */
57         dst->ecpri_hdr.ecpri_seq_id.seq_id = *seqid++;
58     }
59
60     loc_data_sec_hdr.fields.all_bits = rte_be_to_cpu_32(dst->data_sec_hdr.fields.all_bits);
61
62     /* update RBs */
63     loc_data_sec_hdr.fields.start_prbu = sectinfo->startPrbc + rboff_bytes/(N_SC_PER_PRB*(IQ_BITS/8*2));
64     loc_data_sec_hdr.fields.num_prbu   = rblen_bytes/(N_SC_PER_PRB*(IQ_BITS/8*2));
65
66     print_dbg("sec [%d %d] pkt [%d %d] rboff_bytes %d rblen_bytes %d\n",sectinfo->startPrbc, sectinfo->numPrbc, loc_data_sec_hdr.fields.start_prbu, loc_data_sec_hdr.fields.num_prbu,
67         rboff_bytes, rblen_bytes);
68
69     dst->data_sec_hdr.fields.all_bits = rte_cpu_to_be_32(loc_data_sec_hdr.fields.all_bits);
70
71     /* update length */
72     dst->ecpri_hdr.cmnhdr.ecpri_payl_size = rte_cpu_to_be_16(sizeof(struct radio_app_common_hdr) +
73                 sizeof(struct data_section_hdr) + rblen_bytes + xran_get_ecpri_hdr_size());
74 }
75
76
77 static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)
78 {
79     uint32_t i;
80     for (i = 0; i != num; i++)
81         rte_pktmbuf_free(mb[i]);
82 }
83
84 /**
85  * XRAN fragmentation.
86  *
87  * This function implements the application fragmentation of XRAN packets.
88  *
89  * @param pkt_in
90  *   The input packet.
91  * @param pkts_out
92  *   Array storing the output fragments.
93  * @param mtu_size
94  *   Size in bytes of the Maximum Transfer Unit (MTU) for the outgoing XRAN
95  *   datagrams. This value includes the size of the XRAN headers.
96  * @param pool_direct
97  *   MBUF pool used for allocating direct buffers for the output fragments.
98  * @param pool_indirect
99  *   MBUF pool used for allocating indirect buffers for the output fragments.
100  * @return
101  *   Upon successful completion - number of output fragments placed
102  *   in the pkts_out array.
103  *   Otherwise - (-1) * <errno>.
104  */
105 int32_t
106 xran_app_fragment_packet(struct rte_mbuf *pkt_in, /* eth hdr is prepended */
107     struct rte_mbuf **pkts_out,
108     uint16_t nb_pkts_out,
109     uint16_t mtu_size,
110     struct rte_mempool *pool_direct,
111     struct rte_mempool *pool_indirect,
112     struct xran_section_info *sectinfo,
113     uint8_t *seqid)
114 {
115     struct rte_mbuf *in_seg = NULL;
116     uint32_t out_pkt_pos =  0, in_seg_data_pos = 0;
117     uint32_t more_in_segs;
118     uint16_t fragment_offset, frag_size;
119     uint16_t frag_bytes_remaining;
120     struct eth_xran_up_pkt_hdr *in_hdr;
121     struct xran_up_pkt_hdr *in_hdr_xran;
122
123     /*
124      * Ensure the XRAN payload length of all fragments is aligned to a
125      * multiple of 48 bytes (1 RB with IQ of 16 bits each)
126      */
127     frag_size = ((mtu_size - sizeof(struct eth_xran_up_pkt_hdr) - RTE_PKTMBUF_HEADROOM)/XRAN_PAYLOAD_RB_ALIGN)*XRAN_PAYLOAD_RB_ALIGN;
128
129
130     print_dbg("frag_size %d\n",frag_size);
131
132     in_hdr = rte_pktmbuf_mtod(pkt_in, struct eth_xran_up_pkt_hdr *);
133
134     in_hdr_xran = &in_hdr->xran_hdr;
135
136     /* Check that pkts_out is big enough to hold all fragments */
137     if (unlikely(frag_size * nb_pkts_out <
138         (uint16_t)(pkt_in->pkt_len - sizeof (struct xran_up_pkt_hdr)))){
139         print_err("-EINVAL\n");
140         return -EINVAL;
141     }
142
143     in_seg = pkt_in;
144     in_seg_data_pos = sizeof(struct eth_xran_up_pkt_hdr);
145     out_pkt_pos = 0;
146     fragment_offset = 0;
147
148     more_in_segs = 1;
149     while (likely(more_in_segs)) {
150         struct rte_mbuf *out_pkt = NULL, *out_seg_prev = NULL;
151         uint32_t more_out_segs;
152         struct xran_up_pkt_hdr *out_hdr;
153
154         /* Allocate direct buffer */
155         out_pkt = rte_pktmbuf_alloc(pool_direct);
156         if (unlikely(out_pkt == NULL)) {
157             print_err("pool_direct -ENOMEM\n");
158             __free_fragments(pkts_out, out_pkt_pos);
159             return -ENOMEM;
160         }
161
162         print_dbg("[%d] out_pkt %p\n",more_in_segs, out_pkt);
163
164         /* Reserve space for the XRAN header that will be built later */
165         //out_pkt->data_len = sizeof(struct xran_up_pkt_hdr);
166          //out_pkt->pkt_len = sizeof(struct xran_up_pkt_hdr);
167         if(rte_pktmbuf_append(out_pkt, sizeof(struct xran_up_pkt_hdr)) ==NULL){
168             rte_panic("sizeof(struct xran_up_pkt_hdr)");
169         }
170         frag_bytes_remaining = frag_size;
171
172         out_seg_prev = out_pkt;
173         more_out_segs = 1;
174         while (likely(more_out_segs && more_in_segs)) {
175             uint32_t len;
176 #ifdef XRAN_ATTACH_MBUF
177             struct rte_mbuf *out_seg = NULL;
178
179             /* Allocate indirect buffer */
180             print_dbg("Allocate indirect buffer \n");
181             out_seg = rte_pktmbuf_alloc(pool_indirect);
182             if (unlikely(out_seg == NULL)) {
183                 print_err("pool_indirect -ENOMEM\n");
184                 rte_pktmbuf_free(out_pkt);
185                 __free_fragments(pkts_out, out_pkt_pos);
186                 return -ENOMEM;
187             }
188
189             print_dbg("[%d %d] out_seg %p\n",more_out_segs, more_in_segs, out_seg);
190             out_seg_prev->next = out_seg;
191             out_seg_prev = out_seg;
192
193             /* Prepare indirect buffer */
194             rte_pktmbuf_attach(out_seg, in_seg);
195 #endif
196             len = frag_bytes_remaining;
197             if (len > (in_seg->data_len - in_seg_data_pos)) {
198                 len = in_seg->data_len - in_seg_data_pos;
199             }
200 #ifdef XRAN_ATTACH_MBUF
201             out_seg->data_off = in_seg->data_off + in_seg_data_pos;
202             out_seg->data_len = (uint16_t)len;
203             out_pkt->pkt_len = (uint16_t)(len +
204                 out_pkt->pkt_len);
205             out_pkt->nb_segs += 1;
206 #else
207 {
208             char* pChar   = rte_pktmbuf_mtod(in_seg, char*);
209             void *iq_src  = (pChar + in_seg_data_pos);
210             void *iq_dst  = rte_pktmbuf_append(out_pkt, len);
211
212             print_dbg("rte_pktmbuf_attach\n");
213             if(iq_src && iq_dst)
214                 rte_memcpy(iq_dst, iq_src, len);
215             else
216                 print_err("iq_src %p iq_dst %p\n len %d room %d\n", iq_src, iq_dst, len, rte_pktmbuf_tailroom(out_pkt));
217 }
218 #endif
219             in_seg_data_pos += len;
220             frag_bytes_remaining -= len;
221
222             /* Current output packet (i.e. fragment) done ? */
223             if (unlikely(frag_bytes_remaining == 0))
224                 more_out_segs = 0;
225
226             /* Current input segment done ? */
227             if (unlikely(in_seg_data_pos == in_seg->data_len)) {
228                 in_seg = in_seg->next;
229                 in_seg_data_pos = 0;
230
231                 if (unlikely(in_seg == NULL))
232                     more_in_segs = 0;
233             }
234         }
235
236         /* Build the XRAN header */
237         print_dbg("Build the XRAN header\n");
238         out_hdr = rte_pktmbuf_mtod(out_pkt, struct xran_up_pkt_hdr *);
239
240         __fill_xranhdr_frag(out_hdr, in_hdr_xran,
241             (uint16_t)out_pkt->pkt_len - sizeof(struct xran_up_pkt_hdr),
242             fragment_offset, sectinfo, more_in_segs, seqid);
243
244         fragment_offset = (uint16_t)(fragment_offset +
245             out_pkt->pkt_len - sizeof(struct xran_up_pkt_hdr));
246
247         //out_pkt->l3_len = sizeof(struct xran_up_pkt_hdr);
248
249         /* Write the fragment to the output list */
250         pkts_out[out_pkt_pos] = out_pkt;
251         print_dbg("out_pkt_pos %d data_len %d pkt_len %d\n", out_pkt_pos, out_pkt->data_len, out_pkt->pkt_len);
252         out_pkt_pos ++;
253         //rte_pktmbuf_dump(stdout, out_pkt, 96);
254     }
255
256     return out_pkt_pos;
257 }
258
259