608 lines
18 KiB
C
608 lines
18 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_pkt_queue_mbc.c,v $ $Revision: 1.15 $
|
|
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_pkt_queue_mbc.c,v $
|
|
* $Author: kenneth $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
/* Multiband Container queue.
|
|
Traffic is ordered in 2 or more band, where the priority decreses as the
|
|
band index increases.
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifndef IPCOM_KERNEL
|
|
#define IPCOM_KERNEL
|
|
#endif
|
|
#include "ipnet_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPNET_USE_IFO_MBC
|
|
#ifndef IPNET_USE_IFO_FIFO
|
|
#error "MultiBand Container requires the FIFO queue"
|
|
#endif
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_syslog.h>
|
|
|
|
#include "ipnet_h.h"
|
|
#include "ipnet_netif.h"
|
|
#include "ipnet_pkt_queue.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
typedef struct Ipnet_pkt_queue_mbc_struct
|
|
{
|
|
Ipnet_pkt_queue hdr;
|
|
Ip_u32 number_of_bands;
|
|
Ip_u32 default_band;
|
|
Ipnet_pkt_queue **bands;
|
|
Ipnet_classifier *classifier;
|
|
}
|
|
Ipnet_pkt_queue_mbc;
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_insert_default_queue
|
|
*===========================================================================
|
|
* Description: Inserts a FIFO queue in the MBC.
|
|
* Parameters: pq - Pointer to where the new FIFO should be stored.
|
|
* netif - The interface the queue belongs to.
|
|
* Returns: 0 = success
|
|
* <0 = error code
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_insert_default_queue(Ipnet_pkt_queue_mbc *q, int band)
|
|
{
|
|
struct Ipnet_ifqueue fifo;
|
|
|
|
ipcom_strcpy(fifo.ifq_name, q->hdr.netif->ipcom.name);
|
|
ipcom_strcpy(fifo.ifq_type, "fifo");
|
|
if (q->bands[band] == IP_NULL)
|
|
fifo.ifq_id = IP_IFQ_ID_NONE;
|
|
else
|
|
fifo.ifq_id = q->bands[band]->id;
|
|
fifo.ifq_parent_id = q->hdr.id;
|
|
fifo.ifq_data.fifo.fifo_limit = IPNET_PKT_QUEUE_DEFAULT_FIFO_SIZE;
|
|
return ipnet_pkt_queue_new(&fifo, q->hdr.netif, &q->bands[band]);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_enqueue
|
|
*===========================================================================
|
|
* Description: Inserts a packet into the queue.
|
|
* Parameters: q - A MBC based queue.
|
|
* pkt - The packet to store.
|
|
* Returns: 0 = success
|
|
* <0 = error code
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_enqueue(Ipnet_pkt_queue_mbc *q, Ipcom_pkt *pkt)
|
|
{
|
|
int band;
|
|
Ipnet_pkt_queue *child_q;
|
|
|
|
band = ipnet_classifier_pkt_to_tag(q->classifier, pkt);
|
|
if (band < 0)
|
|
child_q = q->bands[q->default_band];
|
|
else
|
|
child_q = q->bands[band];
|
|
|
|
return child_q->enqueue(child_q, pkt);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_dequeue
|
|
*===========================================================================
|
|
* Description: Removed a packet from the queue.
|
|
* Parameters: q - A MBC based queue.
|
|
* Returns: A packet from the queue or IP_NULL if all bands of the queue
|
|
* are empty.
|
|
*
|
|
*/
|
|
IP_STATIC Ipcom_pkt *
|
|
ipnet_pkt_queue_mbc_dequeue(Ipnet_pkt_queue_mbc *q)
|
|
{
|
|
Ipcom_pkt *pkt;
|
|
Ip_u32 band;
|
|
|
|
for (band = 0; band < q->number_of_bands; band++)
|
|
{
|
|
if (q->bands[band] == IP_NULL)
|
|
continue;
|
|
|
|
pkt = q->bands[band]->dequeue(q->bands[band]);
|
|
if (pkt)
|
|
return pkt;
|
|
}
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_requeue
|
|
*===========================================================================
|
|
* Description: Puts back a packet so it will be the first to dequeue next
|
|
* time.
|
|
* Parameters: q - A MBC packet queue.
|
|
* pkt - The packet to requeue.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_pkt_queue_mbc_requeue(Ipnet_pkt_queue_mbc *q, Ipcom_pkt *pkt)
|
|
{
|
|
int band;
|
|
Ipnet_pkt_queue *child_q;
|
|
|
|
band = ipnet_classifier_pkt_to_tag(q->classifier, pkt);
|
|
if (band < 0)
|
|
child_q = q->bands[q->default_band];
|
|
else
|
|
child_q = q->bands[band];
|
|
|
|
child_q->requeue(child_q, pkt);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_count
|
|
*===========================================================================
|
|
* Description: Returns the number of packets that is currently queued.
|
|
* Parameters: q - A MBC based queue.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_count(Ipnet_pkt_queue_mbc *q)
|
|
{
|
|
Ip_u32 band;
|
|
int count = 0;
|
|
|
|
for (band = 0; band < q->number_of_bands; band++)
|
|
count += q->bands[band]->count(q->bands[band]);
|
|
return count;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_reset
|
|
*===========================================================================
|
|
* Description: Resets the queue, all packets is discarded.
|
|
* Parameters: q - A MBC based queue.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_pkt_queue_mbc_reset(Ipnet_pkt_queue_mbc *q)
|
|
{
|
|
Ip_u32 band;
|
|
|
|
for (band = 0; band < q->number_of_bands; band++)
|
|
q->bands[band]->reset(q->bands[band]);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_dump
|
|
*===========================================================================
|
|
* Description: Dumps the configuration to the supplied buffer.
|
|
* Parameters: q - A packet queue.
|
|
* m - The buffer where the data should be dumped.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_pkt_queue_mbc_dump(Ipnet_pkt_queue_mbc *q, struct Ipnet_ifqueue_mbc *m)
|
|
{
|
|
Ip_u32 band;
|
|
|
|
m->mbc_bands = q->number_of_bands;
|
|
m->mbc_default_band = q->default_band;
|
|
|
|
for (band = 0; band < q->number_of_bands; band++)
|
|
*(int *)&m->mbc_container.child_ids[band] = q->bands[band]->id;
|
|
|
|
*(int *)&m->mbc_container.child_count = (int) q->number_of_bands;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_configure
|
|
*===========================================================================
|
|
* Description: Configures a queue with new parameters.
|
|
* Parameters: q - A packet queue.
|
|
* m - The queue parameters.
|
|
* Returns: 0 = success
|
|
* <0 = error code
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_configure(Ipnet_pkt_queue_mbc *q, struct Ipnet_ifqueue_mbc *m)
|
|
{
|
|
Ip_u32 band;
|
|
|
|
if (q->number_of_bands)
|
|
{
|
|
IPCOM_LOG0(ERR, "MBC configure: Can only be configured once");
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
if (m->mbc_bands < 2 || m->mbc_bands > IPNET_IFQ_CONTAINER_MAX_COUNT)
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"MBC configure: Number of priority bands must be between 2 and %d",
|
|
IPNET_IFQ_CONTAINER_MAX_COUNT);
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
if (m->mbc_bands <= m->mbc_default_band)
|
|
{
|
|
IPCOM_LOG1(ERR, "MBC configure: invalid default band, must be [0..%d]",
|
|
m->mbc_bands - 1);
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
q->bands = ipcom_calloc(m->mbc_bands, sizeof(Ipnet_pkt_queue *));
|
|
if (q->bands == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(CRIT, "MBC configure: out of memory");
|
|
return -IP_ERRNO_ENOMEM;
|
|
}
|
|
|
|
q->number_of_bands = m->mbc_bands;
|
|
q->default_band = m->mbc_default_band;
|
|
|
|
for (band = 0; band < q->number_of_bands; band++)
|
|
{
|
|
int ret;
|
|
|
|
ret = ipnet_pkt_queue_mbc_insert_default_queue(q, band);
|
|
if (ret < 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "MBC configure: Failed to create default queue: %s",
|
|
ipcom_strerror(-ret));
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_init
|
|
*===========================================================================
|
|
* Description: Configures a queue with new parameters.
|
|
* Parameters: q - A packet queue.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_init(Ipnet_pkt_queue_mbc *q)
|
|
{
|
|
ipcom_memset((Ip_u8 *) q + sizeof(Ipnet_pkt_queue),
|
|
0,
|
|
sizeof(Ipnet_pkt_queue_mbc) - sizeof(Ipnet_pkt_queue));
|
|
|
|
q->classifier = ipnet_classifier_new();
|
|
if (q->classifier == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "MBC init: Failed to create classifier: out of memory");
|
|
return -IP_ERRNO_ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_destroy
|
|
*===========================================================================
|
|
* Description: Frees all contained queues.
|
|
* Parameters: q - A MBC based queue.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_pkt_queue_mbc_destroy(Ipnet_pkt_queue_mbc *q)
|
|
{
|
|
Ip_u32 band;
|
|
|
|
for (band = 0; band < q->number_of_bands; band++)
|
|
ipnet_pkt_queue_delete(q->bands[band]);
|
|
ipcom_free(q->bands);
|
|
|
|
if (q->classifier)
|
|
ipnet_classifier_delete(q->classifier);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_get
|
|
*===========================================================================
|
|
* Description: Returns the queue that matches the specified ID.
|
|
* Parameters: q - A MBC packet queue.
|
|
* id - The ID of the contained queue.
|
|
* Returns: A pointer to the queue or IP_NULL if it was not found.
|
|
*
|
|
*/
|
|
IP_STATIC struct Ipnet_pkt_queue_struct *
|
|
ipnet_pkt_queue_mbc_get(Ipnet_pkt_queue_mbc *q, int id)
|
|
{
|
|
Ip_u32 band;
|
|
Ipnet_pkt_queue *c;
|
|
|
|
if (q->hdr.id == id)
|
|
return &q->hdr;
|
|
|
|
for (band = 0; band < q->number_of_bands; band++)
|
|
{
|
|
c = q->bands[band];
|
|
if (c)
|
|
{
|
|
if (c->id == id)
|
|
return c;
|
|
if (c->c_ops && IP_NULL != (c = c->c_ops->q_get(c, id)))
|
|
return c;
|
|
}
|
|
}
|
|
IPCOM_LOG3(DEBUG2, "MBC: Did not find %d queue inside %s:%d",
|
|
id, q->hdr.type, q->hdr.id);
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_remove
|
|
*===========================================================================
|
|
* Description: Removes an queue from a container queue and put pack a
|
|
* default queue type.
|
|
* Parameters: c - The MBC parent queue for 'q'.
|
|
* q - The queue to remove.
|
|
* Returns: 0 = success, <0 = error code (-IP_ERRNO_xxx)
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_remove(Ipnet_pkt_queue_mbc *c, Ipnet_pkt_queue *q)
|
|
{
|
|
Ip_u32 band;
|
|
|
|
ip_assert(c->hdr.id == q->parent_id);
|
|
for (band = 0; band < c->number_of_bands; band++)
|
|
{
|
|
if (q == c->bands[band])
|
|
{
|
|
int ret = ipnet_pkt_queue_mbc_insert_default_queue(c, band);
|
|
if (ret < 0)
|
|
IPCOM_LOG3(WARNING, "MBC: Failed to replace %s:%d with a fifo in remove(): %s",
|
|
q->type, q->id, ipcom_strerror(-ret));
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return -IP_ERRNO_ESRCH;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_insert
|
|
*===========================================================================
|
|
* Description: Inserts an queue to a container queue.
|
|
* Parameters: c - The parent queue for 'q', must be container capable
|
|
* q - The queue to insert.
|
|
* Returns: 0 = success, <0 = error code (-IP_ERRNO_xxx)
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_insert(Ipnet_pkt_queue_mbc *c, Ipnet_pkt_queue *q)
|
|
{
|
|
Ip_u32 band;
|
|
|
|
for (band = 0; band < c->number_of_bands; band++)
|
|
{
|
|
if (c->bands[band] == IP_NULL)
|
|
{
|
|
/* Is adding the initial queues */
|
|
c->bands[band] = q;
|
|
return 0;
|
|
}
|
|
|
|
if (q->id == c->bands[band]->id)
|
|
{
|
|
/* Replace this queue */
|
|
ipnet_pkt_queue_delete(c->bands[band]);
|
|
c->bands[band] = q;
|
|
return 0;
|
|
}
|
|
}
|
|
IPCOM_LOG1(ERR, "MBC: No band has queue id %d", q->id);
|
|
return -IP_ERRNO_ESRCH;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_htbc_f_insert
|
|
*===========================================================================
|
|
* Description: Inserts a new filter into a MBC queue.
|
|
* Parameters: c - A HTBC queue.
|
|
* filter_id - The ID the filter will have.
|
|
* rule - The rule to match this filter.
|
|
* child_queue_id - The queue ID of the child filter that packets
|
|
* that matches the rule will be queued at.
|
|
* Returns: 0 = success, <0 = error code (-IP_ERRNO_xxx)
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_f_insert(Ipnet_pkt_queue_mbc *c,
|
|
int filter_id,
|
|
struct Ipnet_classifier_rule *rule,
|
|
int child_queue_id)
|
|
{
|
|
int ret;
|
|
Ip_u32 band;
|
|
|
|
for (band = 0; band < c->number_of_bands; band++)
|
|
if (c->bands[band]->id == child_queue_id)
|
|
break;
|
|
|
|
if (0 > (ret = ipnet_classifier_add_mapping(c->classifier, rule, filter_id)))
|
|
return ret;
|
|
return ipnet_classifier_set_tag(c->classifier, filter_id, band);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_mbc_f_remove
|
|
*===========================================================================
|
|
* Description: Removes a filter from a MBC queue.
|
|
* Parameters: mbc - A MBC queue.
|
|
* queue_id - The
|
|
* Returns: 0 = success, <0 = error code (-IP_ERRNO_xxx)
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_pkt_queue_mbc_f_remove(Ipnet_pkt_queue_mbc *c, int filter_id)
|
|
{
|
|
return ipnet_classifier_del_mapping(c->classifier, filter_id);
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_pkt_queue_htbc_template
|
|
*===========================================================================
|
|
* Description: Returns a template for Hierarchical Token Bucket Filter queue.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipnet_pkt_queue *
|
|
ipnet_pkt_queue_mbc_template()
|
|
{
|
|
static Ipnet_pkt_queue_container c_ops = {
|
|
(Ipnet_pkt_queue_container_get_queue) ipnet_pkt_queue_mbc_get,
|
|
(Ipnet_pkt_queue_container_insert_queue) ipnet_pkt_queue_mbc_insert,
|
|
(Ipnet_pkt_queue_container_remove_queue) ipnet_pkt_queue_mbc_remove,
|
|
(Ipnet_pkt_queue_container_insert_filter) ipnet_pkt_queue_mbc_f_insert,
|
|
(Ipnet_pkt_queue_container_remove_filter) ipnet_pkt_queue_mbc_f_remove,
|
|
};
|
|
|
|
static Ipnet_pkt_queue mbc_template = {
|
|
"mbc",
|
|
sizeof(Ipnet_pkt_queue_mbc),
|
|
&c_ops,
|
|
(Ipnet_pkt_queue_enqueue) ipnet_pkt_queue_mbc_enqueue,
|
|
(Ipnet_pkt_queue_dequeue) ipnet_pkt_queue_mbc_dequeue,
|
|
(Ipnet_pkt_queue_requeue) ipnet_pkt_queue_mbc_requeue,
|
|
(Ipnet_pkt_queue_count) ipnet_pkt_queue_mbc_count,
|
|
(Ipnet_pkt_queue_reset) ipnet_pkt_queue_mbc_reset,
|
|
(Ipnet_pkt_queue_dump) ipnet_pkt_queue_mbc_dump,
|
|
(Ipnet_pkt_queue_configure) ipnet_pkt_queue_mbc_configure,
|
|
(Ipnet_pkt_queue_init) ipnet_pkt_queue_mbc_init,
|
|
(Ipnet_pkt_queue_destroy) ipnet_pkt_queue_mbc_destroy,
|
|
};
|
|
return &mbc_template;
|
|
}
|
|
|
|
#else
|
|
int ipnet_pkt_q_container_mbc_empty_file;
|
|
#endif /* IPNET_USE_IFO_MBC */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|