mirror of https://gerrit.osmocom.org/libosmocore
gprs_ns2: implement a simple load sharing for UDP
Implement the load sharing based on modulo of the LSP. As long the gprs_ns2 doesn't support the resource distribution function (48.016 § 4.4a) this simple approach is good enought. Fixes: OS#4836 Change-Id: I8c2fe5d647694886ac600470fca6ea5d5d210a85
This commit is contained in:
parent
bf5d0dbdec
commit
d8a8d98053
|
@ -384,6 +384,45 @@ static struct gprs_ns2_vc *ns2_load_sharing_modulor(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 4.4.2 Load Sharing function for the IP Sub-Network
|
||||||
|
*
|
||||||
|
* Implement a simple approach for UDP load sharing of data weight based on the modulo of the lsp.
|
||||||
|
*
|
||||||
|
* E.g. 3 NSVC: 1st weight 5, 2nd weight 3, 3rd weight 1, lsp = 3.
|
||||||
|
* sum all weights = 9
|
||||||
|
* target_weight = lsp % sum = 3
|
||||||
|
*
|
||||||
|
* 1st NSVC will be the target for 0-4
|
||||||
|
* 2nd NSVC will be the target for 5-7
|
||||||
|
* 3rd NSVC will be the target for 8
|
||||||
|
*
|
||||||
|
* The 1st NSVC will be used.
|
||||||
|
* E.g. lsp = 7. The 2nd NSVC will used.
|
||||||
|
*/
|
||||||
|
static struct gprs_ns2_vc *ns2_load_sharing_weight_modulo(
|
||||||
|
struct gprs_ns2_nse *nse,
|
||||||
|
uint16_t bvci,
|
||||||
|
uint32_t load_selector)
|
||||||
|
{
|
||||||
|
struct gprs_ns2_vc *tmp;
|
||||||
|
uint32_t mod;
|
||||||
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
if (nse->nsvc_count == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mod = (bvci + load_selector) % nse->sum_data_weight;
|
||||||
|
llist_for_each_entry(tmp, &nse->nsvc, list) {
|
||||||
|
if (!ns2_vc_is_unblocked(tmp))
|
||||||
|
continue;
|
||||||
|
if (i == mod || mod < i + tmp->data_weight)
|
||||||
|
return tmp;
|
||||||
|
i += tmp->data_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* pick the first available data NSVC - no load sharing */
|
/* pick the first available data NSVC - no load sharing */
|
||||||
struct gprs_ns2_vc *ns2_load_sharing_first(struct gprs_ns2_nse *nse)
|
struct gprs_ns2_vc *ns2_load_sharing_first(struct gprs_ns2_nse *nse)
|
||||||
{
|
{
|
||||||
|
@ -421,7 +460,7 @@ static struct gprs_ns2_vc *ns2_load_sharing(
|
||||||
nsvc = ns2_load_sharing_signal(nse);
|
nsvc = ns2_load_sharing_signal(nse);
|
||||||
} else {
|
} else {
|
||||||
/* data with load sharing parameter */
|
/* data with load sharing parameter */
|
||||||
nsvc = ns2_load_sharing_first(nse);
|
nsvc = ns2_load_sharing_weight_modulo(nse, bvci, link_selector);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,18 @@ static int ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int gp_send_to_ns(struct gprs_ns2_inst *nsi, struct msgb *msg, uint16_t nsei, uint16_t bvci, uint32_t lsp)
|
||||||
|
{
|
||||||
|
struct osmo_gprs_ns2_prim nsp = {};
|
||||||
|
nsp.nsei = nsei;
|
||||||
|
nsp.bvci = bvci;
|
||||||
|
nsp.u.unitdata.link_selector = lsp;
|
||||||
|
osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA,
|
||||||
|
PRIM_OP_REQUEST, msg);
|
||||||
|
return gprs_ns2_recv_prim(nsi, &nsp.oph);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct msgb *get_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type pdu_type)
|
static struct msgb *get_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type pdu_type)
|
||||||
{
|
{
|
||||||
struct gprs_ns_hdr *nsh;
|
struct gprs_ns_hdr *nsh;
|
||||||
|
@ -88,6 +100,12 @@ static bool find_pdu(struct gprs_ns2_vc_bind *bind, enum ns_pdu_type pdu_type)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int count_pdus(struct gprs_ns2_vc_bind *bind)
|
||||||
|
{
|
||||||
|
struct osmo_wqueue *queue = bind->priv;
|
||||||
|
return llist_count(&queue->msg_queue);
|
||||||
|
}
|
||||||
|
|
||||||
static void clear_pdus(struct gprs_ns2_vc_bind *bind)
|
static void clear_pdus(struct gprs_ns2_vc_bind *bind)
|
||||||
{
|
{
|
||||||
struct osmo_wqueue *queue = bind->priv;
|
struct osmo_wqueue *queue = bind->priv;
|
||||||
|
@ -370,6 +388,81 @@ void test_unitdata(void *ctx)
|
||||||
printf("--- Finish unitdata test\n");
|
printf("--- Finish unitdata test\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_unitdata_weights(void *ctx)
|
||||||
|
{
|
||||||
|
struct gprs_ns2_inst *nsi;
|
||||||
|
struct gprs_ns2_vc_bind *bind[3];
|
||||||
|
struct gprs_ns2_vc_bind *loopbind;
|
||||||
|
struct gprs_ns2_nse *nse;
|
||||||
|
struct gprs_ns2_vc *nsvc[3];
|
||||||
|
struct gprs_ns2_vc *loop[3];
|
||||||
|
|
||||||
|
struct msgb *msg, *other;
|
||||||
|
char idbuf[32];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
printf("--- Testing unitdata weight test\n");
|
||||||
|
osmo_wqueue_clear(unitdata);
|
||||||
|
printf("---- Create NSE + Binds\n");
|
||||||
|
nsi = gprs_ns2_instantiate(ctx, ns_prim_cb, NULL);
|
||||||
|
bind[0] = dummy_bind(nsi, "bblock1");
|
||||||
|
bind[1] = dummy_bind(nsi, "bblock2");
|
||||||
|
bind[2] = dummy_bind(nsi, "bblock3");
|
||||||
|
loopbind = loopback_bind(nsi, "loopback");
|
||||||
|
nse = gprs_ns2_create_nse(nsi, 1004, GPRS_NS2_LL_UDP, GPRS_NS2_DIALECT_STATIC_ALIVE);
|
||||||
|
OSMO_ASSERT(nse);
|
||||||
|
|
||||||
|
/* data weights are
|
||||||
|
* nsvc[0] = 1
|
||||||
|
* nsvc[1] = 2
|
||||||
|
* nsvc[2] = 3
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
printf("---- Create NSVC[%d]\n", i);
|
||||||
|
snprintf(idbuf, sizeof(idbuf), "NSE%05u-dummy-%i", nse->nsei, i);
|
||||||
|
nsvc[i] = ns2_vc_alloc(bind[i], nse, false, GPRS_NS2_VC_MODE_ALIVE, idbuf);
|
||||||
|
loop[i] = loopback_nsvc(loopbind, nsvc[i]);
|
||||||
|
OSMO_ASSERT(nsvc[i]);
|
||||||
|
nsvc[i]->data_weight = i + 1;
|
||||||
|
ns2_vc_fsm_start(nsvc[i]);
|
||||||
|
OSMO_ASSERT(!ns2_vc_is_unblocked(nsvc[i]));
|
||||||
|
ns2_tx_alive_ack(loop[i]);
|
||||||
|
OSMO_ASSERT(ns2_vc_is_unblocked(nsvc[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all nsvcs are alive */
|
||||||
|
printf("---- Send UNITDATA to all NSVCs\n");
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
msg = generate_unitdata("test_unitdata_weight");
|
||||||
|
ns2_recv_vc(nsvc[i], msg);
|
||||||
|
other = msgb_dequeue(&unitdata->msg_queue);
|
||||||
|
OSMO_ASSERT(msg == other);
|
||||||
|
other = msgb_dequeue(&unitdata->msg_queue);
|
||||||
|
OSMO_ASSERT(NULL == other);
|
||||||
|
msgb_free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* nsvc[1] should be still good */
|
||||||
|
printf("---- Send BSSGP data to the NSE to test unitdata over NSVC[1]\n");
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
clear_pdus(bind[i]);
|
||||||
|
|
||||||
|
for (i = 0; i < 12; i++) {
|
||||||
|
msg = generate_unitdata("test_unitdata_weight2");
|
||||||
|
gp_send_to_ns(nsi, msg, 1004, 1, i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
fprintf(stderr, "count_pdus(bind[%d]) = %d\n", i, count_pdus(bind[i]));
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
OSMO_ASSERT(count_pdus(bind[i]) == nsvc[i]->data_weight * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
gprs_ns2_free(nsi);
|
||||||
|
printf("--- Finish unitdata weight test\n");
|
||||||
|
}
|
||||||
|
|
||||||
void test_mtu(void *ctx)
|
void test_mtu(void *ctx)
|
||||||
{
|
{
|
||||||
struct gprs_ns2_inst *nsi;
|
struct gprs_ns2_inst *nsi;
|
||||||
|
@ -440,6 +533,7 @@ int main(int argc, char **argv)
|
||||||
test_nse_transfer_cap(ctx);
|
test_nse_transfer_cap(ctx);
|
||||||
test_block_unblock_nsvc(ctx);
|
test_block_unblock_nsvc(ctx);
|
||||||
test_unitdata(ctx);
|
test_unitdata(ctx);
|
||||||
|
test_unitdata_weights(ctx);
|
||||||
test_mtu(ctx);
|
test_mtu(ctx);
|
||||||
printf("===== NS2 protocol test END\n\n");
|
printf("===== NS2 protocol test END\n\n");
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,14 @@
|
||||||
---- Try to receive over blocked NSVC[0]
|
---- Try to receive over blocked NSVC[0]
|
||||||
---- Receive over NSVC[1]
|
---- Receive over NSVC[1]
|
||||||
--- Finish unitdata test
|
--- Finish unitdata test
|
||||||
|
--- Testing unitdata weight test
|
||||||
|
---- Create NSE + Binds
|
||||||
|
---- Create NSVC[0]
|
||||||
|
---- Create NSVC[1]
|
||||||
|
---- Create NSVC[2]
|
||||||
|
---- Send UNITDATA to all NSVCs
|
||||||
|
---- Send BSSGP data to the NSE to test unitdata over NSVC[1]
|
||||||
|
--- Finish unitdata weight test
|
||||||
--- Testing mtu test
|
--- Testing mtu test
|
||||||
---- Create NSE + Binds
|
---- Create NSE + Binds
|
||||||
---- Create NSVC[0]
|
---- Create NSVC[0]
|
||||||
|
|
Loading…
Reference in New Issue