Commit d44ccd24 authored by Cedric Roux's avatar Cedric Roux
Browse files

- Update multicast:

	* Remove recv thread
	* Update logs to LOG api
	* Retransmit Initial message if master not ready
	* Assert if packets lost -> break the execution if there is a drift in slots

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4006 818b1a75-f10b-46b9-bf7c-635c3b92a50f
parent b62ae47b
/*! \file phy_emulation.h
* \brief specifies the data structure and variable for phy emulation
* \author Navid Nikaein, Raymomd Knopp and Hicham Anouar
* \date 2011
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
//#include "SCHED/defs.h"
#include "proto.h"
//#include "UTIL/OCG/OCG.h"
* \brief specifies the data structure and variable for phy emulation
* \author Navid Nikaein, Raymomd Knopp and Hicham Anouar
* \date 2011
* \version 1.1
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
#ifndef __BYPASS_SESSION_LAYER_DEFS_H__
# define __BYPASS_SESSION_LAYER_DEFS_H__
//-----------------------------------------------------------------------------
//#include "openair_defs.h"
#define WAIT_PM_TRANSPORT_INFO 0x1
#define WAIT_SM_TRANSPORT_INFO 0x2
#define SYNC_TRANSPORT_INFO 0x3
#define ENB_TRANSPORT_INFO 0X4
#define UE_TRANSPORT_INFO 0X5
#define RELEASE_TRANSPORT_INFO 0x6
typedef enum {
EMU_TRANSPORT_INFO_ERROR = 0x0,
EMU_TRANSPORT_INFO_WAIT_PM,
EMU_TRANSPORT_INFO_WAIT_SM,
EMU_TRANSPORT_INFO_SYNC,
EMU_TRANSPORT_INFO_ENB,
EMU_TRANSPORT_INFO_UE,
EMU_TRANSPORT_INFO_RELEASE
} emu_transport_info_t;
#define WAIT_PM_TRANSPORT 1
#define WAIT_SM_TRANSPORT 2
......@@ -41,10 +38,11 @@
#define BYPASS_RX_BUFFER_SIZE 64000
#define BYPASS_TX_BUFFER_SIZE 64000
typedef unsigned int (*tx_handler_t) (unsigned char, char*, unsigned int*, unsigned int*);
typedef unsigned int (*rx_handler_t) (unsigned char, char*, unsigned int);
/*************************************************************/
typedef struct {
u32 pbch_flag:1;
u32 pss:2;
......@@ -71,8 +69,10 @@ typedef struct {
u8 prach_flag:1; // 0=none,1=active
u8 prach_id:6; // this is the PHY preamble index for the prach
} UE_cntl;
#define MAX_TRANSPORT_BLOCKS_BUFFER_SIZE 16384
#define MAX_NUM_DCI 5
typedef struct {
eNB_cntl cntl;
u8 num_common_dci;
......@@ -85,15 +85,6 @@ typedef struct {
u8 transport_blocks[MAX_TRANSPORT_BLOCKS_BUFFER_SIZE];
} __attribute__ ((__packed__)) eNB_transport_info_t ;
/*typedef struct {
eNB_cntl cntl;
u8 num_common_dci;
u8 num_ue_spec_dci;
DCI_ALLOC_t dci_alloc;
u8 dlsch_info[6*MAX_NUM_DCI + MAX_TRANSPORT_BLOCKS_BUFFER_SIZE];
} eNB_transport_info_rx_t ;
*/
typedef struct {
UE_cntl cntl;
u8 num_eNB;
......@@ -113,54 +104,12 @@ typedef struct bypass_msg_header {
unsigned int nb_ue; /*! \brief */
unsigned int nb_flow; /*! \brief */
unsigned int frame;
unsigned int subframe;
unsigned int subframe;
uint64_t seq_num;
}__attribute__ ((__packed__)) bypass_msg_header_t;
typedef struct bypass_proto2multicast_header_t {
unsigned int size;
} bypass_proto2multicast_header_t;
/* // replaced to OCG.h
#define NUMBER_OF_MASTER_MAX 20
//#define NUMBER_OF_UE_MAX 32
typedef struct {
unsigned char nb_ue;
unsigned char first_ue;
unsigned char nb_enb;
unsigned char first_enb;
}master_info_t;
typedef struct {
master_info_t master[NUMBER_OF_MASTER_MAX];
unsigned char nb_ue_local;
unsigned char nb_ue_remote;
unsigned char nb_enb_local;
unsigned char nb_enb_remote;
unsigned char first_enb_local;
unsigned char first_ue_local;
unsigned short master_id;
unsigned char nb_master;
unsigned int master_list;
unsigned int is_primary_master;
unsigned int ethernet_flag;
char local_server[128]; // for the oaisim -c option : 0 = EURECOM web portal; -1 = local; 1 - N or filename = running a specific XML configuration file
unsigned int offset_ue_inst;
unsigned char multicast_group;
unsigned char ocg_enabled;
unsigned char opt_enabled;
unsigned char otg_enabled;
unsigned char omg_model_enb;
unsigned char omg_model_ue;
unsigned int seed;
double time;
}emu_info_t;
*/
#endif //
#endif /* __BYPASS_SESSION_LAYER_DEFS_H__ */
/*! \file extern.h
* \brief specifies the extern variables for phy emulation
* \author Navid Nikaein and Raymomd Knopp and Hicham Anouar
* \date 2011
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
* \brief specifies the extern variables for phy emulation
* \author Navid Nikaein and Raymomd Knopp and Hicham Anouar
* \date 2011
* \version 1.1
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
#ifndef __BYPASS_SESSION_LAYER_EXTERN_H__
# define __BYPASS_SESSION_LAYER_EXTERN_H__
......@@ -23,16 +23,17 @@ extern unsigned char emu_rx_status;
//extern unsigned short Master_id;
//extern unsigned int Is_primary_master;
#if !defined(ENABLE_NEW_MULTICAST)
extern pthread_mutex_t emul_low_mutex;
extern pthread_cond_t emul_low_cond;
extern char emul_low_mutex_var;
extern pthread_mutex_t Tx_mutex;
extern pthread_cond_t Tx_cond;
extern char Tx_mutex_var;
#endif
extern int (*rx_handler) (unsigned char,char*,int);
extern int (*tx_handler) (unsigned char,char*, unsigned int*, unsigned int*);
extern rx_handler_t rx_handler;
extern tx_handler_t tx_handler;
extern eNB_transport_info_t eNB_transport_info[NUMBER_OF_eNB_MAX];
extern u16 eNB_transport_info_TB_index[NUMBER_OF_eNB_MAX];
......
/*! \file multicast.h
* \brief
* \author Lionel Gauthier and Navid Nikaein
* \date 2011
* \version 1.0
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
* \brief
* \author Lionel Gauthier and Navid Nikaein
* \date 2011
* \version 1.1
* \company Eurecom
* \email: navid.nikaein@eurecom.fr
*/
#include <pthread.h>
#include <stdio.h>
......@@ -26,110 +26,117 @@
#include <sys/socket.h>
#include <sys/select.h>
//#include "openair_defs.h"
//#include <sys/socket.h>
#include <netinet/in.h>
//#include "openair_defs.h"
#define MULTICAST_LINK_C
#include "socket.h"
#include "multicast_link.h"
#ifndef USER_MODE
#ifdef NODE_RG
//#include "mac_rg_bypass.h"
#endif
#ifdef NODE_MT
//#include "mac_ue_bypass.h"
#endif
#endif //USER_MODE
#ifdef USER_MODE
//#include <rtai.h>
# define msg printf
# include "UTIL/LOG/log.h"
#endif //USER_MODE
//#include "extern.h"
extern unsigned short Master_id;
#define MULTICAST_LINK_NUM_GROUPS 4
char *multicast_group_list[MULTICAST_LINK_NUM_GROUPS] = {
"239.0.0.161\0",
"239.0.0.162\0",
"239.0.0.163\0",
"239.0.0.164\0"
"239.0.0.161",
"239.0.0.162",
"239.0.0.163",
"239.0.0.164"
};
static multicast_group_t group_list[MULTICAST_LINK_NUM_GROUPS];
static fd_set socks; /* Socket file descriptors we want to wake up for, using select() */
static int highsock; /* Highest #'d file descriptor, needed for select() */
/* Socket file descriptors we want to wake up for, using select() */
static fd_set socks;
/* Highest #'d file descriptor, needed for select() */
static int highsock;
#if ! defined(ENABLE_NEW_MULTICAST)
static pthread_t main_loop_thread;
static void (*rx_handler) (unsigned int, char*);
static unsigned char multicast_group;
static char *multicast_if;
#endif
static void (*rx_handler) (unsigned int, char *);
static unsigned char multicast_group;
static char *multicast_if;
//------------------------------------------------------------------------------
void
multicast_link_init ()
{
//------------------------------------------------------------------------------
int group;
int multicast_loop;
int reuse_addr = 1; /* Used so we can re-bind to our port
while a previous connection is still
in TIME_WAIT state. */
static struct ip_mreq command;
struct sockaddr_in sin;
// struct ifreq ifr;
for (group = 0; group < MULTICAST_LINK_NUM_GROUPS; group++) {
strcpy (group_list[group].host_addr, multicast_group_list[group]);
group_list[group].port = 46014 + group;
group_list[group].socket = make_socket_inet (SOCK_DGRAM, &group_list[group].port, &sin);
msg("multicast_link_init(): Created socket %d for group %d, port %d\n",
group_list[group].socket,group,group_list[group].port);
if (setsockopt (group_list[group].socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof (reuse_addr)) < 0) {
msg ("[MULTICAST] ERROR : setsockopt:SO_REUSEADDR, exiting ...");
exit (EXIT_FAILURE);
}
if (multicast_if != NULL) {
/* memset(&ifr, 0, sizeof(struct ifreq));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), multicast_if);
ioctl(group_list[group].socket, SIOCGIFINDEX, &ifr);
if (setsockopt (group_list[group].socket, SOL_SOCKET,SO_BINDTODEVICE,(void*)&ifr, sizeof(struct ifreq)) < 0) { */
if (setsockopt (group_list[group].socket, SOL_SOCKET,SO_BINDTODEVICE,multicast_if, 4) < 0) {
msg ("[MULTICAST] ERROR : setsockopt:SO_BINDTODEVICE on interface %s, exiting ...\n", multicast_if);
msg ("[MULTICAST] make sure that you have a root privilage or run with sudo -E \n");
exit (EXIT_FAILURE);
}
}
socket_setnonblocking (group_list[group].socket);
int group;
int multicast_loop;
int reuse_addr = 1;
static struct ip_mreq command;
struct sockaddr_in sin;
// struct ifreq ifr;
//
multicast_loop = 0;
if (setsockopt (group_list[group].socket, IPPROTO_IP, IP_MULTICAST_LOOP, &multicast_loop, sizeof (multicast_loop)) < 0) {
msg ("[MULTICAST] ERROR: %s line %d multicast_link_main_loop() IP_MULTICAST_LOOP %m", __FILE__, __LINE__);
exit (EXIT_FAILURE);
}
// Join the broadcast group:
command.imr_multiaddr.s_addr = inet_addr (group_list[group].host_addr);
command.imr_interface.s_addr = htonl (INADDR_ANY);
if (command.imr_multiaddr.s_addr == -1) {
msg ("[MULTICAST] ERROR: %s line %d NO MULTICAST", __FILE__, __LINE__);
exit (EXIT_FAILURE);
}
if (setsockopt (group_list[group].socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof (command)) < 0) {
msg ("[MULTICAST] ERROR: %s line %d IP_ADD_MEMBERSHIP %m", __FILE__, __LINE__);
exit (EXIT_FAILURE);
}
for (group = 0; group < MULTICAST_LINK_NUM_GROUPS; group++) {
strcpy (group_list[group].host_addr, multicast_group_list[group]);
group_list[group].port = 46014 + group;
group_list[group].socket = make_socket_inet(
SOCK_DGRAM,
&group_list[group].port, &sin);
LOG_D(EMU, "multicast_link_init(): Created socket %d for group %d, port %d\n",
group_list[group].socket,group,group_list[group].port);
/* Used so we can re-bind to our port while a previous connection is still
* in TIME_WAIT state.
*/
if (setsockopt(group_list[group].socket, SOL_SOCKET, SO_REUSEADDR,
&reuse_addr, sizeof (reuse_addr)) < 0) {
LOG_E(EMU, "[MULTICAST] ERROR : setsockopt:SO_REUSEADDR, exiting ...");
exit (EXIT_FAILURE);
}
if (multicast_if != NULL) {
if (setsockopt(group_list[group].socket, SOL_SOCKET,SO_BINDTODEVICE,
multicast_if, 4) < 0) {
LOG_E(EMU,
"[MULTICAST] ERROR : setsockopt:SO_BINDTODEVICE on interface %s, exiting ...\n",
multicast_if);
LOG_E(EMU,
"[MULTICAST] make sure that you have a root privilage or run with sudo -E \n");
exit (EXIT_FAILURE);
}
}
memset (&group_list[group].sock_remote_addr, 0, sizeof (struct sockaddr_in));
group_list[group].sock_remote_addr.sin_family = AF_INET;
group_list[group].sock_remote_addr.sin_addr.s_addr = inet_addr (multicast_group_list[group]);
group_list[group].sock_remote_addr.sin_port = htons (group_list[group].port);
}
#if !defined(ENABLE_TCP_MULTICAST)
/* Make the socket blocking */
socket_setnonblocking(group_list[group].socket);
#endif
multicast_loop = 0;
if (setsockopt (group_list[group].socket, IPPROTO_IP, IP_MULTICAST_LOOP,
&multicast_loop, sizeof (multicast_loop)) < 0) {
LOG_E(EMU,
"[MULTICAST] ERROR: %s line %d multicast_link_main_loop() IP_MULTICAST_LOOP %m",
__FILE__, __LINE__);
exit (EXIT_FAILURE);
}
// Join the broadcast group:
command.imr_multiaddr.s_addr = inet_addr (group_list[group].host_addr);
command.imr_interface.s_addr = htonl (INADDR_ANY);
if (command.imr_multiaddr.s_addr == -1) {
LOG_E(EMU, "[MULTICAST] ERROR: %s line %d NO MULTICAST", __FILE__, __LINE__);
exit (EXIT_FAILURE);
}
if (setsockopt (group_list[group].socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&command, sizeof (command)) < 0) {
LOG_E(EMU, "[MULTICAST] ERROR: %s line %d IP_ADD_MEMBERSHIP %m", __FILE__,
__LINE__);
exit (EXIT_FAILURE);
}
memset (&group_list[group].sock_remote_addr, 0, sizeof (struct sockaddr_in));
group_list[group].sock_remote_addr.sin_family = AF_INET;
group_list[group].sock_remote_addr.sin_addr.s_addr = inet_addr (
multicast_group_list[group]);
group_list[group].sock_remote_addr.sin_port = htons (group_list[group].port);
}
}
//------------------------------------------------------------------------------
......@@ -137,86 +144,69 @@ void
multicast_link_build_select_list ()
{
//------------------------------------------------------------------------------
int group;
int group;
/* First put together fd_set for select(), which will
consist of the sock veriable in case a new connection
is coming in, plus all the sockets we have already
accepted. */
/* First put together fd_set for select(), which will
consist of the sock veriable in case a new connection
is coming in, plus all the sockets we have already
accepted. */
/* FD_ZERO() clears out the fd_set called socks, so that
it doesn't contain any file descriptors. */
/* FD_ZERO() clears out the fd_set called socks, so that
it doesn't contain any file descriptors. */
FD_ZERO (&socks);
FD_ZERO (&socks);
/* Loops through all the possible connections and adds
those sockets to the fd_set */
/* Loops through all the possible connections and adds
those sockets to the fd_set */
for (group = 0; group < MULTICAST_LINK_NUM_GROUPS; group++) {
if (group_list[group].socket != 0) {
FD_SET (group_list[group].socket, &socks);
if (group_list[group].socket > highsock)
highsock = group_list[group].socket;
for (group = 0; group < MULTICAST_LINK_NUM_GROUPS; group++) {
if (group_list[group].socket != 0) {
FD_SET (group_list[group].socket, &socks);
if (group_list[group].socket > highsock) {
highsock = group_list[group].socket;
}
}
}
}
}
//------------------------------------------------------------------------------
void
multicast_link_read_data (int groupP)
{
//------------------------------------------------------------------------------
int num_bytes;
#ifdef BYPASS_PHY
//pthread_mutex_lock(&Bypass_phy_wr_mutex);
// while(Bypass_phy_wr){
// msg("[Multicast read] BYPASS_PHY_NOT_YET READY, Waiting for signal\n");
// pthread_cond_wait(&Bypass_phy_wr_cond,&Bypass_phy_wr_mutex);
// }
//msg("[Multicast read] BYPASS_PHY TX Signal\n");
//pthread_mutex_unlock(&Bypass_phy_wr_mutex);
//pthread_mutex_lock(&Bypass_phy_wr_mutex);
// Bypass_phy_wr=1;
// pthread_mutex_unlock(&Bypass_phy_wr_mutex);
#endif //BYPASS_PHY
int num_bytes;
//msg("multicast link read INNNNNNNNNNNNNNNNNN\n");
// msg("multicast_link_read_data: groupP=%d,rx_buffer = %p\n",groupP,group_list[groupP].rx_buffer );
if ((groupP <= MULTICAST_LINK_NUM_GROUPS) && (groupP >= 0)) {
if ((num_bytes = recvfrom (group_list[groupP].socket, group_list[groupP].rx_buffer, 40000, 0, 0, 0)) < 0) {
fprintf (stderr, "ERROR: %s line %d multicast_link_read_data()/recvfrom() %m", __FILE__, __LINE__);
if ((groupP <= MULTICAST_LINK_NUM_GROUPS) && (groupP >= 0)) {
if ((num_bytes = recvfrom (group_list[groupP].socket,
group_list[groupP].rx_buffer, 40000, 0, 0, 0)) < 0) {
LOG_E(EMU, "[MULTICAST] recvfrom has failed (%d:%s)\n (%s:%d)\n",
errno, strerror(errno), __FILE__, __LINE__);
} else {
rx_handler(num_bytes,group_list[groupP].rx_buffer);
}
} else {
// msg("multicast_link_read_data: groupP=%d,rx_buffer = %p,NUm_bytes=%d\n",groupP,group_list[groupP].rx_buffer,num_bytes );
//msg("MULTICAST calling rx_handler\n");
rx_handler(num_bytes,group_list[groupP].rx_buffer);
LOG_E(EMU, "[MULTICAST] ERROR: groupP out of bounds %d\n", groupP);
}
}
else {
fprintf(stderr,"ERROR: groupP out of bounds %d\n",groupP);
}
//msg("ENNNNND multicast_link_read_data: groupP=%d,rx_buffer = %p, num_bytes=%d\n",groupP,group_list[groupP].rx_buffer,num_bytes );
}
//------------------------------------------------------------------------------
void
multicast_link_read ()
{
//------------------------------------------------------------------------------
int group; /* Current item in connectlist for for loops */
int group; /* Current item in connectlist for for loops */
/* Now check connectlist for available data */
/* Now check connectlist for available data */
/* Run through our sockets and check to see if anything
happened with them, if so 'service' them. */
for (group = multicast_group; group < MULTICAST_LINK_NUM_GROUPS ; group++) {
if (FD_ISSET (group_list[group].socket, &socks)) {
multicast_link_read_data (group);
break;
}
} /* for (all entries in queue) */
/* Run through our sockets and check to see if anything
happened with them, if so 'service' them. */
for (group = multicast_group; group < MULTICAST_LINK_NUM_GROUPS ; group++) {
if (FD_ISSET (group_list[group].socket, &socks)) {
multicast_link_read_data (group);
break;
}
} /* for (all entries in queue) */
}
//------------------------------------------------------------------------------
......@@ -224,73 +214,89 @@ int
multicast_link_write_sock (int groupP, char *dataP, uint32_t sizeP)
{
//------------------------------------------------------------------------------
int num;
if ((num = sendto (group_list[groupP].socket, dataP, sizeP, 0, (struct sockaddr *) &group_list[groupP].sock_remote_addr, sizeof (group_list[groupP].sock_remote_addr))) < 0) {
fprintf (stderr, "ERROR: %s line %d multicast_link_write_sock()/sendto() %m", __FILE__, __LINE__);
}
return num;
int num;
if ((num = sendto (group_list[groupP].socket, dataP, sizeP, 0,
(struct sockaddr *) &group_list[groupP].sock_remote_addr,
sizeof (group_list[groupP].sock_remote_addr))) < 0) {
LOG_E(EMU, "[MULTICAST] sendto has failed (%d:%s)\n (%s:%d)\n",
errno, strerror(errno),
__FILE__, __LINE__);
}
return num;
}
//------------------------------------------------------------------------------
void *
multicast_link_main_loop (void *param)
int multicast_link_read_data_from_sock(uint8_t is_master)
{
//------------------------------------------------------------------------------
struct timeval timeout; /* Timeout for select */
int readsocks; /* Number of sockets ready for reading */
#ifdef USER_MODE
struct timeval timeout, *timeout_p;
int readsocks; /* Number of sockets ready for reading */
timeout.tv_sec = 0;
timeout.tv_usec = 3000;
if (is_master == 0) {
/* UE will block indefinetely if no data is sent from eNB
* NOTE: a NULL timeout for select will block indefinetely
*/
timeout_p = NULL;
} else {
/* In case of eNB set the timeout to 500 usecs after which we consider
* the packets as dropped.
*/
timeout_p = &timeout;
}
highsock = -1;
#endif //USER_MODE
highsock = -1;
while (1) {
multicast_link_build_select_list ();
/* [24/06/13] SR: Set the timeout to one second ->
* avoid infinite loop if no data to read.
*/
timeout.tv_sec = 1;
timeout.tv_usec = 0;
readsocks = select (highsock + 1, &socks, (fd_set *) 0, (fd_set *) 0, &timeout);
LOG_D(EMU, "Stuck on select with timeout %s\n",
timeout_p == NULL ? "infinite" : "1000 usecs");
readsocks = select(highsock + 1, &socks, (fd_set *) 0, (fd_set *) 0, timeout_p);
if (readsocks < 0) {
LOG_E(EMU, "Multicast select failed (%d:%s)\n", errno, strerror(errno));
// exit();
LOG_E(EMU, "Multicast select failed (%d:%s)\n", errno, strerror(errno));
exit(EXIT_FAILURE);
} else if (readsocks > 0) {
//msg("calling multicast link read\n");
multicast_link_read ();
// usleep(1);
LOG_D(EMU, "Multicast Normal read\n");
multicast_link_read();
} else {
/* Timeout */
LOG_I(EMU, "Multicast select time-out\n");
/* Timeout */
LOG_I(EMU, "Multicast select time-out\n");
return 1;
}
}