diff options
author | Alexander Couzens <lynxis@fe80.eu> | 2021-06-06 18:57:56 +0200 |
---|---|---|
committer | Alexander Couzens <lynxis@fe80.eu> | 2021-08-06 20:06:14 +0200 |
commit | 32f30640445410286116891a4dac49260db70e4c (patch) | |
tree | abad074aab2c305314c6e1ee102662a924cd8dda | |
parent | 3a7ad1462c06ce88bccbdc6cbda4af073d61e751 (diff) |
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
-rw-r--r-- | src/gb/gprs_ns2_sns.c | 222 |
1 files changed, 188 insertions, 34 deletions
diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c index b22d6a4c..4fb364d6 100644 --- a/src/gb/gprs_ns2_sns.c +++ b/src/gb/gprs_ns2_sns.c @@ -1473,6 +1473,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 +1490,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; @@ -1505,7 +1570,6 @@ static void ns2_sns_st_local_procedure(struct osmo_fsm_inst *fi, uint32_t event, ns2_sns_st_configured_change(fi, gss, tp); break; case GPRS_SNS_EV_RX_ACK: - break; /* presence of trans_id is already checked here */ trans_id = tlvp_val8(tp, NS_IE_TRANS_ID, 0); if (trans_id != gss->current_procedure->trans_id) { @@ -1524,6 +1588,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: @@ -1759,7 +1835,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) { @@ -1767,10 +1842,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 && @@ -1792,39 +1868,37 @@ 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; - - procedure->sbind = sbind; - procedure->procedure = procedure_type; - procedure->sig_weight = sbind->bind->sns_sig_weight; - procedure->data_weight = sbind->bind->sns_data_weight; - - switch(gss->family) { - case AF_INET: + procedure = talloc_zero(gss, struct ns2_sns_procedure); + if (!procedure) + return; - 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; - procedure->ip4.data_weight = sbind->bind->sns_data_weight; - break; - case AF_INET6: + llist_add_tail(&procedure->list, &gss->procedures); + procedure->sbind = sbind; + procedure->procedure = procedure_type; + procedure->sig_weight = sbind->bind->sns_sig_weight; + procedure->data_weight = sbind->bind->sns_data_weight; - memcpy(&procedure->ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr)); - procedure->ip6.udp_port = saddr->u.sin.sin_port; - procedure->ip6.sig_weight = sbind->bind->sns_sig_weight; - procedure->ip6.data_weight = sbind->bind->sns_data_weight; - break; - default: - OSMO_ASSERT(0); - } + 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; + procedure->ip4.data_weight = sbind->bind->sns_data_weight; + break; + case AF_INET6: - llist_add_tail(&procedure->list, &gss->procedures); + memcpy(&procedure->ip6.ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr)); + procedure->ip6.udp_port = saddr->u.sin.sin_port; + procedure->ip6.sig_weight = sbind->bind->sns_sig_weight; + procedure->ip6.data_weight = sbind->bind->sns_data_weight; break; default: - return; + OSMO_ASSERT(0); } if (gss->nse->bss_sns_fi->state == GPRS_SNS_ST_CONFIGURED) { @@ -1833,6 +1907,37 @@ static void ns2_add_procedure(struct ns2_sns_state *gss, struct ns2_sns_bind *sb } } +/* 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) @@ -1847,15 +1952,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: - osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL); + if (gss->role == GPRS_SNS_ROLE_BSS) + osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_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, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, (void *) 1); + 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, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, (void *) 1); + 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; @@ -1977,6 +2130,7 @@ static void ns2_sns_st_all_action_bss(struct osmo_fsm_inst *fi, uint32_t event, break; case GPRS_SNS_EV_REQ_FREE_NSVCS: case GPRS_SNS_EV_REQ_SELECT_ENDPOINT: + /* TODO: keep the order of binds when data != NULL */ /* tear down previous state * gprs_ns2_free_nsvcs() will trigger NO_NSVC, prevent this from triggering a reselection */ gss->reselection_running = true; |