pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-uecups/+/42458?usp=email )
Change subject: cups_client: Add commands to perform IPv6 SLAAC and obtain GTP tunnel IPv6 global info ......................................................................
cups_client: Add commands to perform IPv6 SLAAC and obtain GTP tunnel IPv6 global info
Change-Id: I1570ccf5f98ac98c1af467c48f42b6b54ac3911d --- M daemon/cups_client.c M daemon/gtp_endpoint.c M daemon/internal.h M ttcn3/UECUPS_Types.ttcn 4 files changed, 158 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-uecups refs/changes/58/42458/1
diff --git a/daemon/cups_client.c b/daemon/cups_client.c index e283f23..f7c6f1a 100644 --- a/daemon/cups_client.c +++ b/daemon/cups_client.c @@ -133,6 +133,92 @@ return jret; }
+json_t *gen_uecups_ep(const struct gtp_endpoint *ep) +{ + json_t *jret = json_object(); + char *addr_type; + char ip_str[32+1]; + uint16_t port; + + switch (ep->bind_addr.u.sa.sa_family) { + case AF_INET: + addr_type = "IPV4"; + osmo_hexdump_buf(ip_str, sizeof(ip_str), + (const unsigned char *)&ep->bind_addr.u.sin.sin_addr, + sizeof(ep->bind_addr.u.sin.sin_addr), + "", true); + break; + case AF_INET6: + addr_type = "IPV6"; + osmo_hexdump_buf(ip_str, sizeof(ip_str), + (const unsigned char *)&ep->bind_addr.u.sin6.sin6_addr, + sizeof(ep->bind_addr.u.sin6.sin6_addr), + "", true); + break; + default: + OSMO_ASSERT(0); + } + port = osmo_sockaddr_port(&ep->bind_addr.u.sa); + + json_object_set_new(jret, "addr_type", json_string(addr_type)); + json_object_set_new(jret, "ip", json_string(ip_str)); + json_object_set_new(jret, "Port", json_integer(port)); + + return jret; +} + +void cc_ipv6_slaac_ind(const struct gtp_tunnel *t) +{ + struct gtp_endpoint *ep = t->gtp_ep; + struct cups_client *cc; + json_t *jtx = json_object(); + json_t *jslaac_ind = json_object(); + json_t *jep; + char *json_str = NULL; + unsigned int json_strlen; + char ipv6_str[32+1]; + + LOGP(DUECUPS, LOGL_INFO, "ipv6_slaac_ind\n"); + + OSMO_ASSERT(jtx); + OSMO_ASSERT(jslaac_ind); + + json_object_set_new(jtx, "ipv6_slaac_ind", jslaac_ind); + + jep = gen_uecups_ep(ep); + if (!jep) + goto free_ret; + json_object_set_new(jslaac_ind, "local_gtp_ep", jep); + + json_object_set_new(jslaac_ind, "rx_teid", json_integer(t->rx_teid)); + + osmo_hexdump_buf(ipv6_str, sizeof(ipv6_str), + (const unsigned char *)&t->user_addr_ipv6_prefix.u.sin6.sin6_addr, + 8, "", true); + json_object_set_new(jslaac_ind, "ipv6_prefix", json_string(ipv6_str)); + + osmo_hexdump_buf(ipv6_str, sizeof(ipv6_str), + (const unsigned char *)&t->user_addr.u.sin6.sin6_addr, + sizeof(t->user_addr.u.sin6.sin6_addr), + "", true); + json_object_set_new(jslaac_ind, "ipv6_user_addr", json_string(ipv6_str)); + + json_str = json_dumps(jtx, JSON_SORT_KEYS); + if (!json_str) { + LOGT(t, LOGL_ERROR, "Error encoding JSON\n"); + goto free_ret; + } + json_strlen = strlen(json_str); + + llist_for_each_entry(cc, &t->d->cups_clients, list) + cups_client_tx_json_str(cc, json_str, json_strlen); + +free_ret: + if (jtx) + json_decref(jtx); + free(json_str); +} + static int parse_ep(struct osmo_sockaddr *out, json_t *in) { json_t *jaddr_type, *jport, *jip; @@ -525,6 +611,38 @@ return 0; }
+static int cups_client_handle_ipv6_slaac(struct cups_client *cc, json_t *cmd) +{ + struct osmo_sockaddr local_ep_addr; + json_t *jlocal_gtp_ep, *jrx_teid; + uint32_t rx_teid; + int rc; + + jlocal_gtp_ep = json_object_get(cmd, "local_gtp_ep"); + jrx_teid = json_object_get(cmd, "rx_teid"); + + if (!jlocal_gtp_ep || !jrx_teid) + return -EINVAL; + + if (!json_is_object(jlocal_gtp_ep) || !json_is_integer(jrx_teid)) + return -EINVAL; + + rc = parse_ep(&local_ep_addr, jlocal_gtp_ep); + if (rc < 0) + return rc; + rx_teid = json_integer_value(jrx_teid); + + rc = gtp_tunnel_tx_icmpv6_rs(g_daemon, &local_ep_addr, rx_teid); + if (rc < 0) { + LOGCC(cc, LOGL_NOTICE, "Failed to start IPv6 SLAAC\n"); + cups_client_tx_json(cc, gen_uecups_result("ipv6_slaac_res", "ERR_IPv6_SLAAC_FAILED")); + } else { + cups_client_tx_json(cc, gen_uecups_result("ipv6_slaac_res", "OK")); + } + + return 0; +} + static int cups_client_handle_json(struct cups_client *cc, json_t *jroot) { void *iter; @@ -549,6 +667,8 @@ rc = cups_client_handle_start_program(cc, cmd); } else if (!strcmp(key, "reset_all_state")) { rc = cups_client_handle_reset_all_state(cc, cmd); + } else if (!strcmp(key, "ipv6_slaac")) { + rc = cups_client_handle_ipv6_slaac(cc, cmd); } else { LOGCC(cc, LOGL_NOTICE, "Unknown command '%s' received\n", key); return -EINVAL; diff --git a/daemon/gtp_endpoint.c b/daemon/gtp_endpoint.c index 8d3c2b0..29422a1 100644 --- a/daemon/gtp_endpoint.c +++ b/daemon/gtp_endpoint.c @@ -86,6 +86,9 @@ inet_ntop(AF_INET6, &t->user_addr.u.sin6.sin6_addr, &ip6strbuf[1][0], sizeof(ip6strbuf[1])), strerror(-rc)); } + + /* Notify cups_client about the new available IPv6 prefix and global address: */ + cc_ipv6_slaac_ind(t); } } } diff --git a/daemon/internal.h b/daemon/internal.h index 2394e2c..5d4b832 100644 --- a/daemon/internal.h +++ b/daemon/internal.h @@ -155,6 +155,7 @@
struct osmo_stream_srv_link *cups_srv_link_create(struct gtp_daemon *d); void child_terminated(struct gtp_daemon *d, int pid, int status); +void cc_ipv6_slaac_ind(const struct gtp_tunnel *t); json_t *gen_uecups_result(const char *name, const char *res); int cups_client_tx_json(struct cups_client *cc, json_t *jtx);
diff --git a/ttcn3/UECUPS_Types.ttcn b/ttcn3/UECUPS_Types.ttcn index 29fa738..45466c8 100644 --- a/ttcn3/UECUPS_Types.ttcn +++ b/ttcn3/UECUPS_Types.ttcn @@ -101,6 +101,27 @@ UECUPS_Result result };
+/* Perform IPv6 SLAAC on GTP-U tunnel to obtain IPv6 global IPv6 address for the UE */ +type record UECUPS_IPv6SLAAC { + /* local GTP endpoint + TEID are sufficient for unique identification */ + UECUPS_SockAddr local_gtp_ep, + uint32_t rx_teid +}; + +type record UECUPS_IPv6SLAACRes { + UECUPS_Result result +}; + +/* Daemon informs us that IPv6 SLAAC was terminated */ +type record UECUPS_IPv6SLAACInd { + /* local GTP endpoint + TEID are sufficient for unique identification */ + UECUPS_SockAddr local_gtp_ep, + uint32_t rx_teid, + OCT8 ipv6_prefix, + OCT16 ipv6_user_addr +}; + + type union PDU_UECUPS { UECUPS_CreateTun create_tun, UECUPS_CreateTunRes create_tun_res, @@ -113,7 +134,11 @@ UECUPS_ProgramTermInd program_term_ind,
UeCUPS_ResetAllState reset_all_state, - UeCUPS_ResetAllStateRes reset_all_state_res + UeCUPS_ResetAllStateRes reset_all_state_res, + + UECUPS_IPv6SLAAC ipv6_slaac, + UECUPS_IPv6SLAACRes ipv6_slaac_res, + UECUPS_IPv6SLAACInd ipv6_slaac_ind };
@@ -202,4 +227,12 @@ tun_netns_name := tun_netns_name };
+template (value) UECUPS_IPv6SLAAC +ts_UECUPS_IPv6SLAAC(template (value) UECUPS_SockAddr local_gtp_ep, + template (value) uint32_t rx_teid) +:= { + local_gtp_ep := local_gtp_ep, + rx_teid := rx_teid +}; + } with { encode "JSON" };