This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
lynxis lazus gerrit-no-reply at lists.osmocom.orglynxis lazus has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/23187 )
Change subject: WIP: gprs_ns2: sns: implement local procedure change weight
......................................................................
WIP: gprs_ns2: sns: implement local procedure change weight
Change-Id: Icec4dabb46bc198f68f91bfe09ba279fbe68d454
---
M src/gb/gprs_ns2.c
M src/gb/gprs_ns2_internal.h
M src/gb/gprs_ns2_sns.c
3 files changed, 422 insertions(+), 19 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/87/23187/1
diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c
index c56b0b5..e3d3298 100644
--- a/src/gb/gprs_ns2.c
+++ b/src/gb/gprs_ns2.c
@@ -1289,6 +1289,7 @@
nsi->timeout[NS_TOUT_TSNS_PROV] = 3; /* 1..10 */
nsi->timeout[NS_TOUT_TSNS_SIZE_RETRIES] = 3;
nsi->timeout[NS_TOUT_TSNS_CONFIG_RETRIES] = 3;
+ nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES] = 3;
return nsi;
}
diff --git a/src/gb/gprs_ns2_internal.h b/src/gb/gprs_ns2_internal.h
index 1bef753..35933aa 100644
--- a/src/gb/gprs_ns2_internal.h
+++ b/src/gb/gprs_ns2_internal.h
@@ -33,8 +33,8 @@
struct gprs_ns2_vc_driver;
struct gprs_ns2_vc_bind;
-#define NS_TIMERS_COUNT 10
-#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries)"
+#define NS_TIMERS_COUNT 11
+#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries|tsns-prov|tsns-size-retries|tsns-config-retries|tsns-procedures-retries)"
#define NS_TIMERS_HELP \
"(un)blocking Timer (Tns-block) timeout\n" \
"(un)blocking Timer (Tns-block) number of retries\n" \
@@ -46,6 +46,7 @@
"SNS Provision Timer (Tsns-prov) timeout\n" \
"SNS Size number of retries\n" \
"SNS Config number of retries\n" \
+ "SNS Procedures number of retries\n" \
/* Educated guess - LLC user payload is 1500 bytes plus possible headers */
#define NS_ALLOC_SIZE 3072
@@ -62,6 +63,7 @@
NS_TOUT_TSNS_PROV,
NS_TOUT_TSNS_SIZE_RETRIES,
NS_TOUT_TSNS_CONFIG_RETRIES,
+ NS_TOUT_TSNS_PROCEDURES_RETRIES,
};
enum nsvc_timer_mode {
diff --git a/src/gb/gprs_ns2_sns.c b/src/gb/gprs_ns2_sns.c
index 86b4fdf..3517378 100644
--- a/src/gb/gprs_ns2_sns.c
+++ b/src/gb/gprs_ns2_sns.c
@@ -35,6 +35,8 @@
* - No concurrent dual stack. It supports either IPv4 or IPv6, but not both at the same time.
* - SNS Add/Change/Delete: Doesn't answer on the same NSVC as received SNS ADD/CHANGE/DELETE PDUs.
* - SNS Add/Change/Delete: Doesn't communicated the failed IPv4/IPv6 entries on the SNS_ACK.
+ *
+ * -
*/
#include <errno.h>
@@ -67,6 +69,7 @@
GPRS_SNS_ST_CONFIG_BSS, /*!< SNS-CONFIG procedure (BSS->SGSN) ongoing */
GPRS_SNS_ST_CONFIG_SGSN, /*!< SNS-CONFIG procedure (SGSN->BSS) ongoing */
GPRS_SNS_ST_CONFIGURED,
+ GPRS_SNS_ST_LOCAL_PROCEDURE, /*!< in process of a ADD/DEL/UPDATE procedure towards SGSN (BSS->SGSN) */
};
enum gprs_sns_event {
@@ -79,10 +82,12 @@
GPRS_SNS_EV_RX_ADD,
GPRS_SNS_EV_RX_DELETE,
GPRS_SNS_EV_RX_CHANGE_WEIGHT,
+ GPRS_SNS_EV_RX_ACK,
GPRS_SNS_EV_REQ_NO_NSVC,
GPRS_SNS_EV_REQ_NSVC_ALIVE, /*!< a NS-VC became alive */
GPRS_SNS_EV_REQ_ADD_BIND,
GPRS_SNS_EV_REQ_DELETE_BIND,
+ GPRS_SNS_EV_REQ_CHANGE_WEIGHT, /*!< a bind changed its weight */
};
static const struct value_string gprs_sns_event_names[] = {
@@ -95,13 +100,21 @@
{ GPRS_SNS_EV_RX_ADD, "RX_ADD" },
{ GPRS_SNS_EV_RX_DELETE, "RX_DELETE" },
{ GPRS_SNS_EV_RX_CHANGE_WEIGHT, "RX_CHANGE_WEIGHT" },
+ { GPRS_SNS_EV_RX_ACK, "RX_ACK" },
{ GPRS_SNS_EV_REQ_NO_NSVC, "REQ_NO_NSVC" },
{ GPRS_SNS_EV_REQ_NSVC_ALIVE, "REQ_NSVC_ALIVE"},
{ GPRS_SNS_EV_REQ_ADD_BIND, "REQ_ADD_BIND"},
{ GPRS_SNS_EV_REQ_DELETE_BIND, "REQ_DELETE_BIND"},
+ { GPRS_SNS_EV_REQ_CHANGE_WEIGHT, "REQ_UPDATE_WEIGHT"},
{ 0, NULL }
};
+enum sns_procedure {
+ SNS_ADD,
+ SNS_DEL,
+ SNS_CHANGE_WEIGHT,
+};
+
struct sns_endpoint {
struct llist_head list;
struct osmo_sockaddr saddr;
@@ -112,6 +125,13 @@
struct gprs_ns2_vc_bind *bind;
};
+struct ns2_sns_procedure {
+ struct llist_head list;
+ struct gprs_ns2_vc_bind *bind;
+ void *endpoint;
+ enum sns_procedure procedure;
+};
+
struct ns2_sns_state {
struct gprs_ns2_nse *nse;
@@ -133,12 +153,20 @@
struct sns_endpoint *initial;
/* all SNS PDU will be sent over this nsvc */
struct gprs_ns2_vc *sns_nsvc;
+
+ /* all pending local procedures*/
+ struct llist_head procedures;
+ /* all current procedure */
+ struct ns2_sns_procedure *current;
+
/* timer N */
int N;
/* true if at least one nsvc is alive */
bool alive;
/* alive timeout, to ensure at least one NSVC comes after X online */
struct osmo_timer_list alive_timeout;
+ /* valid transaction id to use for our procedures */
+ uint8_t trans_id;
/* local configuration to send to the remote end */
struct gprs_ns_ie_ip4_elem *ip4_local;
@@ -163,12 +191,42 @@
unsigned int num_ip6_remote;
};
+static void add_local_procedure(struct ns2_sns_state *gss, enum sns_procedure procedure, void *endpoint);
+
static inline struct gprs_ns2_nse *nse_inst_from_fi(struct osmo_fsm_inst *fi)
{
struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
return gss->nse;
}
+static struct gprs_ns_ie_ip4_elem *ip4_elem_by_saddr(struct gprs_ns_ie_ip4_elem *ip4, size_t num, const struct osmo_sockaddr *saddr)
+{
+ if (saddr->u.sa.sa_family != AF_INET)
+ return NULL;
+
+ for (size_t i = 0; i < num; i++) {
+ if (ip4[i].ip_addr == saddr->u.sin.sin_addr.s_addr &&
+ ip4->udp_port == saddr->u.sin.sin_port)
+ return &ip4[i];
+ }
+
+ return NULL;
+}
+
+static struct gprs_ns_ie_ip6_elem *ip6_elem_by_saddr(struct gprs_ns_ie_ip6_elem *ip6, size_t num, const struct osmo_sockaddr *saddr)
+{
+ if (saddr->u.sa.sa_family != AF_INET6)
+ return NULL;
+
+ for (size_t i = 0; i < num; i++) {
+ if (memcmp(&ip6[i].ip_addr, &saddr->u.sin6.sin6_addr, sizeof(struct in6_addr)) == 0 &&
+ ip6->udp_port == saddr->u.sin6.sin6_port)
+ return &ip6[i];
+ }
+
+ return NULL;
+}
+
/* helper function to compute the sum of all (data or signaling) weights */
static int ip4_weight_sum(const struct gprs_ns_ie_ip4_elem *ip4, unsigned int num,
bool data_weight)
@@ -283,6 +341,8 @@
static void ns2_clear_ipv46_entries(struct ns2_sns_state *gss)
{
+ struct ns2_sns_procedure *procedure, *tmp;
+
TALLOC_FREE(gss->ip4_local);
TALLOC_FREE(gss->ip4_remote);
TALLOC_FREE(gss->ip6_local);
@@ -292,6 +352,15 @@
gss->num_ip4_remote = 0;
gss->num_ip6_local = 0;
gss->num_ip6_remote = 0;
+
+ if (gss->current)
+ talloc_free(gss->current);
+ gss->current = NULL;
+
+ llist_for_each_entry_safe(procedure, tmp, &gss->procedures, list) {
+ llist_del(&procedure->list);
+ talloc_free(&procedure);
+ }
}
static void ns2_vc_create_ip(struct osmo_fsm_inst *fi, struct gprs_ns2_nse *nse, const struct osmo_sockaddr *remote,
@@ -433,6 +502,47 @@
return 0;
}
+/* Add a given local IPv4 element to gprs_sns_state */
+static int add_local_ip4_elem(struct ns2_sns_state *gss, uint32_t ip_addr, uint16_t port)
+{
+ unsigned int i;
+
+ if (gss->num_ip4_local + gss->num_ip4_remote >= gss->num_max_nsvcs)
+ return -NS_CAUSE_INVAL_NR_NS_VC;
+
+ /* check for duplicates */
+ for (i = 0; i < gss->num_ip4_local; i++) {
+ if (memcmp(&gss->ip4_local[i], ip4, sizeof(*ip4)))
+ continue;
+ /* TODO: log message duplicate */
+ /* TODO: check if this is the correct cause code */
+ return -NS_CAUSE_PROTO_ERR_UNSPEC;
+ }
+
+ gss->ip4_local = talloc_realloc(gss, gss->ip4_local, struct gprs_ns_ie_ip4_elem,
+ gss->num_ip4_local+1);
+ gss->ip4_local[gss->num_ip4_local] = *ip4;
+ gss->num_ip4_local += 1;
+ return 0;
+}
+
+/* Remove a given local IPv4 element from gprs_sns_state */
+static int remove_local_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
+{
+ unsigned int i;
+
+ for (i = 0; i < gss->num_ip4_local; i++) {
+ if (memcmp(&gss->ip4_local[i], ip4, sizeof(*ip4)))
+ continue;
+ /* all array elements < i remain as they are; all > i are shifted left by one */
+ memmove(&gss->ip4_local[i], &gss->ip4_local[i+1], gss->num_ip4_local-i-1);
+ gss->num_ip4_local -= 1;
+ return 0;
+ }
+ return -1;
+}
+
+
/* Add a given remote IPv4 element to gprs_sns_state */
static int add_remote_ip4_elem(struct ns2_sns_state *gss, const struct gprs_ns_ie_ip4_elem *ip4)
{
@@ -743,7 +853,7 @@
if (old_state != GPRS_SNS_ST_SIZE)
gss->N = 0;
-
+ gss->trans_id = 0;
gss->alive = false;
ns2_clear_ipv46_entries(gss);
@@ -1149,19 +1259,19 @@
if (TLVP_PRESENT(tp, NS_IE_IPv4_LIST)) {
v4_list = (const struct gprs_ns_ie_ip4_elem *) TLVP_VAL(tp, NS_IE_IPv4_LIST);
num_v4 = TLVP_LEN(tp, NS_IE_IPv4_LIST) / sizeof(*v4_list);
- for ( i = 0; i < num_v4; i++) {
+ for (i = 0; i < num_v4; i++) {
rc = do_sns_delete(fi, &v4_list[i], NULL);
if (rc < 0) {
cause = -rc;
/* continue to delete others */
}
}
+
if (cause != 0xff) {
/* TODO: create list of not-deleted and return it */
ns2_tx_sns_ack(gss->sns_nsvc, trans_id, &cause, NULL, 0, NULL, 0);
return;
}
-
} else if (TLVP_PRESENT(tp, NS_IE_IP_ADDR) && TLVP_LEN(tp, NS_IE_IP_ADDR) == 5) {
/* delete all NS-VCs for given IPv4 address */
const uint8_t *ie = TLVP_VAL(tp, NS_IE_IP_ADDR);
@@ -1302,6 +1412,7 @@
static void ns2_sns_st_configured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
+ struct gprs_ns2_inst *nsi = nse_inst_from_fi(fi)->nsi;
struct tlv_parsed *tp = data;
switch (event) {
@@ -1317,13 +1428,103 @@
case GPRS_SNS_EV_REQ_NSVC_ALIVE:
osmo_timer_del(&gss->alive_timeout);
break;
+ case GPRS_SNS_EV_REQ_CHANGE_WEIGHT:
+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);
+ break;
}
}
static void ns2_sns_st_configured_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
{
struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
- ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);
+ if (old_state != GPRS_SNS_ST_LOCAL_PROCEDURE)
+ ns2_prim_status_ind(nse, NULL, 0, GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED);
+}
+
+static void ns2_sns_st_local_procedure_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
+{
+ struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
+ struct ns2_sns_procedure *current;
+
+ if (!gss->current) {
+ gss->current = llist_first_entry_or_null(&gss->procedures, struct ns2_sns_procedure, list);
+ if (!gss->current) {
+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
+ return;
+ }
+ llist_del(&gss->current->list);
+ }
+
+ current = gss->current;
+ switch (current->procedure) {
+ case SNS_ADD:
+ if (gss->ip == IPv4)
+ ns2_tx_sns_add(gss->sns_nsvc, gss->trans_id, current->endpoint, 1, NULL, 0);
+ else
+ ns2_tx_sns_add(gss->sns_nsvc, gss->trans_id, NULL, 0, current->endpoint, 1);
+ break;
+ case SNS_CHANGE_WEIGHT:
+ if (gss->ip == IPv4)
+ ns2_tx_sns_change_weight(gss->sns_nsvc, gss->trans_id, current->endpoint, 1, NULL, 0);
+ else
+ ns2_tx_sns_change_weight(gss->sns_nsvc, gss->trans_id, NULL, 0, current->endpoint, 1);
+ break;
+ case SNS_DEL:
+ if (gss->ip == IPv4)
+ ns2_tx_sns_del(gss->sns_nsvc, gss->trans_id, current->endpoint, 1, NULL, 0);
+ else
+ ns2_tx_sns_del(gss->sns_nsvc, gss->trans_id, NULL, 0, current->endpoint, 1);
+ break;
+ }
+}
+
+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;
+ struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
+ struct gprs_ns2_inst *nsi = nse->nsi;
+ struct tlv_parsed *tp = data;
+ uint8_t trans_id;
+
+ switch (event) {
+ case GPRS_SNS_EV_RX_ADD:
+ ns2_sns_st_configured_add(fi, gss, tp);
+ break;
+ case GPRS_SNS_EV_RX_DELETE:
+ ns2_sns_st_configured_delete(fi, gss, tp);
+ break;
+ case GPRS_SNS_EV_RX_CHANGE_WEIGHT:
+ ns2_sns_st_configured_change(fi, gss, tp);
+ break;
+ case GPRS_SNS_EV_REQ_NSVC_ALIVE:
+ osmo_timer_del(&gss->alive_timeout);
+ break;
+ case GPRS_SNS_EV_RX_ACK:
+ /* the transaction id has been already checked */
+ trans_id = tlvp_val8(tp, NS_IE_TRANS_ID, 0);
+ if (trans_id != gss->trans_id) {
+ LOGPFSML(fi, LOGL_DEBUG, "NSEI=%u Rx SNS ACK with invalid transaction id %d. Valid %d\n",
+ nse->nsei, trans_id, gss->trans_id);
+ break;
+ }
+
+ if (!TLVP_PRESENT(tp, NS_IE_CAUSE)) {
+ /* everything ok */
+ talloc_free(gss->current);
+ gss->current = NULL;
+ gss->trans_id++;
+ if (llist_empty(&gss->procedures)) {
+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIGURED, 0, 0);
+ } else {
+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE,
+ nsi->timeout[NS_TOUT_TSNS_PROV], GPRS_SNS_ST_LOCAL_PROCEDURE);
+ }
+ return;
+ }
+
+ /* what happened, when rejected? remove the bind? */
+ break;
+ }
}
static const struct osmo_fsm_state ns2_sns_bss_states[] = {
@@ -1356,9 +1557,10 @@
.in_event_mask = S(GPRS_SNS_EV_RX_CONFIG) |
S(GPRS_SNS_EV_RX_CONFIG_END),
.out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
+ S(GPRS_SNS_ST_SIZE) |
S(GPRS_SNS_ST_CONFIG_SGSN) |
S(GPRS_SNS_ST_CONFIGURED) |
- S(GPRS_SNS_ST_SIZE),
+ S(GPRS_SNS_ST_LOCAL_PROCEDURE),
.name = "CONFIG_SGSN",
.action = ns2_sns_st_config_sgsn,
.onenter = ns2_sns_st_config_sgsn_onenter,
@@ -1367,13 +1569,30 @@
.in_event_mask = S(GPRS_SNS_EV_RX_ADD) |
S(GPRS_SNS_EV_RX_DELETE) |
S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |
+ S(GPRS_SNS_EV_REQ_CHANGE_WEIGHT) |
S(GPRS_SNS_EV_REQ_NSVC_ALIVE),
.out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
- S(GPRS_SNS_ST_SIZE),
+ S(GPRS_SNS_ST_SIZE) |
+ S(GPRS_SNS_ST_LOCAL_PROCEDURE),
.name = "CONFIGURED",
.action = ns2_sns_st_configured,
.onenter = ns2_sns_st_configured_onenter,
},
+ [GPRS_SNS_ST_LOCAL_PROCEDURE] = {
+ .in_event_mask = S(GPRS_SNS_EV_RX_ADD) |
+ S(GPRS_SNS_EV_RX_DELETE) |
+ S(GPRS_SNS_EV_RX_CHANGE_WEIGHT) |
+ S(GPRS_SNS_EV_RX_ACK) |
+ S(GPRS_SNS_EV_REQ_CHANGE_WEIGHT) |
+ S(GPRS_SNS_EV_REQ_NSVC_ALIVE),
+ .out_state_mask = S(GPRS_SNS_ST_UNCONFIGURED) |
+ S(GPRS_SNS_ST_SIZE) |
+ S(GPRS_SNS_ST_CONFIGURED) |
+ S(GPRS_SNS_ST_LOCAL_PROCEDURE),
+ .name = "LOCAL_PROCEDURE",
+ .action = ns2_sns_st_local_procedure,
+ .onenter = ns2_sns_st_local_procedure_onenter,
+ },
};
/* timer to ensure the SNS doesn't configure NSVC, but then no NSVC come alive afterwards */
@@ -1419,16 +1638,93 @@
osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_CONFIG_SGSN, nsi->timeout[NS_TOUT_TSNS_PROV], 3);
}
break;
+ case GPRS_SNS_ST_LOCAL_PROCEDURE:
+ if (gss->N >= nsi->timeout[NS_TOUT_TSNS_PROCEDURES_RETRIES]) {
+ LOGPFSML(fi, LOGL_ERROR, "NSE %d: SNS Procedure retries failed. Selecting next IP-SNS endpoint.\n", nse->nsei);
+ osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
+ } else {
+ osmo_fsm_inst_state_chg(fi, GPRS_SNS_ST_LOCAL_PROCEDURE, nsi->timeout[NS_TOUT_TSNS_PROV],
+ fi->T);
+ }
}
return 0;
}
+/* create a local endpoint from sns_bind */
+static void *ns2_create_local_endpoint(struct ns2_sns_state *gss, struct ns2_sns_bind *sns_bind)
+{
+ struct osmo_sockaddr *local = NULL, *remote = NULL;
+ const struct osmo_sockaddr *sa;
+ struct gprs_ns_ie_ip4_elem *ip4;
+ struct gprs_ns_ie_ip6_elem *ip6;
+
+ sa = gprs_ns2_ip_bind_sockaddr(sns_bind->bind);
+ if (!sa)
+ return NULL;
+
+ switch (sa->u.sa.sa_family) {
+ case AF_INET:
+ if (sa->u.sin.sin_addr.s_addr == 0) {
+ if (osmo_sockaddr_local_ip(local, &gss->initial->saddr))
+ return NULL;
+ sa = local;
+ }
+
+ ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, sa);
+ if (ip4) {
+ return NULL;
+ } else {
+ // TODO: use memmov/realloc
+ add_local_ip4_elem()
+ ip4 = talloc_zero(gss, struct gprs_ns_ie_ip4_elem);
+ if (!ip4)
+ return NULL;
+ }
+
+ ip4->ip_addr = sa->u.sin.sin_addr.s_addr;
+ ip4->udp_port = sa->u.sin.sin_port;
+ ip4->data_weight = sns_bind->bind->sns_data_weight;
+ ip4->sig_weight = sns_bind->bind->sns_sig_weight;
+ // TODO: add to local endpoints
+ return ip4;
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sin6.sin6_addr)) {
+ if (osmo_sockaddr_local_ip(local, remote))
+ return NULL;
+ sa = local;
+ }
+
+ ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, sa);
+ if (ip6) {
+ return NULL;
+ } else {
+ ip6 = talloc_zero(gss, struct gprs_ns_ie_ip6_elem);
+ if (!ip6)
+ return NULL;
+ }
+
+ memcpy(&ip6->ip_addr, &sa->u.sin6.sin6_addr, sizeof(struct in6_addr));
+ ip6->udp_port = sa->u.sin6.sin6_port;
+ ip6->data_weight = sns_bind->bind->sns_data_weight;
+ ip6->sig_weight = sns_bind->bind->sns_sig_weight;
+ // TODO: add to local endpoints
+ return ip6;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+
+ return NULL;
+}
+
static void ns2_sns_st_all_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct ns2_sns_state *gss = (struct ns2_sns_state *) fi->priv;
struct gprs_ns2_nse *nse = nse_inst_from_fi(fi);
struct ns2_sns_bind *sbind;
struct gprs_ns2_vc *nsvc, *nsvc2;
+ const struct osmo_sockaddr *sa;
+ void *endpoint = NULL;
/* reset when receiving GPRS_SNS_EV_REQ_NO_NSVC */
switch (event) {
@@ -1468,17 +1764,30 @@
break;
case GPRS_SNS_EV_REQ_ADD_BIND:
sbind = data;
+ // free sbind or llist_add_tail(&tmp->list, &gss->binds);
+ // bind to remote
switch (fi->state) {
case GPRS_SNS_ST_UNCONFIGURED:
+ llist_add_tail(&sbind->list, &gss->binds);
osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_SELECT_ENDPOINT, NULL);
break;
case GPRS_SNS_ST_SIZE:
- /* TODO: add the ip4 element to the list */
+ endpoint = ns2_create_local_endpoint(gss, sbind);
+ if (!endpoint) {
+ talloc_free(sbind);
+ return;
+ }
+ // TODO add to endpoints
break;
case GPRS_SNS_ST_CONFIG_BSS:
case GPRS_SNS_ST_CONFIG_SGSN:
case GPRS_SNS_ST_CONFIGURED:
- /* TODO: add to SNS-IP procedure queue & add nsvc() */
+ endpoint = ns2_create_local_endpoint(gss, sbind);
+ if (!endpoint) {
+ talloc_free(sbind);
+ return;
+ }
+ add_local_procedure(gss, SNS_ADD, endpoint);
break;
}
break;
@@ -1552,6 +1861,7 @@
gss->nse = nse;
INIT_LLIST_HEAD(&gss->sns_endpoints);
INIT_LLIST_HEAD(&gss->binds);
+ INIT_LLIST_HEAD(&gss->procedures);
osmo_timer_setup(&gss->alive_timeout, ns2_sns_timeout_alive_cb, fi);
return fi;
@@ -1610,8 +1920,7 @@
osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_CHANGE_WEIGHT, tp);
break;
case SNS_PDUT_ACK:
- LOGPFSML(fi, LOGL_NOTICE, "NSEI=%u Rx unsupported SNS PDU type %s\n", nsei,
- get_value_string(gprs_ns_pdu_strings, nsh->pdu_type));
+ osmo_fsm_inst_dispatch(fi, GPRS_SNS_EV_RX_ACK, tp);
break;
default:
LOGPFSML(fi, LOGL_ERROR, "NSEI=%u Rx unknown SNS PDU type %s\n", nsei,
@@ -1844,7 +2153,7 @@
return;
gss = nse->bss_sns_fi->priv;
- if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED)
+ if(nse->bss_sns_fi->state != GPRS_SNS_ST_CONFIGURED && nse->bss_sns_fi->state != GPRS_SNS_ST_LOCAL_PROCEDURE)
return;
if (alive == gss->alive)
@@ -1875,6 +2184,28 @@
}
}
+static void add_local_procedure(struct ns2_sns_state *gss, enum sns_procedure procedure, void *endpoint)
+{
+ struct ns2_sns_procedure *sns_proc;
+
+ switch (gss->nse->bss_sns_fi->state) {
+ case GPRS_SNS_ST_UNCONFIGURED:
+ case GPRS_SNS_ST_SIZE:
+ /* we can ignore the procedure as nothing yet configured */
+ return;
+ default:
+ break;
+ }
+
+ sns_proc = talloc_zero(gss, struct ns2_sns_procedure);
+ if (!sns_proc)
+ return;
+
+ sns_proc->endpoint = endpoint;
+ sns_proc->procedure = procedure;
+ llist_add(&sns_proc->list, &gss->procedures);
+}
+
int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse,
struct gprs_ns2_vc_bind *bind)
{
@@ -1899,15 +2230,13 @@
if (!tmp)
return -ENOMEM;
tmp->bind = bind;
- llist_add_tail(&tmp->list, &gss->binds);
-
osmo_fsm_inst_dispatch(nse->bss_sns_fi, GPRS_SNS_EV_REQ_ADD_BIND, tmp);
return 0;
}
/* Remove a bind from the SNS. All assosiated NSVC must be removed. */
int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse,
- struct gprs_ns2_vc_bind *bind)
+ struct gprs_ns2_vc_bind *bind)
{
struct ns2_sns_state *gss;
struct ns2_sns_bind *tmp, *tmp2;
@@ -1938,12 +2267,83 @@
return 0;
}
-/* Update SNS weights
- * \param[in] nsvc the NSVC which should be updated
+
+/* Update SNS weights for a bind (local endpoint). */
+static void _ns2_sns_update_weights(struct ns2_sns_state *gss, struct ns2_sns_bind *sns_bind) {
+ // find the ip_local entry by using the initial connection for 0.0.0.0
+ struct osmo_sockaddr *local = NULL, *remote = NULL;
+ const struct osmo_sockaddr *sa;
+ struct gprs_ns_ie_ip4_elem *ip4;
+ struct gprs_ns_ie_ip6_elem *ip6;
+
+ sa = gprs_ns2_ip_bind_sockaddr(sns_bind->bind);
+ if (!sa)
+ return;
+
+ switch (sa->u.sa.sa_family) {
+ case AF_INET:
+ if (sa->u.sin.sin_addr.s_addr == 0) {
+ if (osmo_sockaddr_local_ip(local, &gss->initial->saddr))
+ return;
+ ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, local);
+ } else {
+ ip4 = ip4_elem_by_saddr(gss->ip4_local, gss->num_ip4_local, sa);
+ }
+
+ /* TODO: check if this bind is about to be added */
+ if (!ip4)
+ return;
+
+ ip4->data_weight = sns_bind->bind->sns_data_weight;
+ ip4->sig_weight = sns_bind->bind->sns_sig_weight;
+ add_local_procedure(gss, SNS_CHANGE_WEIGHT, ip4);
+ osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, GPRS_SNS_EV_REQ_CHANGE_WEIGHT, ip4);
+ break;
+ case AF_INET6:
+ // in6addr_any
+ if (memcmp(&sa->u.sin6.sin6_addr, &in6addr_any, sizeof(struct in6_addr))) {
+ if (osmo_sockaddr_local_ip(local, remote))
+ return;
+ ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, local);
+ } else {
+ ip6 = ip6_elem_by_saddr(gss->ip6_local, gss->num_ip6_local, sa);
+ }
+
+ /* TODO: check if this bind is about to be added */
+ if (!ip6)
+ return;
+
+ ip6->data_weight = sns_bind->bind->sns_data_weight;
+ ip6->sig_weight = sns_bind->bind->sns_sig_weight;
+ add_local_procedure(gss, SNS_CHANGE_WEIGHT, ip6);
+ osmo_fsm_inst_dispatch(gss->nse->bss_sns_fi, GPRS_SNS_EV_REQ_CHANGE_WEIGHT, ip6);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ break;
+ }
+}
+
+/* Update SNS weights for a bind (local endpoint).
+ * \param[in] bind the bind which has been updated
*/
void ns2_sns_update_weights(struct gprs_ns2_vc_bind *bind)
{
- /* TODO: implement weights after binds per sns implemented */
+ struct ns2_sns_bind *sns_bind;
+ struct gprs_ns2_nse *nse;
+ struct ns2_sns_state *gss;
+ llist_for_each_entry(nse, &bind->nsi->nse, list) {
+ if (!nse->bss_sns_fi)
+ continue;
+
+ gss = nse->bss_sns_fi->priv;
+ llist_for_each_entry(sns_bind, &gss->binds, list) {
+ if (sns_bind->bind == bind) {
+ _ns2_sns_update_weights(gss, sns_bind);
+ break;
+ }
+ }
+ }
}
/* initialize osmo_ctx on main tread */
--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/23187
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Icec4dabb46bc198f68f91bfe09ba279fbe68d454
Gerrit-Change-Number: 23187
Gerrit-PatchSet: 1
Gerrit-Owner: lynxis lazus <lynxis at fe80.eu>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210302/a921d34f/attachment.htm>