1 /******************************************************************************
3 * Copyright (c) 2020 Intel.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 *******************************************************************************/
20 * @brief XRAN layer one-way delay measurement support
21 * @file xran_delay_measurement.c
22 * @ingroup group_source_xran
23 * @author Intel Corporation
26 #include <immintrin.h>
29 #include <arpa/inet.h>
35 #include <rte_ethdev.h>
38 #include "xran_common.h"
42 #include "xran_lib_mlog_tasks_id.h"
43 #include "xran_ecpri_owd_measurements.h"
45 #include "xran_printf.h"
46 #include "xran_mlog_lnx.h"
48 //#define ORAN_OWD_DEBUG_MSG_FLOW
49 //#define XRAN_OWD_DEBUG_MSG_FLOW
50 //#define XRAN_OWD_DEBUG_DELAY_INFO
51 //#define XRAN_OWD_DEBUG_TIME_STAMPS_INFO
52 //#define XRAN_OWD_DEBUG_MEAS_DB
53 //#define XRAN_OWD_TIMING_MODS
56 // Support for 1-way eCPRI delay measurement per section 3.2.4.6 of eCPRI Specification V2.0
58 uint64_t xran_ptp_to_host(uint64_t compValue)
60 return (rte_be_to_cpu_64(compValue));
62 void xran_host_to_ptp_ts(TimeStamp *ts, struct timespec *t)
64 uint64_t seconds, nanoseconds;
67 nanoseconds = t->tv_nsec%1000000000LL;
68 #ifdef XRAN_OWD_DEBUG_DELAY_CONV_FUNCTIONS
69 printf("H2P_ts tv_sec %8"PRIx64" tv_nsec %8"PRIx64" seconds %8"PRIx64" ns %8"PRIx64" \n",t->tv_sec,t->tv_nsec,seconds,nanoseconds);
72 ts->secs_msb = rte_cpu_to_be_16((rte_be16_t)((seconds >> 32) & 0xFFFF));
73 ts->secs_lsb = rte_cpu_to_be_32((rte_be32_t)(seconds & 0xFFFFFFFF));
74 ts->ns = rte_cpu_to_be_32((rte_be32_t)nanoseconds);
75 #ifdef XRAN_OWD_DEBUG_DELAY_CONV_FUNCTIONS
76 printf("Net order s_msb %4"PRIx16" s_lsb %8"PRIx32" ns %8"PRIx32" \n", ts->secs_msb, ts->secs_lsb,ts->ns );
80 uint64_t xran_ptp_ts_to_ns(TimeStamp *t)
82 uint64_t seconds, nanoseconds;
84 // Convert to host order
85 t->secs_msb=rte_be_to_cpu_16(t->secs_msb);
86 t->secs_lsb=rte_be_to_cpu_32(t->secs_lsb);
87 seconds = ((uint64_t)t->secs_msb << 32) | ((uint64_t)t->secs_lsb );
88 nanoseconds = rte_be_to_cpu_32((uint64_t)t->ns);
89 ret_value = seconds * NS_PER_SEC + nanoseconds;
90 #ifdef XRAN_OWD_DEBUG_DELAY_CONV_FUNCTIONS
91 printf("PTP ts to ns sec_msb %4"PRIx16" secs_lsb %4"PRIx32" ns %4"PRIx32" seconds %8"PRIx64" nanosec %8"PRIx64" ret_value %8"PRIx64"\n",t->secs_msb,t->secs_lsb,t->ns,seconds, nanoseconds,ret_value);
96 static inline uint64_t xran_timespec_to_ns(struct timespec *t)
100 ret_val = t->tv_sec * NS_PER_SEC + t->tv_nsec;
101 #ifdef XRAN_OWD_DEBUG_DELAY_CONV_FUNCTIONS
102 printf("t->tv_sec is %08"PRIx64" tv_nsec is %08"PRIx64" ret_val is %08"PRIx64" ts_to_ns\n",t->tv_sec,t->tv_nsec,ret_val);
108 void xran_ns_to_timespec(uint64_t ns, struct timespec *t)
110 t->tv_sec = ns/NS_PER_SEC;
111 t->tv_nsec = ns % NS_PER_SEC;
115 void xran_initialize_and_verify_owd_pl_length(void* handle)
117 struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)handle;
119 if ((p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id].owdm_PlLength == 0)||(p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id].owdm_PlLength < MIN_OWDM_PL_LENGTH))
121 // Use default length value
122 p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id].owdm_PlLength = MIN_OWDM_PL_LENGTH;
124 else if ( p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id].owdm_PlLength > MAX_OWDM_PL_LENGTH)
126 p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id].owdm_PlLength = MAX_OWDM_PL_LENGTH;
131 void xran_adjust_timing_parameters(void* Handle)
133 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx*)Handle;
134 #ifdef XRAN_OWD_TIMING_MODS
135 printf("delayAvg is %d and DELAY_THRESHOLD is %d \n", p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][0].delayAvg, DELAY_THRESHOLD);
137 if (p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][0].delayAvg < DELAY_THRESHOLD )
139 /* Modify the timing parameters */
140 if (p_xran_dev_ctx->fh_cfg.T1a_max_up >= ADJUSTMENT)
141 p_xran_dev_ctx->fh_cfg.T1a_max_up -= ADJUSTMENT;
142 if (p_xran_dev_ctx->fh_cfg.T2a_max_up >= ADJUSTMENT)
143 p_xran_dev_ctx->fh_cfg.T2a_max_up -= ADJUSTMENT;
144 if (p_xran_dev_ctx->fh_cfg.Ta3_min >= ADJUSTMENT)
145 p_xran_dev_ctx->fh_cfg.Ta3_min -= ADJUSTMENT;
146 if (p_xran_dev_ctx->fh_cfg.T1a_max_cp_dl >= ADJUSTMENT)
147 p_xran_dev_ctx->fh_cfg.T1a_max_cp_dl -= ADJUSTMENT;
148 if (p_xran_dev_ctx->fh_cfg.T1a_min_up >= ADJUSTMENT)
149 p_xran_dev_ctx->fh_cfg.T1a_min_up -= ADJUSTMENT;
150 if (p_xran_dev_ctx->fh_cfg.T1a_max_up >= ADJUSTMENT)
151 p_xran_dev_ctx->fh_cfg.T1a_max_up -= ADJUSTMENT;
152 if (p_xran_dev_ctx->fh_cfg.Ta4_min >= ADJUSTMENT)
153 p_xran_dev_ctx->fh_cfg.Ta4_min -= ADJUSTMENT;
154 if (p_xran_dev_ctx->fh_cfg.Ta4_max >= ADJUSTMENT)
155 p_xran_dev_ctx->fh_cfg.Ta4_max -= ADJUSTMENT;
156 #ifdef XRAN_OWD_TIMING_MODS
157 printf("Mod T1a_max_up is %d\n",p_xran_dev_ctx->fh_cfg.T1a_max_up);
158 printf("Mod T2a_max_up is %d\n",p_xran_dev_ctx->fh_cfg.T2a_max_up);
159 printf("Mod Ta3_min is %d\n",p_xran_dev_ctx->fh_cfg.Ta3_min);
160 printf("Mod T1a_max_cp_dl is %d\n",p_xran_dev_ctx->fh_cfg.T1a_max_cp_dl);
161 printf("Mod T1a_min_up is %d\n",p_xran_dev_ctx->fh_cfg.T1a_min_up);
162 printf("Mod T1a_max_up is %d\n",p_xran_dev_ctx->fh_cfg.T1a_max_up);
163 printf("Mod Ta4_min is %d\n",p_xran_dev_ctx->fh_cfg.Ta4_min);
164 printf("Mod Ta4_max is %d\n",p_xran_dev_ctx->fh_cfg.Ta4_max);
172 void xran_compute_and_report_delay_estimate (struct xran_ecpri_del_meas_port *portData, uint16_t totalSamples, uint16_t id )
175 uint64_t *samples= portData->delaySamples;
178 for (i=2 ; i < MX_NUM_SAMPLES; i++) //Ignore first 2 samples
180 portData->delayAvg += samples[i];
184 // Average the delay by the number of samples
185 if ((totalSamples != 0)&&(totalSamples > 2))
187 portData->delayAvg /= (totalSamples-2);
189 // Report Average with printf
191 printf("OWD for port %i is %lu [ns] id %d \n", portData->portid, portData->delayAvg, id);
196 int xran_get_delay_measurements_results (void* handle, uint16_t port_id, uint8_t id, uint64_t* pdelay_avg)
198 int ret_value = FAIL;
199 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx*)handle;
200 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[id][port_id];
201 // Check is the one way delay measurement completed successfully
202 if (powdp->msState == XRAN_OWDM_DONE)
204 *pdelay_avg = powdp->delayAvg;
211 void xran_build_owd_meas_ecpri_hdr(char* mbuf, struct xran_ecpri_del_meas_cmn* eowdcmn)
213 union xran_ecpri_cmn_hdr *tmp= (union xran_ecpri_cmn_hdr*)mbuf;
214 /* Fill common header */
215 tmp->bits.ecpri_ver = XRAN_ECPRI_VER;
216 tmp->bits.ecpri_resv = 0; // should be zero
217 tmp->bits.ecpri_concat = 0;
218 tmp->bits.ecpri_mesg_type = ECPRI_DELAY_MEASUREMENT;
219 tmp->bits.ecpri_payl_size = 10 + eowdcmn->owdm_PlLength;
220 tmp->bits.ecpri_payl_size = rte_cpu_to_be_16(tmp->bits.ecpri_payl_size);
223 void xran_add_at_and_measId_info_to_header(void* pbuf, uint8_t actionType, uint8_t MeasurementID)
225 struct xran_ecpri_delay_meas_pl* tmp = (struct xran_ecpri_delay_meas_pl*)pbuf;
226 // Fill ActionType and MeasurementId
227 tmp->ActionType = actionType;
228 tmp->MeasurementID = MeasurementID;
231 void xran_initialize_ecpri_del_meas_port(struct xran_ecpri_del_meas_cmn* pCmn, struct xran_ecpri_del_meas_port* pPort, uint16_t full)
235 // Initialize port parameters during the first pass
236 pPort->currentMeasID++;
243 pPort->portid = pCmn->measVf;
249 #ifdef XRAN_OWD_DEBUG_MEAS_DB
250 printf("Clearing t1 and delta\n");
253 for (i=0; i < MX_NUM_SAMPLES; i++)
255 pPort->delaySamples[i] = 0;
258 // Set msState based on measMethod and whether the FHI is initiator or recipient
260 if (pCmn->initiator_en)
262 switch (pCmn->measMethod)
265 pPort->msState = XRAN_OWDM_WAITRESP;
268 pPort->msState = XRAN_OWDM_WAITREQ;
271 pPort->msState = XRAN_OWDM_WAITRESP;
273 case XRAN_REM_REQ_WFUP:
274 pPort->msState = XRAN_OWDM_WAITREQWFUP;
277 pPort->msState = XRAN_OWDM_WAITRESP;
283 switch (pCmn->measMethod)
286 pPort->msState = XRAN_OWDM_WAITREQ;
289 pPort->msState = XRAN_OWDM_WAITREMREQ;
292 pPort->msState = XRAN_OWDM_WAITREQWFUP;
294 case XRAN_REM_REQ_WFUP:
295 pPort->msState = XRAN_OWDM_WAITREMREQWFUP;
298 pPort->msState = XRAN_OWDM_WAITREQ;
304 int32_t xran_ecpri_port_update_required (struct xran_io_cfg * cfg, uint16_t port_id)
306 int32_t ret_value = 0;
307 int32_t* port = &cfg->port[0];
312 struct xran_ecpri_del_meas_port* eowdp = &cfg->eowd_port[cfg->id][port_id];
313 struct xran_ecpri_del_meas_cmn* eowdc = &cfg->eowd_cmn[cfg->id];
316 // Check if the current port has completed all the measurements to move to the next port
317 if (eowdp->numMeas == eowdc->numberOfSamples)
319 // Mark state as done and move to the next port
320 if (port_id < cfg->num_vfs)
323 if (port[port_id] == 0xFF)
325 // Done with all ports disable further execution
326 eowdc->owdm_enable = 0;
331 eowdp= &cfg->eowd_port[cfg->id][port_id];
332 // Initialize the next port
333 #ifdef XRAN_OWD_DEBUG_MEAS_DB
334 printf("Init call_1 port %d\n", port_id);
336 xran_initialize_ecpri_del_meas_port(eowdc, eowdp,1);
338 ret_value = 1; // Wait for the next pass through the loop to go to the next port
342 // Disable the measurements
343 eowdc->owdm_enable = 0;
349 // Continue running on the same port
351 // xran_initialize_ecpri_del_meas_port(eowdc, eowdp,0); //Now this logic is driven by the receiver
356 errx(1, "Exit 1 epur with cfg null");
363 * @brief ecpri 2.0 one-way delay measurement transmitter control
365 * @ingroup group_source_xran
370 * Pointer to an xran_device_ctx (cast)
374 * FAIL if failed to process the packet
377 int xran_ecpri_one_way_delay_measurement_transmitter(uint16_t port_id, void* handle)
379 // The ecpri one way delay measurement transmitter handles the transmission
380 // of the owd measurement packets on each of the vfs present in the system in a sequential order
381 // so the owd_meas_method is provided from the configuration file and it can be one of 4 possible
382 // methods: REQUEST, REM_REQ, REQ_WFUP or REM_REQ_WFUP
383 // In the current implementation the measurement is performed on one vf until completion of the number
384 // of measurements defined from the configuration file.
385 // A variable in the xran_ecpri_del_meas_cmn keeps track of the current vf that is using the transmitter and
386 // when the current vf completes all the measurements it moves to the next vf until all of the vfs complete
388 // In the current implementation the measurements start after the xran_if_current_state has reached the
389 // XRAN_RUNNING state (i.e. after having executed the xran_start())
390 // The measurements run only once for the current release.
391 int ret_value = FAIL;
392 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
393 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
394 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
396 if (powdc->measState == OWDMTX_INIT)
398 // Perform the initialization for the very first call to the transmitter for a given port
399 powdc->measVf = port_id;
400 powdc->measState = OWDMTX_ACTIVE;
401 // Check whether PL length was passed in config file and if it is within bounds
402 if ((powdc->owdm_PlLength == 0)|| ( powdc->owdm_PlLength < MIN_OWDM_PL_LENGTH ))
404 // Use default length value
405 powdc->owdm_PlLength = MIN_OWDM_PL_LENGTH;
407 else if ( powdc->owdm_PlLength > MAX_OWDM_PL_LENGTH)
409 powdc->owdm_PlLength = MAX_OWDM_PL_LENGTH;
411 #ifdef XRAN_OWD_DEBUG_MEAS_DB
412 printf("Clear call 2 port_id %d\n", port_id);
414 xran_initialize_ecpri_del_meas_port(powdc, powdp,1);
417 // Initiator State Machine , recipient state machine driven from process_delay_meas()
418 // printf("owdm tx w state %d runMeas %d inen %d\n", powdp->msState,powdp->runMeas,powdc->initiator_en);
420 if ((powdp->runMeas != 0 )&&(powdc->initiator_en != 0)) // Current port still running measurements
422 switch (powdp->msState)
424 case XRAN_OWDM_WAITRESP:
425 // Check the measmethod to define the action
426 if (powdc->measMethod == XRAN_REQUEST)
430 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
431 printf("owdm ecpri tx req gen\n");
433 if (xran_generate_delay_meas(port_id, handle, (uint8_t)ECPRI_REQUEST, powdc->measId) == 0 )
435 errx(1, "Exit 1 owdm tx port_id %d measId %d", port_id, powdc->measId);
442 // The only else corresponds to XRAN_REQ_WFUP
445 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
446 printf("owdm ecpri tx req w fup gen\n");
448 if (xran_generate_delay_meas(port_id, handle, (uint8_t)ECPRI_REQUEST_W_FUP , powdc->measId) == 0 )
450 errx(1, "Exit 2 owdm tx port_id %d measId %d", port_id, powdc->measId );
452 powdp->txDone=0; // Needs fup
456 case XRAN_OWDM_WAITREQ:
459 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
460 printf("owdm ecpri tx rem req gen\n");
462 if (xran_generate_delay_meas(port_id, handle, (uint8_t)ECPRI_REMOTE_REQ , powdc->measId) == 0 )
464 errx(1, "Exit 3 owdm tx port_id %d measId %d", port_id, powdc->measId );
469 case XRAN_OWDM_WAITREQWFUP:
472 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
473 printf("owdm ecpri tx rem req w fup gen\n");
475 if (xran_generate_delay_meas(port_id, handle, (uint8_t)ECPRI_REMOTE_REQ_W_FUP , powdc->measId) == 0 )
477 errx(1, "Exit 4 owdm tx port_id %d measId %d", port_id, powdc->measId );
482 case XRAN_OWDM_GENFUP:
485 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
486 printf("owdm ecpri follow up gen\n");
488 if (xran_generate_delay_meas(port_id, handle, (uint8_t)ECPRI_FOLLOW_UP , powdc->measId) == 0 )
490 errx(1, "Exit 4 owdm tx port_id %d measId %d", port_id, powdc->measId );
495 case XRAN_OWDM_WAITFUP:
498 // Transmitter doesn't have to do anything in these states
501 errx(1, "Exit 5 owdm tx port_id %d measId %d id %d state %d", port_id, powdc->measId, p_xran_dev_ctx->fh_init.io_cfg.id, powdp->msState );
511 * @brief Generate a Delay Measurement packet
512 * Transport layer fragmentation is not supported.
514 * @ingroup group_source_xran
519 * Pointer to an xran_device_ctx (cast)
521 * actionType to be used in the owd measurement packet
522 * @param MeasurementID
523 * MeasurementID to be populated in the owd measurement packet
526 * FAIL if failed to process the packet
529 int xran_generate_delay_meas(uint16_t port_id, void* handle, uint8_t actionType, uint8_t MeasurementID )
531 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
532 struct xran_ecpri_delay_meas_pkt *ecpri_delmeas_pkt;
534 struct rte_mbuf *mbuf,*pkt;
536 struct xran_ecpri_delay_meas_pl * pdm= NULL;
537 uint64_t tcv1,tr2m,trm;
538 struct timespec tr2, tr;
539 struct xran_io_cfg* cfg = &p_xran_dev_ctx->fh_init.io_cfg;
540 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
541 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
542 int32_t *port = &cfg->port[port_id];
543 int ret_value = FAIL;
544 struct rte_ether_addr addr;
545 uint16_t ethertype = ETHER_TYPE_ECPRI;
547 // printf("in xran_generate_delay_meas for action_type %d\n", actionType);
549 pkt_len = sizeof(struct xran_ecpri_del_meas_pkt);
550 // Allocate a buffer from the pool
551 mbuf =xran_ethdi_mbuf_alloc();
555 errx(1,"exit 1 owdm gen");
557 pChar = rte_pktmbuf_append(mbuf, pkt_len);
561 errx(1,"exit 2 owdm gen");
563 pChar = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
567 errx(1,"exit 3 owdm gen");
570 struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
572 struct rte_ether_hdr *h = (struct rte_ether_hdr *)rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
573 PANIC_ON(h == NULL, "mbuf prepend of ether_hdr failed");
575 /* Fill in the ethernet header. */
576 rte_eth_macaddr_get(port_id, &h->s_addr); /* set source addr */
578 if (p_xran_dev_ctx->fh_init.io_cfg.id)
580 // rte_ether_addr_copy( (struct rte_ether_addr *)p_xran_dev_ctx->fh_init.p_o_du_addr[port_id],&h->d_addr);
581 h->d_addr = ctx->entities[port_id][ID_O_DU]; /* set dst addr */
585 h->d_addr = ctx->entities[port_id][ID_O_RU]; /* set dst addr */
586 // rte_ether_addr_copy( (struct rte_ether_addr *)p_xran_dev_ctx->fh_init.p_o_ru_addr[port_id],&h->d_addr);
589 h->ether_type = rte_cpu_to_be_16(ethertype); /* ethertype too */
590 mbuf->port = ctx->io_cfg.port[port_id];
593 // Prepare the ecpri header info
594 // Advance pointer to the begining of the ecpri common header
595 pChar = pChar + sizeof (struct rte_ether_hdr);
596 xran_build_owd_meas_ecpri_hdr(pChar, powdc );
597 // Advance pointer to the begining of the xran_ecpri_delay_meas_pl
598 pChar = pChar + sizeof (union xran_ecpri_cmn_hdr);
599 xran_add_at_and_measId_info_to_header(pChar, actionType, MeasurementID);
601 pdm = (struct xran_ecpri_delay_meas_pl *)rte_pktmbuf_mtod_offset(mbuf, struct xran_ecpri_delay_meas_pl *, sizeof(struct rte_ether_hdr) + sizeof(union xran_ecpri_cmn_hdr));
604 // For owd meas originator there are a subset of actionTypes used see ecpri 2.0 Figures 25 and 26 for the details
606 // Record t1, prepare Request Message and determine tcv1 and include both time stamps in the packet
607 // 1) Record the current timestamp when the preparation of the message started i.e. t1
608 if (clock_gettime(CLOCK_REALTIME, &tr )) // t1
612 trm = xran_timespec_to_ns(&tr);
613 #ifdef XRAN_OWD_DEBUG_TIME_STAMPS_INFO
614 printf("trm at gen is %8"PRIx64" \n", trm);
616 // 2) Prepare the delay measurement request packet
617 pdm->ActionType = ECPRI_REQUEST;
618 // 3) Record the current timestamp at the moment that the delay measurement packet is ready to be transmitted tr2 i.e.t1+tcv1 and write it
619 // to the Delay Measurement request packet PL field
620 if (clock_gettime(CLOCK_REALTIME, &tr2 )) // ts
624 // 4) Convert host to ptp time stamp format for tr and write to the outgoing packet
625 xran_host_to_ptp_ts(&pdm->ts, &tr);
626 // 5) Convert from Timestamp tr2 to ns before computing the compensation value
627 tr2m = xran_timespec_to_ns(&tr2);
628 // 6) Compute tcv1 as tr2m-trm
630 #ifdef XRAN_OWD_DEBUG_TIME_STAMPS_INFO
631 printf("tcv1 is %08"PRIx64"\n",tcv1);
634 // 7) write tcv1 to the CompensationValue field of the delay measurement request packet
635 pdm->CompensationValue = rte_cpu_to_be_64(tcv1);
636 #ifdef XRAN_OWD_DEBUG_TIME_STAMPS_INFO
637 printf("compensation value after net order %8"PRIx64" \n", pdm->CompensationValue);
639 // 8) Store t1 and tcv1 to be used later once we get the response message
640 powdp->currentMeasID = pdm->MeasurementID;
643 powdp->msState = XRAN_OWDM_WAITRESP;
644 #ifdef XRAN_OWD_DEBUG_TIME_STAMPS_INFO
645 printf("At req gen t1 %8"PRIx64" and delta %8"PRIx64" port %d \n",powdp->t1,powdp->delta,port_id);
649 case ECPRI_REMOTE_REQ:
650 // Prepare and send Remote Request Message with zero timestamp and correction values
654 // Convert host to ptp time stamp format for tr and write to the outgoing packet
655 xran_host_to_ptp_ts(&pdm->ts, &tr);
656 // write zero to the CompensationValue field of the delay measurement remote request packet
657 pdm->CompensationValue = rte_cpu_to_be_64(tcv1);
658 // 1) Prepare the delay measurement request packet
659 pdm->ActionType = ECPRI_REMOTE_REQ;
660 // 2) Store MeasurementID and msState to be checked once the Request Message is received
661 powdp->currentMeasID = pdm->MeasurementID;
662 powdp->msState = XRAN_OWDM_WAITREQ;
666 case ECPRI_REQUEST_W_FUP:
667 // Record t1, prepare Request with follow up Message and determine tcv1, send zero timestamp and correction value in the packet
668 // 1) Record the current timestamp when the message preparation started i.e. t1
669 if (clock_gettime(CLOCK_REALTIME, &tr )) // t1
673 trm = xran_timespec_to_ns(&tr);
674 // 2) Prepare the delay measurement remote request with follow up packet
675 pdm->ActionType = ECPRI_REQUEST_W_FUP;
676 // 3) Record the current timestamp at the moment that the delay measurement packet is ready to be transmitted tr2 i.e.t1+tcv1
677 if (clock_gettime(CLOCK_REALTIME, &tr2 )) // ts
681 // 4) Convert from Timestamp tr2 to ns before computing the compensation value
682 tr2m = xran_timespec_to_ns(&tr2);
683 // 5) Compute tcv1 as tr2m-trm
685 // Prepare and send Remote Request Message with zero timestamp and correction values
688 powdp->delta = tcv1; // Save tcv1 while waiting for the Response
690 // Convert host to ptp time stamp format for tr and write to the outgoing packet
691 xran_host_to_ptp_ts(&pdm->ts, &tr);
692 // write zero to the CompensationValue field of the delay measurement remote request packet
693 pdm->CompensationValue = rte_cpu_to_be_64(tcv1);
694 // 6) Store MeasurementID and msState to be checked once the Request Message is received
695 powdp->currentMeasID = pdm->MeasurementID;
697 powdp->msState = XRAN_OWDM_GENFUP;
701 case ECPRI_FOLLOW_UP:
702 // Use the t1 and tcv1 values recorded in the ECPRI_REQUEST_W_FUP packet generation step and send these values in the follow up packet
703 // 1) Prepare the delay measurement follow up packet
704 pdm->ActionType = ECPRI_FOLLOW_UP;
705 // 2) Convert t1 from host to ptp format
706 xran_ns_to_timespec(powdp->t1, &tr);
707 // 3) Convert host to ptp time stamp format for tr and write to the outgoing packet
708 xran_host_to_ptp_ts(&pdm->ts, &tr);
709 // 4) write tcv1 to the CompensationValue field of the delay measurement request packet
710 pdm->CompensationValue = rte_cpu_to_be_64(powdp->delta);
711 powdp->currentMeasID = pdm->MeasurementID;
712 powdp->msState = XRAN_OWDM_WAITRESP;
715 case ECPRI_REMOTE_REQ_W_FUP:
716 // Prepare the Remote Request with follow up Message, send zero timestamp and correction value in the packet
720 // Convert host to ptp time stamp format for tr and write to the outgoing packet
721 xran_host_to_ptp_ts(&pdm->ts, &tr);
722 // write zero to the CompensationValue field of the delay measurement remote request packet
723 pdm->CompensationValue = rte_cpu_to_be_64(tcv1);
724 // 1) Prepare the delay measurement request packet
725 pdm->ActionType = ECPRI_REMOTE_REQ_W_FUP;
726 // 2) Store MeasurementID and msState to be checked once the Request Message is received
727 powdp->currentMeasID = pdm->MeasurementID;
728 powdp->msState = XRAN_OWDM_WAITREQWFUP;
733 errx(1,"exit 4 owdm gen");
737 // printf("xran_gen_del_4n");
739 // Retrieve Ethernet Header for the port and copy to the packet
740 rte_eth_macaddr_get(port_id, &addr);
741 #ifdef XRAN_OWD_DEBUG_PKTS
742 printf("id is %d\n", p_xran_dev_ctx->fh_init.io_cfg.id);
743 printf("Port %u SRC MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
744 " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
746 addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
747 addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
750 if (p_xran_dev_ctx->fh_init.io_cfg.id)
752 #ifdef XRAN_OWD_DEBUG_PKTS
753 int8_t *pa = &p_xran_dev_ctx->fh_init.p_o_du_addr[0];
754 printf("DST_MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]);
756 rte_ether_addr_copy((struct rte_ether_addr *)&p_xran_dev_ctx->fh_init.p_o_du_addr[0], (struct rte_ether_addr *)&h->d_addr.addr_bytes[0]);
761 #ifdef XRAN_OWD_DEBUG_PKTS
762 int8_t *pb = &p_xran_dev_ctx->fh_init.p_o_ru_addr[0];
763 printf("DST_MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pb[0],pb[1],pb[2],pb[3],pb[4],pb[5]);
765 rte_ether_addr_copy((struct rte_ether_addr *)&p_xran_dev_ctx->fh_init.p_o_ru_addr[0], (struct rte_ether_addr *)&h->d_addr.addr_bytes[0]);
768 #ifdef XRAN_OWD_DEBUG_PKTS
769 uint8_t *pc = &h->s_addr.addr_bytes[0];
770 printf(" Src MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pc[0],pc[1],pc[2],pc[3],pc[4],pc[5]);
771 uint8_t *pd = &h->d_addr.addr_bytes[0];
772 printf(" Dst MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pd[0],pd[1],pd[2],pd[3],pd[4],pd[5]);
774 // Copy dest address from above
775 // Send out the packet
776 ret_value = rte_eth_tx_burst((uint16_t)*port, 0, &mbuf, 1);
777 // Try using the normal scheme of passing through the ring
778 // ret_value = xran_enqueue_mbuf(mbuf, ctx->tx_ring[port_id]);
779 #ifdef XRAN_OWD_DEBUG_PKTS
780 printf("owdt rte_eth_tx_burst returns %d for port %d\n", ret_value,port_id);
787 * @brief Process a Delay Measurement Request packet
789 * @ingroup group_source_xran
792 * The pointer of the packet buffer to be processed
794 * Pointer to an xran_device_ctx (cast)
795 * @param xran_ecpri_delay_meas_pl
796 * Pointer to an eCPRI delay measurement PL
799 * FAIL if failed to process the packet
801 int xran_process_delmeas_request(struct rte_mbuf *pkt, void* handle, struct xran_ecpri_del_meas_pkt* ptr, uint16_t port_id)
803 int ret_value = FAIL;
805 struct xran_ecpri_delay_meas_pl *txDelayHdr;
807 struct rte_mbuf* pkt1;
809 uint64_t tcv1, tcv2,t2m,trm, td12, t1m;
810 struct xran_ecpri_del_meas_pkt *pdm= NULL;
811 union xran_ecpri_cmn_hdr *cmn;
812 struct timespec tr, t2;
813 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
814 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
815 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
816 struct rte_ether_hdr *eth_hdr;
817 struct rte_ether_addr addr;
818 struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
820 struct xran_io_cfg* cfg = &p_xran_dev_ctx->fh_init.io_cfg;
821 // struct xran_io_cfg *cfg = &ctx->io_cfg;
822 int32_t *port = &cfg->port[port_id];
824 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
825 printf("RX ecpri Measure Request \n");
827 // Since we are processing the receipt of a delay measurement request packet the following actions
828 // need to be taken (Per eCPRI V2.0 Figure 25)
829 // 1) Record the current timestamp when the message was received i.e. tr
830 if (clock_gettime(CLOCK_REALTIME, &tr )) // tr
832 errx(1, "Exit 1 owd rx f1 port_id %d", port_id);
836 trm = xran_timespec_to_ns(&tr);
837 // 2) Copy MeasurementID to the Delay Measurement Response packet
838 // but first prepend ethernet header since the info is still in the buffer
839 // pchar = rte_pktmbuf_prepend(pkt, (uint16_t)(sizeof(struct rte_ether_hdr)+ sizeof(union xran_ecpri_cmn_hdr ))); // Pointer to new data start address 10/20/20 Now not removing ecpri_cmn in process_delay_meas
840 pchar = rte_pktmbuf_prepend(pkt, (uint16_t)sizeof(struct rte_ether_hdr));
841 pkt1 = rte_pktmbuf_copy(pkt, _eth_mbuf_pool, 0, UINT32_MAX);
842 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt*, sizeof(struct rte_ether_hdr));
843 // 3) Get time stamp T1 from the Timestamp field i.e. t1
844 pt1 = pdm->deMeasPl.ts;
845 // 3a) Convert to ns in the host format
846 t1m = xran_ptp_ts_to_ns(&pt1);
847 // 4) Get the compensation value from the packet i.e. tcv1
848 tcv1 = rte_be_to_cpu_64(pdm->deMeasPl.CompensationValue);
849 // 5) Prepare the delay measurement response packet
850 pdm->deMeasPl.ActionType = ECPRI_RESPONSE;
851 // 6) Record the current timestamp at the moment that the delay measurement packet is ready to be transmitted i.e.t2 and write it
852 // to the Delay Measurement response packet PL field
853 if (clock_gettime(CLOCK_REALTIME, &t2 )) // t2
855 errx(1,"Exit 2 owd rx f1 port_id %d", port_id);
858 // 7) Convert host to ptp time stamp format for t2 and write to the outgoing packet
859 xran_host_to_ptp_ts(&pdm->deMeasPl.ts, &t2);
860 // 8) Convert from Timestamp t2 to ns before computing the compensation value
861 t2m = xran_timespec_to_ns(&t2);
862 // 9) Compute tcv2 as t2-tr
864 // 10) write cv2 to the CompensationValue field of the delay measurement response packet
865 pdm->deMeasPl.CompensationValue = rte_cpu_to_be_64(tcv2);
866 // 11) Fill the ethernet header properly by swapping src and dest addressed from the copied frame
867 eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *);
868 /* Swap dest and src mac addresses. */
869 rte_ether_addr_copy(ð_hdr->d_addr, &addr);
870 rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr);
871 rte_ether_addr_copy(&addr, ð_hdr->s_addr);
872 // Still need to check ol_flags state and update if necessary
873 // Compute the delay td12 and save
874 // Still need to define the DB to save the info and run averages
875 td12 = t2m - tcv2 - (t1m + tcv1);
876 // 12) Send the response right away
877 struct rte_ether_hdr *h = (struct rte_ether_hdr *)rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr*);
878 #ifdef XRAN_OWD_DEBUG_PKTS
879 uint8_t *pc = &h->s_addr.addr_bytes[0];
880 printf(" Src MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pc[0],pc[1],pc[2],pc[3],pc[4],pc[5]);
881 uint8_t *pd = &h->d_addr.addr_bytes[0];
882 printf(" Dst MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pd[0],pd[1],pd[2],pd[3],pd[4],pd[5]);
883 // printf("EtherType: %04"PRIx16" \n",&h->ether_type);
885 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt *, sizeof(struct rte_ether_hdr) );
886 pdm->cmnhdr.bits.ecpri_payl_size = 10 + powdc->owdm_PlLength; // 10 correponds to the xran_ecpri_delay_meas_pl minus the dummy_bytes field which now allows the user to select the length for this field to be sent
887 pdm->cmnhdr.bits.ecpri_payl_size = rte_cpu_to_be_16(pdm->cmnhdr.bits.ecpri_payl_size);
888 pdm->cmnhdr.bits.ecpri_mesg_type = ECPRI_DELAY_MEASUREMENT;
889 #ifdef XRAN_OWD_DEBUG_TIME_STAMPS_INFO
890 printf ("pdm has:%02"PRIx8" %04"PRIx16" %02"PRIx8" %02"PRIx8" \n", pdm->cmnhdr.bits.ecpri_mesg_type, pdm->cmnhdr.bits.ecpri_payl_size, pdm->cmnhdr.bits.ecpri_ver,pdm->deMeasPl.MeasurementID);
893 // Copy dest address from above
894 ret_value = rte_eth_tx_burst((uint16_t)*port, 0, &pkt1, 1); // Need to check for the proper method of getting the port and mac address
895 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
896 printf ("in dly ms req sending response rte_eth_tx_burst returns %d for port %d\n",ret_value, *port);
898 // 13) Update measurements DB and check if completed
899 powdp->delaySamples[powdp->numMeas]= td12 ;
900 #ifdef XRAN_OWD_DEBUG_DELAY_INFO
901 printf("Computed delay is %08"PRIx64" MeasNum %d portId %d id is %d \n",powdp->delaySamples[powdp->numMeas],powdp->numMeas, port_id, p_xran_dev_ctx->fh_init.io_cfg.id);
906 if (powdp->numMeas == powdc->numberOfSamples)
908 xran_compute_and_report_delay_estimate(powdp, powdc->numberOfSamples, p_xran_dev_ctx->fh_init.io_cfg.id);
909 powdp->msState = XRAN_OWDM_DONE;
910 xran_if_current_state = XRAN_RUNNING;
915 // powdp->msState = XRAN_OWDM_IDLE;
916 if (powdc->initiator_en)
918 // Reinitialize txDone for next pass
920 #ifdef XRAN_OWD_DEBUG_MEAS_DB
921 printf("Clear call 3 port id %d \n", port_id);
923 xran_initialize_ecpri_del_meas_port(powdc, powdp,0);
930 int xran_process_delmeas_request_w_fup(struct rte_mbuf *pkt, void* handle, struct xran_ecpri_del_meas_pkt* ptr, uint16_t port_id)
932 int ret_value = FAIL;
933 struct xran_ecpri_delay_meas_pl* txDelayHdr;
935 struct rte_mbuf* pkt1;
937 struct xran_ecpri_del_meas_pkt* pdm= ptr;
939 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
940 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
941 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
942 struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
943 struct xran_io_cfg *cfg = &ctx->io_cfg;
944 int32_t* port = &cfg->port[port_id];
946 // Since we are processing the receipt of a delay measurement request with follow up packet the following actions
947 // need to be taken (Per eCPRI V2.0 Figure 26)
948 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
949 printf("RX ecpri Measure Request with fup\n");
952 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod(pkt, struct xran_ecpri_del_meas_pkt*);
953 // Record tr and save to memory with the associated measurement Id and Port
954 // 1) Record the current timestamp when the message was received i.e. tr
955 if (clock_gettime(CLOCK_REALTIME, &tr )) // tr
957 errx(1, "Exit 1 owd rx f2 port_id %d",port_id);
960 trm = xran_timespec_to_ns(&tr);
961 // Save trm so when the Follow Up packet is received we can compute tcv2 as t2-trm
963 // Save the measurement Id
964 powdp->currentMeasID = pdm->deMeasPl.MeasurementID;
965 // Change the state to waiting for follow up
966 powdp->msState = XRAN_OWDM_WAITFUP;
972 int xran_process_delmeas_response(struct rte_mbuf *pkt, void* handle, struct xran_ecpri_del_meas_pkt* ptr, uint16_t port_id)
975 struct xran_ecpri_delay_meas_pl* txDelayHdr;
977 struct rte_mbuf* pkt1;
978 uint64_t tcv1, tcv2,t2m,trm, td12;
979 struct xran_ecpri_del_meas_pkt* pdm;
980 struct timespec tr, t2;
981 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
982 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
983 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
984 struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
985 struct xran_io_cfg *cfg = &ctx->io_cfg;
986 struct xran_io_cfg* cfg1 = &p_xran_dev_ctx->fh_init.io_cfg;
987 int32_t* port = &cfg->port[port_id];
990 // Since we are processing the receipt of a delay measurement response packet the following actions
991 // need to be taken (Per eCPRI V2.0 Figure 25)
992 // Need to know if a Remote Request was processed against this measurement ID if so then the receipt of the response
993 // is used to compute the one-way delay as td= (t2-tcv2) - (t1+tcv1) with t2, tcv2 contained in the packet and
994 // t1 and tcv1 stored from the previous Remote Request packet processing task
995 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
996 printf("RX ecpri Measure Response \n");
999 pdm = (struct xran_ecpri_del_meas_pkt*)(struct xran_ecpri_del_meas_pkt *)rte_pktmbuf_mtod(pkt, struct xran_ecpri_del_meas_pkt *);
1000 // Save the measurement Id
1001 powdp->currentMeasID = pdm->deMeasPl.MeasurementID;
1003 // 1) Get time stamp T2 from the Timestamp field i.e. t2
1004 pt2 = pdm->deMeasPl.ts;
1006 // 2a) Convert to ns in the host format
1007 t2m = xran_ptp_ts_to_ns(&pt2);
1008 // 3) Get the compensation value from the packet i.e. tcv2
1009 tcv2 = rte_be_to_cpu_64(pdm->deMeasPl.CompensationValue);
1010 #ifdef XRAN_OWD_DEBUG_TIME_STAMPS_INFO
1011 printf ("tcv2 at Gen is %08"PRIx64" \n",tcv2);
1013 // Compute the delay using the stored t1 and tcv1 used in the request message
1014 // td= (t2-tcv2) - (t1+tcv1) where t1 and tcv1 have been stored previously for the same measurement ID
1015 #ifdef XRAN_OWD_DEBUG_TIME_STAMPS_INFO
1016 printf("Delay comp at orig has t2m %08"PRIx64" tcv2 %08"PRIx64" t1 %08"PRIx64" delta %08"PRIx64" port_id %d \n", t2m,tcv2,powdp->t1 ,powdp->delta,port_id);
1018 powdp->delaySamples[powdp->numMeas]= (t2m-tcv2) -(powdp->t1 + powdp->delta);
1019 #ifdef XRAN_OWD_DEBUG_DELAY_INFO
1020 printf("Computed delay is %08"PRIx64" MeasNum %d portId %d id is %d \n",powdp->delaySamples[powdp->numMeas],powdp->numMeas, port_id,p_xran_dev_ctx->fh_init.io_cfg.id );
1027 if (powdp->numMeas == powdc->numberOfSamples)
1029 xran_compute_and_report_delay_estimate(powdp, powdc->numberOfSamples,p_xran_dev_ctx->fh_init.io_cfg.id);
1030 powdp->msState = XRAN_OWDM_DONE;
1031 xran_if_current_state= XRAN_RUNNING;
1036 // powdp->msState = XRAN_OWDM_IDLE;
1037 if (powdc->initiator_en)
1039 // Reinitialize txDone for next pass
1041 #ifdef XRAN_OWD_DEBUG_MEAS_DB
1042 printf("Clear call_4 port_id %d \n", port_id);
1044 xran_initialize_ecpri_del_meas_port(powdc, powdp,0);
1045 #ifdef XRAN_OWD_DEBUG_MEAS_DB
1046 printf("Reseting done \n");
1052 // Needs work and change ret_value to OK
1056 int xran_process_delmeas_rem_request(struct rte_mbuf *pkt, void* handle, struct xran_ecpri_del_meas_pkt* ptr, uint16_t port_id)
1058 int ret_value = FAIL;
1059 struct xran_ecpri_delay_meas_pl* txDelayHdr;
1060 struct rte_mbuf* pkt1;
1061 uint64_t tcv1,tr2m,trm;
1062 struct xran_ecpri_del_meas_pkt* pdm;
1064 struct timespec tr2, tr;
1065 struct rte_ether_hdr *eth_hdr;
1066 struct rte_ether_addr addr;
1067 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
1068 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
1069 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
1070 struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
1071 struct xran_io_cfg *cfg = &ctx->io_cfg;
1072 int32_t* port = &cfg->port[port_id];
1074 // Since we are processing the receipt of a delay measurement remote request packet the following actions
1075 // need to be taken (Per eCPRI V2.0 Figure 25)
1076 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
1077 printf("RX ecpri Measure Remote Request \n");
1080 // 1) Record the current timestamp when the message was received i.e. t1
1081 if (clock_gettime(CLOCK_REALTIME, &tr )) // t1
1083 errx(1,"Exit 1 owd rx f4 port_id %d", port_id);
1086 trm = xran_timespec_to_ns(&tr);
1087 // 2) Copy MeasurementID to the Delay Measurement Request packet
1088 // but first prepend ethernet header since the info is still in the buffer
1089 pchar = rte_pktmbuf_prepend(pkt, (uint16_t)sizeof(struct rte_ether_hdr));
1090 pkt1 = rte_pktmbuf_copy(pkt, _eth_mbuf_pool, 0, UINT32_MAX);
1091 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt*, sizeof(struct rte_ether_hdr));
1093 // 3) Prepare the delay measurement request packet
1094 pdm->deMeasPl.ActionType = ECPRI_REQUEST;
1095 // 4) Record the current timestamp at the moment that the delay measurement packet is ready to be transmitted tr2 i.e.t1+tcv1 and write it
1096 // to the Delay Measurement request packet PL field
1097 if (clock_gettime(CLOCK_REALTIME, &tr2 )) // tr2
1099 errx(1,"Exit 2 owd rx f4 port_id %d", port_id);
1102 // 5) Convert host to ptp time stamp format for tr2 and write to the outgoing packet
1103 xran_host_to_ptp_ts(&pdm->deMeasPl.ts, &tr);
1104 // 6) Convert from Timestamp tr2 to ns before computing the compensation value
1105 tr2m = xran_timespec_to_ns(&tr2);
1106 // 7) Compute tcv1 as tr2m-trm
1108 // 8) write tcv1 to the CompensationValue field of the delay measurement request packet
1109 pdm->deMeasPl.CompensationValue = rte_cpu_to_be_64(tcv1);
1110 // 9) Fill the ethernet header properly by swapping src and dest addressed from the copied frame
1111 eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *);
1112 /* Swap dest and src mac addresses. */
1113 rte_ether_addr_copy(ð_hdr->d_addr, &addr);
1114 rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr);
1115 rte_ether_addr_copy(&addr, ð_hdr->s_addr);
1116 // 10) Send the response right away
1117 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt *, sizeof(struct rte_ether_hdr) );
1118 pdm->cmnhdr.bits.ecpri_payl_size = 10 + powdc->owdm_PlLength; // 10 correponds to the xran_ecpri_delay_meas_pl minus the dummy_bytes field which now allows the user to select the length for this field to be sent
1119 pdm->cmnhdr.bits.ecpri_payl_size = rte_cpu_to_be_16(pdm->cmnhdr.bits.ecpri_payl_size);
1120 pdm->cmnhdr.bits.ecpri_mesg_type = ECPRI_DELAY_MEASUREMENT;
1121 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
1122 printf("Ecpri Measure Sending Request Msg \n");
1124 ret_value = rte_eth_tx_burst((uint16_t)*port, 0, &pkt1, 1); // Need to check for the proper method of getting the port and mac address
1125 // Still need to check ol_flags state and update if necessary
1126 // Save the computed delays and the measurementId
1128 powdp->delta = tcv1;
1129 powdp->currentMeasID = pdm->deMeasPl.MeasurementID;
1130 powdp->msState = XRAN_OWDM_WAITRESP;
1135 int xran_process_delmeas_rem_request_w_fup(struct rte_mbuf* pkt, void* handle, struct xran_ecpri_del_meas_pkt* ptr, uint16_t port_id)
1137 int ret_value = FAIL;
1138 struct xran_ecpri_delay_meas_pl* txDelayHdr;
1140 struct rte_mbuf* pkt1;
1141 struct rte_mbuf* pkt2;
1142 uint64_t tcv1,tsm,t1;
1143 struct rte_ether_hdr *eth_hdr;
1144 struct rte_ether_addr addr;
1145 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
1146 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
1147 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
1148 struct xran_ecpri_del_meas_pkt* pdm;
1149 struct timespec tr, ts;
1153 struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
1154 struct xran_io_cfg *cfg = &ctx->io_cfg;
1155 int32_t* port = &cfg->port[port_id];
1158 // Since we are processing the receipt of a delay measurement remote request with follow up packet the following
1159 // actions need to be taken (Per eCPRI V2.0 Figure 26)
1160 // record t1 for the packet arrival time and then prepare Request with follow up packet which uses 0 for timsetamp
1161 // and for correctionvalue.
1162 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
1163 printf("RX ecpri Measure Remote Request w Fup \n");
1165 // 1) Record the current timestamp when the message was received i.e. t1
1166 if (clock_gettime(CLOCK_REALTIME, &tr )) // t1
1168 errx(1,"Exit 1 owd rx f5 port_id %d", port_id);
1171 t1 = xran_timespec_to_ns(&tr);
1172 // 2) Copy MeasurementID to the Delay Measurement Request packet
1173 // but first prepend ethernet header since the info is still in the buffer
1174 pchar = rte_pktmbuf_prepend(pkt, (uint16_t)sizeof(struct rte_ether_hdr));
1175 pkt1 = rte_pktmbuf_copy(pkt, _eth_mbuf_pool, 0, UINT32_MAX);
1177 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt*, sizeof(struct rte_ether_hdr));
1180 // 3) Prepare the delay measurement request w fup packet
1181 pdm->deMeasPl.ActionType = ECPRI_REQUEST_W_FUP;
1182 // 4) Zero the ts and CompensationValue entries in the packet
1185 // 5) Convert host to ptp time stamp format for t2 and write to the outgoing packet
1186 xran_host_to_ptp_ts(&pdm->deMeasPl.ts, &ts);
1187 // 6) write zero to the CompensationValue field of the delay measurement response packet
1188 pdm->deMeasPl.CompensationValue = rte_cpu_to_be_64(tsm);
1189 // 7) Fill the ethernet header properly by swapping src and dest addressed from the copied frame
1190 eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *);
1191 /* Swap dest and src mac addresses. */
1192 rte_ether_addr_copy(ð_hdr->d_addr, &addr);
1193 rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr);
1194 rte_ether_addr_copy(&addr, ð_hdr->s_addr);
1195 // 8) Duplicate packet to be used for the follow up packet
1196 pkt2 = rte_pktmbuf_copy(pkt1, _eth_mbuf_pool, 0, UINT32_MAX);
1197 // 9) Record the current timestamp when the request with follow up is being sent
1198 if (clock_gettime(CLOCK_REALTIME, &ts )) // ts
1200 errx(1,"Exit 2 owd rx f5 port_id %d", port_id);
1203 // 10) Send the request with follow up
1204 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
1205 printf("ecpri Measure sending Request with Fup \n");
1207 ret_value = rte_eth_tx_burst((uint16_t)*port, 0, &pkt1, 1); // Need to check for the proper method of getting the port and mac address
1209 // After the Request with follow up packet has been sent, prepare follow up packet with t1 and tcv1, where
1210 // tcv1 = ts - t1 and writing it to the outgoing packet
1211 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt2, struct xran_ecpri_del_meas_pkt*, sizeof(struct rte_ether_hdr));
1212 // 11) Prepare the delay measurement request with follow up packet
1213 pdm->deMeasPl.ActionType = ECPRI_FOLLOW_UP;
1214 // 12) Convert host to ptp time stamp format for t1 and write to the outgoing packet
1215 xran_host_to_ptp_ts(&pdm->deMeasPl.ts, &tr);
1216 // 13) Convert from Timestamp t2 to ns before computing the compensation value
1217 tsm = xran_timespec_to_ns(&ts);
1218 // 14) Compute tcv1 as tsm-t1
1220 // 15) write cv1 to the CompensationValue field of the delay measurement response packet
1221 pdm->deMeasPl.CompensationValue = rte_cpu_to_be_64(tcv1);
1223 // 16) Send the follow up message
1224 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
1225 printf("ecpri Measure sending Follow Up \n");
1227 ret_value = rte_eth_tx_burst((uint16_t)*port, 0, &pkt2, 1); // Need to check for the proper method of getting the port and mac address
1229 // Save trm since it will be used to compute tcv2 based on the arrival of the Follow Up packet
1230 powdp->currentMeasID = pdm->deMeasPl.MeasurementID;
1232 powdp->delta = tcv1;
1233 powdp->msState = XRAN_OWDM_WAITRESP;
1239 int xran_process_delmeas_follow_up(struct rte_mbuf *pkt, void* handle, struct xran_ecpri_del_meas_pkt* ptr, uint16_t port_id)
1241 int ret_value = FAIL;
1242 struct xran_ecpri_delay_meas_pl *txDelayHdr;
1243 struct rte_mbuf *pkt1;
1245 uint64_t tcv1,tr2m, tcv2, t1;
1246 struct xran_ecpri_del_meas_pkt *pdm;
1247 struct timespec tr2, tr;
1248 struct rte_ether_hdr *eth_hdr;
1249 struct rte_ether_addr addr;
1251 struct xran_device_ctx* p_xran_dev_ctx = (struct xran_device_ctx *)handle;
1252 struct xran_ecpri_del_meas_cmn* powdc = &p_xran_dev_ctx->fh_init.io_cfg.eowd_cmn[p_xran_dev_ctx->fh_init.io_cfg.id];
1253 struct xran_ecpri_del_meas_port* powdp = &p_xran_dev_ctx->fh_init.io_cfg.eowd_port[p_xran_dev_ctx->fh_init.io_cfg.id][port_id];
1254 struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
1255 struct xran_io_cfg *cfg = &ctx->io_cfg;
1256 int32_t *port = &cfg->port[0];
1257 // Since we are processing the receipt of a delay measurement follow up packet the following actions
1258 // need to be taken (Per eCPRI V2.0 Figure 26)
1259 #ifdef XRAN_OWD_DEBUG_MSG_FLOW
1260 printf("ecpri Measure received Followup \n");
1263 // 1) Record the current timestamp when the message was received i.e. tr2
1264 if (clock_gettime(CLOCK_REALTIME, &tr2 )) // tr2
1266 errx(1,"Exit 1 owd rx f6 port_id %d", port_id);
1269 tr2m = xran_timespec_to_ns(&tr2);
1272 // 2) Copy MeasurementID to the Delay Measurement Response packet
1273 // but first prepend ethernet header since the info is still in the buffer
1274 pChar = rte_pktmbuf_prepend(pkt, (uint16_t)sizeof(struct rte_ether_hdr));
1275 pkt1 = rte_pktmbuf_copy(pkt, _eth_mbuf_pool, 0, UINT32_MAX);
1276 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt*, sizeof(struct rte_ether_hdr));
1278 // 3) Get time stamp T1 from the Timestamp field i.e. t1
1279 pt1 = pdm->deMeasPl.ts;
1280 // 4) Convert to ns in the host format
1281 t1 = xran_ptp_ts_to_ns(&pt1);
1282 // 5) Get the compensation value from the packet i.e. tcv1
1283 tcv1 = rte_be_to_cpu_64(pdm->deMeasPl.CompensationValue);
1285 // 6) Prepare the delay measurement response packet
1286 pdm->deMeasPl.ActionType = ECPRI_RESPONSE;
1288 // 7) Convert host to ptp time stamp format for tr2 and write to the outgoing packet
1289 xran_host_to_ptp_ts(&pdm->deMeasPl.ts, &tr2);
1290 // 8) Convert from Timestamp tr2 to ns before computing the compensation value
1291 tr2m = xran_timespec_to_ns(&tr2);
1292 // 9) Compute tcv2 as tr2m-trm
1293 tcv2 = tr2m - powdp->tr;
1294 // 0) write tcv2 to the CompensationValue field of the delay measurement request packet
1295 pdm->deMeasPl.CompensationValue = rte_cpu_to_be_64(tcv2);
1296 // 9) Fill the ethernet header properly by swapping src and dest addressed from the copied frame
1297 eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *);
1298 /* Swap dest and src mac addresses. */
1299 rte_ether_addr_copy(ð_hdr->d_addr, &addr);
1300 rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr);
1301 rte_ether_addr_copy(&addr, ð_hdr->s_addr);
1302 pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt *, sizeof(struct rte_ether_hdr) );
1303 pdm->cmnhdr.bits.ecpri_payl_size = 10 + powdc->owdm_PlLength; // 10 correponds to the xran_ecpri_delay_meas_pl minus the dummy_bytes field which now allows the user to select the length for this field to be sent
1304 pdm->cmnhdr.bits.ecpri_payl_size = rte_cpu_to_be_16(pdm->cmnhdr.bits.ecpri_payl_size);
1305 pdm->cmnhdr.bits.ecpri_mesg_type = ECPRI_DELAY_MEASUREMENT;
1307 // 10) Send the response right away
1308 ret_value = rte_eth_tx_burst((uint16_t)*port, 0, &pkt1, 1); // Need to check for the proper method of getting the port and mac address
1310 // Compute the delay using the stored t1 and tcv1 used in the request message
1311 // td= (t2-tcv2) - (t1+tcv1) where t1 and tcv1 have been stored previously for the same measurement ID
1312 powdp->delaySamples[powdp->numMeas]= (tr2m-tcv2) -(t1 + tcv1);
1313 #ifdef XRAN_OWD_DEBUG_DELAY_INFO
1314 printf("Computed delay is %08"PRIx64" MeasNum %d portId %d id %d \n",powdp->delaySamples[powdp->numMeas],powdp->numMeas,port_id,p_xran_dev_ctx->fh_init.io_cfg.id);
1318 if (powdp->numMeas == powdc->numberOfSamples)
1320 xran_compute_and_report_delay_estimate(powdp, powdc->numberOfSamples, p_xran_dev_ctx->fh_init.io_cfg.id);
1321 powdp->msState = XRAN_OWDM_DONE;
1322 xran_if_current_state = XRAN_RUNNING;
1327 // powdp->msState = XRAN_OWDM_IDLE;
1328 if (powdc->initiator_en)
1330 // Reinitialize txDone for next pass
1332 #ifdef XRAN_OWD_DEBUG_MEAS_DB
1333 printf("Clear Call_5 port_id %d \n", port_id);
1335 xran_initialize_ecpri_del_meas_port(powdc, powdp,0);
1345 * @brief Parse a Delay Measurement packet
1346 * Transport layer fragmentation is not supported.
1348 * @ingroup group_source_xran
1351 * The pointer of the packet buffer to be parsed
1353 * Pointer to an xran_device_ctx (cast)
1356 * FAIL if failed to process the packet
1358 int process_delay_meas(struct rte_mbuf *pkt, void* handle, uint16_t port_id)
1360 struct xran_device_ctx * p_xran_dev_ctx = (struct xran_device_ctx *)handle;
1361 struct xran_ecpri_del_meas_pkt *ecpri_delmeas_pkt;
1362 union xran_ecpri_cmn_hdr * ecpricmn;
1363 int ret_value = FAIL;
1364 #ifdef XRAN_OWD_DEBUG_PKTS
1365 printf("pdm Device is %d\n", p_xran_dev_ctx->fh_init.io_cfg.id);
1367 /* Process eCPRI cmn header. */
1369 // (void *)rte_pktmbuf_adj(pkt, sizeof(*ecpricmn));
1370 ecpri_delmeas_pkt = (struct xran_ecpri_del_meas_pkt *)rte_pktmbuf_mtod(pkt, struct xran_ecpri_del_meas_pkt *);
1371 // The processing of the delay measurement here corresponds to eCPRI sections 3.2.4.6.2 and 3.42.6.3
1373 switch(ecpri_delmeas_pkt->deMeasPl.ActionType) {
1375 #ifdef ORAN_OWD_DEBUG_MSG_FLOW
1376 printf("Proc rx Dly Meas Req\n");
1378 ret_value = xran_process_delmeas_request(pkt, p_xran_dev_ctx, ecpri_delmeas_pkt, port_id);
1380 case ECPRI_REQUEST_W_FUP:
1381 #ifdef ORAN_OWD_DEBUG_MSG_FLOW
1382 printf("Proc Dly Meas rx Req w Fup\n");
1384 ret_value = xran_process_delmeas_request_w_fup(pkt, p_xran_dev_ctx, ecpri_delmeas_pkt, port_id);
1386 case ECPRI_RESPONSE:
1387 #ifdef ORAN_OWD_DEBUG_MSG_FLOW
1388 printf("Proc Dly Meas rx Resp\n");
1390 ret_value = xran_process_delmeas_response(pkt, p_xran_dev_ctx, ecpri_delmeas_pkt, port_id);
1392 case ECPRI_REMOTE_REQ:
1393 #ifdef ORAN_OWD_DEBUG_MSG_FLOW
1394 printf("Proc Dly Meas rx Rem Req\n");
1396 ret_value = xran_process_delmeas_rem_request(pkt, p_xran_dev_ctx, ecpri_delmeas_pkt, port_id);
1398 case ECPRI_REMOTE_REQ_W_FUP:
1399 #ifdef ORAN_OWD_DEBUG_MSG_FLOW
1400 printf("Proc Dly Meas Rem rx Req w Fup\n");
1402 ret_value = xran_process_delmeas_rem_request_w_fup(pkt, p_xran_dev_ctx, ecpri_delmeas_pkt, port_id);
1404 case ECPRI_FOLLOW_UP:
1405 #ifdef ORAN_OWD_DEBUG_MSG_FLOW
1406 printf("Proc Dly Meas rx Fup\n");
1408 ret_value = xran_process_delmeas_follow_up(pkt, p_xran_dev_ctx, ecpri_delmeas_pkt, port_id);
1411 #ifdef ORAN_OWD_DEBUG_MSG_FLOW
1412 printf("Proc Dly Meas default\n");