original files of m241
This commit is contained in:
@@ -0,0 +1,557 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* INTERPEAK SOURCE FILE
|
||||
*
|
||||
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_pkt_queue_netemu.c,v $ $Revision: 1.23.10.1 $
|
||||
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_pkt_queue_netemu.c,v $
|
||||
* $Author: kenneth $
|
||||
* $State: Exp $ $Locker: $
|
||||
*
|
||||
* INTERPEAK_COPYRIGHT_STRING
|
||||
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 1 DESCRIPTION
|
||||
****************************************************************************
|
||||
*/
|
||||
/* Network emulator.
|
||||
This queue can
|
||||
- Add latency
|
||||
- Drop packets randomly or at a deterministic rate
|
||||
- Corrupt packets randomly or at a deterministic rate */
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 2 CONFIGURATION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef IPCOM_KERNEL
|
||||
#define IPCOM_KERNEL
|
||||
#endif
|
||||
#include "ipnet_config.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 3 INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifdef IPNET_USE_IFO_NETEMU
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_cstyle.h>
|
||||
#include <ipcom_err.h>
|
||||
#include <ipcom_pqueue.h>
|
||||
#include <ipcom_syslog.h>
|
||||
#include <ipcom_type.h>
|
||||
|
||||
#include "ipnet.h"
|
||||
#include "ipnet_h.h"
|
||||
#include "ipnet_pkt_queue.h"
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 4 DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define IPNET_NETEMU_DROP_PATTERN_INACTIVE 255
|
||||
|
||||
#define IPNET_NETEMU_SET_PKT_SEQ_NUM(pkt, seq) \
|
||||
ipcom_pkt_set_int(pkt, IPNET_PKT_INFO_NETEMU_SEQ_NUM, seq, Ip_u32)
|
||||
#define IPNET_NETEMU_GET_PKT_SEQ_NUM(pkt) \
|
||||
ipcom_pkt_get_int(pkt, IPNET_PKT_INFO_NETEMU_SEQ_NUM, Ip_u32)
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 5 TYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/* netemu queue */
|
||||
typedef struct Ipnet_pkt_queue_netemu_struct
|
||||
{
|
||||
Ipnet_pkt_queue hdr;
|
||||
Ipcom_pqueue *pq;
|
||||
Ipnet_timeout *tmo;
|
||||
int limit; /* Maximum number of packets that can be queued */
|
||||
Ip_u32 enqueue_count; /* Total number of packets that has been queued */
|
||||
Ip_u32 min_latency_msec; /* Minimum latency added to packets in milliseconds */
|
||||
Ip_u32 max_latency_msec; /* Maximum latency added to packets in milliseconds */
|
||||
Ip_bool random_drop; /* IP_FALSE -> drop every drop_probability packet
|
||||
IP_TRUE -> there is 1/every drop_probability
|
||||
chance that at packet is dropped */
|
||||
Ip_u32 drop_probability; /* 1 means every packet dropped, 10 means that
|
||||
every 10 packet is dropped */
|
||||
Ip_u32 drop_pattern; /* Bit field where 1 means drop and 0 means pass */
|
||||
Ip_u8 drop_pattern_len; /* Number of bits that is valid in 'drop_pattern' */
|
||||
Ip_u8 drop_pattern_index; /* Current bit used */
|
||||
Ip_bool random_corrupt; /* IP_FALSE -> corrupt every corrupt_probability packet
|
||||
IP_TRUE -> there is 1/every corrupt_probability
|
||||
chance that a packet is corrupted */
|
||||
Ip_u32 corrupt_probability;/* 1 means every packet corrupted, 10 means that
|
||||
every 10 packet is corrupted */
|
||||
Ip_u32 seq; /* Sequence number that is increased each time
|
||||
a packet is added */
|
||||
}
|
||||
Ipnet_pkt_queue_netemu;
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 6 EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 7 LOCAL PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 8 DATA
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 9 STATIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_pq_cmp
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC int
|
||||
ipnet_pkt_queue_netemu_pq_cmp(const Ipcom_pkt *pkt1, const Ipcom_pkt *pkt2)
|
||||
{
|
||||
if (IPNET_PKT_GET_TIMEOUT_ABS(pkt1) == IPNET_PKT_GET_TIMEOUT_ABS(pkt2))
|
||||
return IPCOM_IS_LT(IPNET_NETEMU_GET_PKT_SEQ_NUM(pkt1),
|
||||
IPNET_NETEMU_GET_PKT_SEQ_NUM(pkt2))
|
||||
? 1 : -1;
|
||||
if (IPCOM_IS_LT(IPNET_PKT_GET_TIMEOUT_ABS(pkt1),
|
||||
IPNET_PKT_GET_TIMEOUT_ABS(pkt2)))
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_corrupt
|
||||
*===========================================================================
|
||||
* Description: Inserts a packet into the queue.
|
||||
* Parameters: pkt - The packet to corrupt
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC void
|
||||
ipnet_pkt_queue_netemu_corrupt(Ipcom_pkt *pkt)
|
||||
{
|
||||
int i;
|
||||
int c = 1 + ipcom_rand() % 10;
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
pkt->data[pkt->start + ipcom_rand() % (pkt->end - pkt->start)] = (Ip_u8) ipcom_rand();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_to_string
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
#ifdef IPNET_DEBUG
|
||||
IP_STATIC int
|
||||
ipnet_pkt_queue_netemu_to_string(Ipnet_pkt_queue_netemu *netemu, char *buf, Ip_size_t buf_len)
|
||||
{
|
||||
return ipcom_snprintf(buf, buf_len, "NetEmu if %s limit %d size %d",
|
||||
netemu->hdr.netif->ipcom.name, netemu->limit, ipcom_pqueue_size(netemu->pq));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_retry_cb
|
||||
*===========================================================================
|
||||
* Description: Retries to transmit packets queued in the 'netemu' queue
|
||||
* Parameters: netemu - a netemu-queue instance
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC void
|
||||
ipnet_pkt_queue_netemu_retry_cb(Ipnet_pkt_queue_netemu *netemu)
|
||||
{
|
||||
Ipcom_pkt *pkt;
|
||||
Ipnet_pkt_queue *q = netemu->hdr.netif->snd_queue;
|
||||
|
||||
while (IP_NULL != (pkt = q->dequeue(q)))
|
||||
{
|
||||
int ret = ipnet_if_drv_output(q->netif, pkt);
|
||||
if (ret < 0)
|
||||
{
|
||||
q->requeue(q, pkt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_enqueue
|
||||
*===========================================================================
|
||||
* Description: Inserts a packet into the queue.
|
||||
* Parameters: q - A NETEMU based queue.
|
||||
* pkt - The packet to store.
|
||||
* Returns: 0 = success
|
||||
* <0 = error code
|
||||
*
|
||||
*/
|
||||
IP_STATIC int
|
||||
ipnet_pkt_queue_netemu_enqueue(Ipnet_pkt_queue_netemu *q,
|
||||
Ipcom_pkt *pkt)
|
||||
{
|
||||
Ip_u32 tmo_msec;
|
||||
Ip_bool drop = IP_FALSE;
|
||||
Ip_bool corrupt = IP_FALSE;
|
||||
|
||||
if (ipcom_pqueue_size(q->pq) == q->limit)
|
||||
{
|
||||
IPCOM_LOG0(DEBUG, "NETEMU enqueue: queue full");
|
||||
return -IP_ERRNO_ENOBUFS;
|
||||
}
|
||||
|
||||
++q->enqueue_count;
|
||||
|
||||
if (q->drop_probability)
|
||||
{
|
||||
Ip_bool restart_pattern = IP_FALSE;
|
||||
|
||||
if(q->random_drop)
|
||||
restart_pattern = !((Ip_u32) ipcom_rand() % q->drop_probability);
|
||||
else
|
||||
restart_pattern = !(q->enqueue_count % q->drop_probability);
|
||||
|
||||
if (restart_pattern)
|
||||
{
|
||||
if (q->drop_pattern_len == 0)
|
||||
drop = IP_TRUE;
|
||||
else
|
||||
q->drop_pattern_index = 0;
|
||||
}
|
||||
|
||||
if (q->drop_pattern_index < q->drop_pattern_len)
|
||||
{
|
||||
drop = IP_BIT_ISSET(q->drop_pattern, 1 << q->drop_pattern_index);
|
||||
++q->drop_pattern_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (drop)
|
||||
{
|
||||
IPCOM_LOG0(DEBUG, "NETEMU enqueue: dropping packet");
|
||||
return -IP_ERRNO_ECOMM;
|
||||
}
|
||||
|
||||
if (q->corrupt_probability)
|
||||
{
|
||||
if (q->random_corrupt)
|
||||
corrupt = !((Ip_u32) ipcom_rand() % q->corrupt_probability);
|
||||
else
|
||||
corrupt = !(q->enqueue_count % q->corrupt_probability);
|
||||
}
|
||||
|
||||
if (corrupt)
|
||||
{
|
||||
Ipcom_pkt *corrupt_pkt;
|
||||
/* Must clone the packet since IPNET does not expect the data
|
||||
be corrupted on the original packet */
|
||||
corrupt_pkt = ipnet_pkt_clone(pkt, IP_FALSE);
|
||||
if (corrupt_pkt != IP_NULL)
|
||||
{
|
||||
IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_NETIF_DEQUEUE);
|
||||
ipcom_pkt_free(pkt);
|
||||
pkt = corrupt_pkt;
|
||||
IPCOM_LOG0(DEBUG, "NETEMU enqueue: corrupting packet");
|
||||
ipnet_pkt_queue_netemu_corrupt(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
tmo_msec = q->min_latency_msec;
|
||||
if (q->max_latency_msec > q->min_latency_msec)
|
||||
tmo_msec += (Ip_u32) ipcom_rand() % (q->max_latency_msec - q->min_latency_msec);
|
||||
|
||||
ipnet->msec_now = ipnet_msec_now();
|
||||
IPNET_PKT_SET_TIMEOUT_ABS(pkt, tmo_msec + ipnet->msec_now);
|
||||
|
||||
IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_NETIF_OUTQ);
|
||||
IPNET_NETEMU_SET_PKT_SEQ_NUM(pkt, ++q->seq);
|
||||
return ipcom_pqueue_insert(q->pq, pkt) == IPCOM_SUCCESS ? 0 : -IP_ERRNO_ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_dequeue
|
||||
*===========================================================================
|
||||
* Description: Removed a packet from the queue.
|
||||
* Parameters: q - A NETEMU based queue.
|
||||
* Returns: A packet from the queue or IP_NULL if the queue is empty.
|
||||
*
|
||||
*/
|
||||
IP_STATIC Ipcom_pkt *
|
||||
ipnet_pkt_queue_netemu_dequeue(Ipnet_pkt_queue_netemu *q)
|
||||
{
|
||||
Ipcom_pkt *pkt;
|
||||
Ip_s64 msec_now;
|
||||
|
||||
pkt = ipcom_pqueue_get_next(q->pq);
|
||||
if (pkt == IP_NULL)
|
||||
return IP_NULL;
|
||||
|
||||
msec_now = ipnet->msec_now;
|
||||
|
||||
if (IPCOM_IS_GT64(IPNET_PKT_GET_TIMEOUT_ABS(pkt), msec_now))
|
||||
{
|
||||
/* More latency to add */
|
||||
if (q->tmo == IP_NULL)
|
||||
{
|
||||
(void)ipnet_timeout_schedule(IPNET_PKT_GET_TIMEOUT_ABS(pkt) - msec_now,
|
||||
(Ipnet_timeout_handler) ipnet_pkt_queue_netemu_retry_cb,
|
||||
q,
|
||||
&q->tmo);
|
||||
}
|
||||
return IP_NULL;
|
||||
}
|
||||
IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_NETIF_DEQUEUE);
|
||||
return ipcom_pqueue_remove_next(q->pq);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_requeue
|
||||
*===========================================================================
|
||||
* Description: Puts back a packet so it will be the first to dequeue next
|
||||
* time.
|
||||
* Parameters: netemu - A NETEMU packet queue.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC void
|
||||
ipnet_pkt_queue_netemu_requeue(Ipnet_pkt_queue_netemu *netemu, Ipcom_pkt *pkt)
|
||||
{
|
||||
(void)ipcom_pqueue_insert(netemu->pq, pkt);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_count
|
||||
*===========================================================================
|
||||
* Description: Returns the number of packets that is currently queued.
|
||||
* Parameters: netemu - A NETEMU based queue.
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC int
|
||||
ipnet_pkt_queue_netemu_count(Ipnet_pkt_queue_netemu *netemu)
|
||||
{
|
||||
return ipcom_pqueue_size(netemu->pq);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_reset
|
||||
*===========================================================================
|
||||
* Description: Resets the queue, all packets is discarded.
|
||||
* Parameters: netemu - A NETEMU based queue.
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC void
|
||||
ipnet_pkt_queue_netemu_reset(Ipnet_pkt_queue_netemu *netemu)
|
||||
{
|
||||
Ipcom_pkt *pkt;
|
||||
|
||||
while (IP_NULL != (pkt = ipcom_pqueue_remove_next(netemu->pq)))
|
||||
{
|
||||
IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_NETIF_DEQUEUE);
|
||||
ipcom_pkt_free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_dump
|
||||
*===========================================================================
|
||||
* Description: Dumps the configuration to the supplied buffer.
|
||||
* Parameters: q - A packet queue.
|
||||
* n - The buffer where the data should be dumped.
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC void
|
||||
ipnet_pkt_queue_netemu_dump(Ipnet_pkt_queue_netemu *q, struct Ipnet_ifqueue_netemu *n)
|
||||
{
|
||||
n->netemu_limit = q->limit;
|
||||
n->netemu_min_latency = q->min_latency_msec;
|
||||
n->netemu_max_latency = q->max_latency_msec;
|
||||
n->netemu_random_drop = q->random_drop;
|
||||
n->netemu_drop_probability = q->drop_probability;
|
||||
n->netemu_random_corrupt = q->random_corrupt;
|
||||
n->netemu_corrupt_probability = q->corrupt_probability;
|
||||
n->netemu_drop_pattern = q->drop_pattern;
|
||||
n->netemu_drop_pattern_len = q->drop_pattern_len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_configure
|
||||
*===========================================================================
|
||||
* Description: Configures a queue with new parameters.
|
||||
* Parameters: q - A packet queue.
|
||||
* n - The queue parameters.
|
||||
* Returns: 0 = success
|
||||
* <0 = error code
|
||||
*/
|
||||
IP_STATIC int
|
||||
ipnet_pkt_queue_netemu_configure(Ipnet_pkt_queue_netemu *q, struct Ipnet_ifqueue_netemu *n)
|
||||
{
|
||||
q->limit = n->netemu_limit;
|
||||
q->min_latency_msec = n->netemu_min_latency;
|
||||
q->max_latency_msec = n->netemu_max_latency;
|
||||
q->random_drop = n->netemu_random_drop;
|
||||
q->drop_probability = n->netemu_drop_probability;
|
||||
q->random_corrupt = n->netemu_random_corrupt;
|
||||
q->corrupt_probability = n->netemu_corrupt_probability;
|
||||
q->drop_pattern = n->netemu_drop_pattern;
|
||||
q->drop_pattern_len = n->netemu_drop_pattern_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_init
|
||||
*===========================================================================
|
||||
* Description: Configures a queue with new parameters.
|
||||
* Parameters: q - A packet queue.
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC int
|
||||
ipnet_pkt_queue_netemu_init(Ipnet_pkt_queue_netemu *q)
|
||||
{
|
||||
ipcom_memset((Ip_u8 *) q + sizeof(Ipnet_pkt_queue),
|
||||
0,
|
||||
sizeof(Ipnet_pkt_queue_netemu) - sizeof(Ipnet_pkt_queue));
|
||||
q->drop_pattern_index = IPNET_NETEMU_DROP_PATTERN_INACTIVE;
|
||||
|
||||
q->pq = ipcom_pqueue_new((Ipcom_pqueue_cmp_func) ipnet_pkt_queue_netemu_pq_cmp,
|
||||
ipcom_pqueue_nop_store_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_destroy
|
||||
*===========================================================================
|
||||
* Description: Frees all contained queues.
|
||||
* Parameters: netemu - A NETEMU based queue.
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_STATIC void
|
||||
ipnet_pkt_queue_netemu_destroy(Ipnet_pkt_queue_netemu *netemu)
|
||||
{
|
||||
ipnet_timeout_cancel(netemu->tmo);
|
||||
ipnet_pkt_queue_netemu_reset(netemu);
|
||||
ipcom_pqueue_delete(netemu->pq);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 10 GLOBAL FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipnet_pkt_queue_netemu_template
|
||||
*===========================================================================
|
||||
* Description: Returns a template for NETEMU queue.
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_GLOBAL Ipnet_pkt_queue *
|
||||
ipnet_pkt_queue_netemu_template()
|
||||
{
|
||||
static Ipnet_pkt_queue netemu_template =
|
||||
{
|
||||
"netemu",
|
||||
sizeof(Ipnet_pkt_queue_netemu),
|
||||
IP_NULL, /* Not a container */
|
||||
(Ipnet_pkt_queue_enqueue) ipnet_pkt_queue_netemu_enqueue,
|
||||
(Ipnet_pkt_queue_dequeue) ipnet_pkt_queue_netemu_dequeue,
|
||||
(Ipnet_pkt_queue_requeue) ipnet_pkt_queue_netemu_requeue,
|
||||
(Ipnet_pkt_queue_count) ipnet_pkt_queue_netemu_count,
|
||||
(Ipnet_pkt_queue_reset) ipnet_pkt_queue_netemu_reset,
|
||||
(Ipnet_pkt_queue_dump) ipnet_pkt_queue_netemu_dump,
|
||||
(Ipnet_pkt_queue_configure) ipnet_pkt_queue_netemu_configure,
|
||||
(Ipnet_pkt_queue_init) ipnet_pkt_queue_netemu_init,
|
||||
(Ipnet_pkt_queue_destroy) ipnet_pkt_queue_netemu_destroy,
|
||||
};
|
||||
#ifdef IPNET_DEBUG
|
||||
ipnet_timeout_to_string((Ipnet_timeout_handler) ipnet_pkt_queue_netemu_retry_cb,
|
||||
(Ipnet_timeout_to_string_f) ipnet_pkt_queue_netemu_to_string);
|
||||
#endif
|
||||
|
||||
return &netemu_template;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 11 PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#else
|
||||
int ipnet_pkt_queue_netemu_empty_file;
|
||||
#endif /* IPNET_USE_IFO_NETEMU */
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user