mirror of https://gerrit.osmocom.org/libosmocore
gprs_ns2_sns: implement outbound SNS ADD procedures
When adding a bind, the remote side needs to be informed via the SNS ADD procedure. Related: OS#5036 Change-Id: I71c33200bd1f0307ceb943ee958db5ebe3623d36
This commit is contained in:
parent
1f3193d344
commit
9cd39ac6ac
|
@ -93,6 +93,8 @@ static const struct value_string gprs_sns_event_names[] = {
|
|||
{ 0, NULL }
|
||||
};
|
||||
|
||||
#define GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER (void *) 1
|
||||
|
||||
enum sns_procedure {
|
||||
SNS_PROC_NONE, /*!< used as invalid/idle value */
|
||||
SNS_PROC_ADD,
|
||||
|
@ -1473,6 +1475,12 @@ static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_
|
|||
|
||||
/* also takes care of retransmitting */
|
||||
switch (gss->current_procedure->procedure) {
|
||||
case SNS_PROC_ADD:
|
||||
if (gss->family == AF_INET)
|
||||
ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
|
||||
else
|
||||
ns2_tx_sns_add(gss->sns_nsvc, gss->current_procedure->trans_id, NULL, 0, &gss->current_procedure->ip6, 1);
|
||||
break;
|
||||
case SNS_PROC_CHANGE_WEIGHT:
|
||||
if (gss->family == AF_INET)
|
||||
ns2_tx_sns_change_weight(gss->sns_nsvc, gss->current_procedure->trans_id, &gss->current_procedure->ip4, 1, NULL, 0);
|
||||
|
@ -1484,6 +1492,65 @@ static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_
|
|||
}
|
||||
}
|
||||
|
||||
static void create_nsvc_for_new_sbind(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind)
|
||||
{
|
||||
struct gprs_ns2_nse *nse = gss->nse;
|
||||
struct gprs_ns2_vc_bind *bind = sbind->bind;
|
||||
struct gprs_ns2_vc *nsvc;
|
||||
struct osmo_sockaddr remote = { };
|
||||
unsigned int i;
|
||||
|
||||
/* iterate over all remote IPv4 endpoints */
|
||||
for (i = 0; i < gss->remote.num_ip4; i++) {
|
||||
const struct gprs_ns_ie_ip4_elem *ip4 = &gss->remote.ip4[i];
|
||||
|
||||
remote.u.sin.sin_family = AF_INET;
|
||||
remote.u.sin.sin_addr.s_addr = ip4->ip_addr;
|
||||
remote.u.sin.sin_port = ip4->udp_port;
|
||||
/* we only care about UDP binds */
|
||||
if (bind->ll != GPRS_NS2_LL_UDP)
|
||||
continue;
|
||||
|
||||
nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
|
||||
if (!nsvc) {
|
||||
nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
|
||||
if (!nsvc) {
|
||||
/* TODO: add to a list to send back a NS-STATUS */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* update data / signalling weight */
|
||||
nsvc->data_weight = ip4->data_weight;
|
||||
nsvc->sig_weight = ip4->sig_weight;
|
||||
nsvc->sns_only = false;
|
||||
}
|
||||
|
||||
/* iterate over all remote IPv4 endpoints */
|
||||
for (i = 0; i < gss->remote.num_ip6; i++) {
|
||||
const struct gprs_ns_ie_ip6_elem *ip6 = &gss->remote.ip6[i];
|
||||
|
||||
remote.u.sin6.sin6_family = AF_INET6;
|
||||
remote.u.sin6.sin6_addr = ip6->ip_addr;
|
||||
remote.u.sin6.sin6_port = ip6->udp_port;
|
||||
|
||||
/* we only care about UDP binds */
|
||||
nsvc = nsvc_for_bind_and_remote(nse, bind, &remote);
|
||||
if (!nsvc) {
|
||||
nsvc = gprs_ns2_ip_connect_inactive(bind, &remote, nse, 0);
|
||||
if (!nsvc) {
|
||||
/* TODO: add to a list to send back a NS-STATUS */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* update data / signalling weight */
|
||||
nsvc->data_weight = ip6->data_weight;
|
||||
nsvc->sig_weight = ip6->sig_weight;
|
||||
nsvc->sns_only = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ns2_sns_st_local_procedure(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
|
||||
|
@ -1523,6 +1590,18 @@ static void ns2_sns_st_local_procedure(struct osmo_fsm_inst *fi, uint32_t event,
|
|||
}
|
||||
|
||||
switch (gss->current_procedure->procedure) {
|
||||
case SNS_PROC_ADD:
|
||||
switch (gss->family) {
|
||||
case AF_INET:
|
||||
add_ip4_elem(gss, &gss->local, &gss->current_procedure->ip4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
add_ip6_elem(gss, &gss->local, &gss->current_procedure->ip6);
|
||||
break;
|
||||
}
|
||||
create_nsvc_for_new_sbind(gss, gss->current_procedure->sbind);
|
||||
gprs_ns2_start_alive_all_nsvcs(nse);
|
||||
break;
|
||||
case SNS_PROC_CHANGE_WEIGHT:
|
||||
switch (gss->family) {
|
||||
case AF_INET:
|
||||
|
@ -1758,7 +1837,6 @@ static int ns2_update_weight_entry(struct ns2_sns_state *gss, struct ns2_sns_bin
|
|||
OSMO_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
|
||||
enum sns_procedure procedure_type)
|
||||
{
|
||||
|
@ -1766,10 +1844,11 @@ static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sb
|
|||
const struct osmo_sockaddr *saddr;
|
||||
saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
|
||||
|
||||
if (saddr->u.sa.sa_family != gss->family)
|
||||
return;
|
||||
OSMO_ASSERT(saddr->u.sa.sa_family == gss->family);
|
||||
|
||||
switch (procedure_type) {
|
||||
case SNS_PROC_ADD:
|
||||
break;
|
||||
case SNS_PROC_CHANGE_WEIGHT:
|
||||
llist_for_each_entry(procedure, &gss->procedures, list) {
|
||||
if (procedure->sbind == sbind && procedure->procedure == procedure_type &&
|
||||
|
@ -1791,11 +1870,16 @@ static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sb
|
|||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
procedure = talloc_zero(gss, struct ns2_sns_procedure);
|
||||
if (!procedure)
|
||||
return;
|
||||
|
||||
llist_add_tail(&procedure->list, &gss->procedures);
|
||||
procedure->sbind = sbind;
|
||||
procedure->procedure = procedure_type;
|
||||
procedure->sig_weight = sbind->bind->sns_sig_weight;
|
||||
|
@ -1803,7 +1887,6 @@ static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sb
|
|||
|
||||
switch(gss->family) {
|
||||
case AF_INET:
|
||||
|
||||
procedure->ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
|
||||
procedure->ip4.udp_port = saddr->u.sin.sin_port;
|
||||
procedure->ip4.sig_weight = sbind->bind->sns_sig_weight;
|
||||
|
@ -1820,18 +1903,43 @@ static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sb
|
|||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
llist_add_tail(&procedure->list, &gss->procedures);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (gss->nse->bss_sns_fi->state == GPRS_SNS_ST_CONFIGURED) {
|
||||
osmo_fsm_inst_state_chg(gss->nse->bss_sns_fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
|
||||
gss->nse->nsi->timeout[NS_TOUT_TSNS_PROV], 5);
|
||||
}
|
||||
}
|
||||
|
||||
/* add an entrypoint to sns_endpoints */
|
||||
static int ns2_sns_add_elements(struct ns2_sns_state *gss, struct ns2_sns_bind *sbind,
|
||||
struct ns2_sns_elems *elems)
|
||||
{
|
||||
const struct osmo_sockaddr *saddr;
|
||||
struct gprs_ns_ie_ip4_elem ip4;
|
||||
struct gprs_ns_ie_ip6_elem ip6;
|
||||
int rc = -1;
|
||||
|
||||
saddr = gprs_ns2_ip_bind_sockaddr(sbind->bind);
|
||||
OSMO_ASSERT(saddr->u.sa.sa_family == gss->family);
|
||||
|
||||
switch (gss->family) {
|
||||
case AF_INET:
|
||||
ip4.ip_addr = saddr->u.sin.sin_addr.s_addr;
|
||||
ip4.udp_port= saddr->u.sin.sin_port;
|
||||
ip4.sig_weight = sbind->bind->sns_sig_weight;
|
||||
ip4.data_weight = sbind->bind->sns_data_weight;
|
||||
rc = add_ip4_elem(gss, elems, &ip4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(&ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr));
|
||||
ip6.udp_port= saddr->u.sin.sin_port;
|
||||
ip6.sig_weight = sbind->bind->sns_sig_weight;
|
||||
ip6.data_weight = sbind->bind->sns_data_weight;
|
||||
rc = add_ip6_elem(gss, elems, &ip6);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* common allstate-action for both roles */
|
||||
static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
|
@ -1846,15 +1954,63 @@ static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void
|
|||
sbind = data;
|
||||
switch (fi->state) {
|
||||
case GPRS_SNS_ST_UNCONFIGURED:
|
||||
if (gss->role == GPRS_SNS_ROLE_BSS)
|
||||
osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
|
||||
break;
|
||||
case GPRS_SNS_ST_BSS_SIZE:
|
||||
/* TODO: add the ip4 element to the list */
|
||||
switch (gss->family) {
|
||||
case AF_INET:
|
||||
if (gss->num_max_ip4_remote <= gss->local.num_ip4 ||
|
||||
gss->num_max_ip4_remote * (gss->local.num_ip4 + 1) > gss->num_max_nsvcs) {
|
||||
osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (gss->num_max_ip6_remote <= gss->local.num_ip6 ||
|
||||
gss->num_max_ip6_remote * (gss->local.num_ip6 + 1) > gss->num_max_nsvcs) {
|
||||
osmo_fsm_inst_dispatch(nse->bss_sns_fi, NS2_SNS_EV_REQ_SELECT_ENDPOINT, GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ns2_sns_add_elements(gss, sbind, &gss->local);
|
||||
break;
|
||||
case GPRS_SNS_ST_BSS_CONFIG_BSS:
|
||||
case GPRS_SNS_ST_BSS_CONFIG_SGSN:
|
||||
case GPRS_SNS_ST_CONFIGURED:
|
||||
/* TODO: add to SNS-IP procedure queue & add nsvc() */
|
||||
switch (gss->family) {
|
||||
case AF_INET:
|
||||
if (gss->num_max_ip4_remote <= gss->local.num_ip4) {
|
||||
LOGPFSML(fi, LOGL_ERROR,
|
||||
"NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
|
||||
nse->nsei, sbind->bind->name);
|
||||
return;
|
||||
}
|
||||
if (gss->remote.num_ip4 * (gss->local.num_ip4 + 1) > gss->num_max_nsvcs) {
|
||||
LOGPFSML(fi, LOGL_ERROR,
|
||||
"NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
|
||||
nse->nsei, sbind->bind->name);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (gss->num_max_ip6_remote <= gss->local.num_ip6) {
|
||||
LOGPFSML(fi, LOGL_ERROR,
|
||||
"NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
|
||||
nse->nsei, sbind->bind->name);
|
||||
return;
|
||||
}
|
||||
if (gss->remote.num_ip6 * (gss->local.num_ip6 + 1) > gss->num_max_nsvcs) {
|
||||
LOGPFSML(fi, LOGL_ERROR,
|
||||
"NSE %d: ignoring bind %s because there are too many endpoints for the SNS.\n",
|
||||
nse->nsei, sbind->bind->name);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ns2_sns_add_elements(gss, sbind, &gss->local_procedure);
|
||||
ns2_add_procedure(gss, sbind, SNS_PROC_ADD);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -1975,6 +2131,7 @@ static void ns2_sns_st_all_action_bss(struct osmo_fsm_inst *fi, uint32_t event,
|
|||
break;
|
||||
case NS2_SNS_EV_REQ_FREE_NSVCS:
|
||||
case NS2_SNS_EV_REQ_SELECT_ENDPOINT:
|
||||
/* TODO: keep the order of binds when data == GPRS_SNS_FLAG_KEEP_SELECT_ENDPOINT_ORDER */
|
||||
/* tear down previous state
|
||||
* gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */
|
||||
gss->reselection_running = true;
|
||||
|
|
Loading…
Reference in New Issue