pespin has uploaded this change for review.

View Change

cups_client: Add commands to perform IPv6 SLAAC and obtain GTP tunnel IPv6 global info

Change-Id: I917b5c70f143d48b55b4e270e24594d1a36f71aa
---
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/57/42457/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" };

To view, visit change 42457. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: newchange
Gerrit-Project: osmo-uecups
Gerrit-Branch: master
Gerrit-Change-Id: I917b5c70f143d48b55b4e270e24594d1a36f71aa
Gerrit-Change-Number: 42457
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>