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>