pespin has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmo-uecups/+/42470?usp=email )


Change subject: Support configuring IPv4v6 tunnels
......................................................................

Support configuring IPv4v6 tunnels

Change-Id: Ic2da7a761a8df7e006fc02ca6557a48f371e4151
---
M daemon/cups_client.c
M daemon/daemon_vty.c
M daemon/gtp_endpoint.c
M daemon/gtp_tunnel.c
M daemon/internal.h
M ttcn3/UECUPS_Types.ttcn
6 files changed, 138 insertions(+), 51 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-uecups refs/changes/70/42470/1

diff --git a/daemon/cups_client.c b/daemon/cups_client.c
index f7c6f1a..a96861f 100644
--- a/daemon/cups_client.c
+++ b/daemon/cups_client.c
@@ -198,9 +198,9 @@
        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);
+                        (const unsigned char 
*)&t->user_addr_ipv6_global.u.sin6.sin6_addr,
+                        sizeof(t->user_addr_ipv6_global.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);
@@ -265,21 +265,26 @@
        return 0;
 }

-static int parse_eua(struct osmo_sockaddr *out, json_t *jip, json_t 
*jaddr_type)
+static int parse_eua(enum gtp1u_eua_type *user_addr_type, struct osmo_sockaddr 
*out4,
+                    struct osmo_sockaddr *out6, json_t *jip, json_t 
*jaddr_type)
 {
        const char *addr_type, *ip;
-       uint8_t buf[16];
-
+       uint8_t buf[20];
+       struct sockaddr_in *sin = &out4->u.sin;
+       struct sockaddr_in6 *sin6 = &out6->u.sin6;
        if (!json_is_string(jip) || !json_is_string(jaddr_type))
                return -EINVAL;

        addr_type = json_string_value(jaddr_type);
        ip = json_string_value(jip);

-       memset(out, 0, sizeof(*out));
+       memset(out4, 0, sizeof(*out4));
+       out4->u.sa.sa_family = AF_UNSPEC;
+       memset(out6, 0, sizeof(*out6));
+       out6->u.sa.sa_family = AF_UNSPEC;

        if (!strcmp(addr_type, "IPV4")) {
-               struct sockaddr_in *sin = &out->u.sin;
+               *user_addr_type = GTP1U_EUA_TYPE_IPv4;
                if (osmo_hexparse(ip, buf, sizeof(buf)) != 4) {
                        LOGP(DUECUPS, LOGL_NOTICE, "Failed parsing EUA %s type 
%s\n", ip, addr_type);
                        return -EINVAL;
@@ -287,13 +292,23 @@
                memcpy(&sin->sin_addr, buf, 4);
                sin->sin_family = AF_INET;
        } else if (!strcmp(addr_type, "IPV6")) {
-               struct sockaddr_in6 *sin6 = &out->u.sin6;
+               *user_addr_type = GTP1U_EUA_TYPE_IPv6;
                if (osmo_hexparse(ip, buf, sizeof(buf)) != 16) {
                        LOGP(DUECUPS, LOGL_NOTICE, "Failed parsing EUA %s type 
%s\n", ip, addr_type);
                        return -EINVAL;
                }
                memcpy(&sin6->sin6_addr, buf, 16);
                sin6->sin6_family = AF_INET6;
+       } else if (!strcmp(addr_type, "IPV4V6")) {
+               *user_addr_type = GTP1U_EUA_TYPE_IPv4v6;
+               if (osmo_hexparse(ip, buf, sizeof(buf)) != 20) {
+                       LOGP(DUECUPS, LOGL_NOTICE, "Failed parsing EUA %s type 
%s\n", ip, addr_type);
+                       return -EINVAL;
+               }
+               memcpy(&sin->sin_addr, buf, 4);
+               sin->sin_family = AF_INET;
+               memcpy(&sin6->sin6_addr, buf + 4, 16);
+               sin6->sin6_family = AF_INET6;
        } else {
                LOGP(DUECUPS, LOGL_NOTICE, "Unknown EUA type %s\n", addr_type);
                return -EINVAL;
@@ -395,7 +410,8 @@
        rc = parse_ep(&out->remote_udp, jremote_gtp_ep);
        if (rc < 0)
                return rc;
-       rc = parse_eua(&out->user_addr, juser_addr, juser_addr_type);
+       rc = parse_eua(&out->user_addr_type, &out->user_addr_ipv4,
+                      &out->user_addr_ipv6, juser_addr, juser_addr_type);
        if (rc < 0)
                return rc;
        out->rx_teid = json_integer_value(jrx_teid);
diff --git a/daemon/daemon_vty.c b/daemon/daemon_vty.c
index 16f23b8..e2562c9 100644
--- a/daemon/daemon_vty.c
+++ b/daemon/daemon_vty.c
@@ -230,20 +230,34 @@

 static void show_one_tunnel(struct vty *vty, const struct gtp_tunnel *t)
 {
-       char remote_ip[64], remote_port[16], user_addr[64];
+       char remote_ip[64], remote_port[16], user_addr_v4[64], user_addr_v6[64];

        getnameinfo(&t->remote_udp.u.sa, sizeof(t->remote_udp.u.sas),
                    remote_ip, sizeof(remote_ip), remote_port, 
sizeof(remote_port),
                    NI_NUMERICHOST|NI_NUMERICSERV);

-       getnameinfo(&t->user_addr.u.sa, sizeof(t->user_addr.u.sas),
-                   user_addr, sizeof(user_addr), NULL, 0,
-                   NI_NUMERICHOST|NI_NUMERICSERV);
+       if (t->user_addr_type == GTP1U_EUA_TYPE_IPv4 || t->user_addr_type == 
GTP1U_EUA_TYPE_IPv4v6) {
+               getnameinfo(&t->user_addr_ipv4.u.sa, 
sizeof(t->user_addr_ipv4.u.sas),
+                           user_addr_v4, sizeof(user_addr_v4), NULL, 0,
+                           NI_NUMERICHOST|NI_NUMERICSERV);
+       } else {
+               user_addr_v4[0] = '\0';
+       }
+       if ((t->user_addr_type == GTP1U_EUA_TYPE_IPv6 || t->user_addr_type == 
GTP1U_EUA_TYPE_IPv4v6) &&
+           t->user_addr_ipv6_global.u.sa.sa_family == AF_INET6) {
+               getnameinfo(&t->user_addr_ipv6_global.u.sa, 
sizeof(t->user_addr_ipv6_global.u.sas),
+                           user_addr_v6, sizeof(user_addr_v6), NULL, 0,
+                           NI_NUMERICHOST|NI_NUMERICSERV);
+       } else {
+               user_addr_v6[0] = '\0';
+       }

-
-       vty_out(vty, "%s/%08X - %s:%s/%08X %s(%s) %s%s",
-               t->gtp_ep->name, t->rx_teid, remote_ip, remote_port, t->tx_teid,
-               t->tun_dev->devname, t->tun_dev->netns_name, user_addr, 
VTY_NEWLINE);
+       vty_out(vty, "%s/%08X - %s:%s/%08X %s(%s) %s%s%s%s",
+               t->gtp_ep->name, t->rx_teid,
+               remote_ip, remote_port, t->tx_teid,
+               t->tun_dev->devname, t->tun_dev->netns_name, user_addr_v4,
+               (user_addr_v4[0] != '\0' && user_addr_v6[0] != '\0') ? " " : "",
+               user_addr_v6, VTY_NEWLINE);
 }

 DEFUN(show_tunnel, show_tunnel_cmd,
diff --git a/daemon/gtp_endpoint.c b/daemon/gtp_endpoint.c
index 0332f91..524226c 100644
--- a/daemon/gtp_endpoint.c
+++ b/daemon/gtp_endpoint.c
@@ -72,19 +72,20 @@
                             0, 16 - prefix_len_bytes);

                        /* Pick second address in the prefix: */
-                       memcpy(&t->user_addr.u.sin6.sin6_addr,
+                       t->user_addr_ipv6_global.u.sa.sa_family = AF_INET6;
+                       memcpy(&t->user_addr_ipv6_global.u.sin6.sin6_addr,
                               &t->user_addr_ipv6_prefix.u.sin6.sin6_addr,
                               
sizeof(t->user_addr_ipv6_prefix.u.sin6.sin6_addr));
-                       ((uint8_t *)&t->user_addr.u.sin6.sin6_addr)[15] = 2;
+                       ((uint8_t 
*)&t->user_addr_ipv6_global.u.sin6.sin6_addr)[15] = 2;

                        LOGT(t, LOGL_INFO, "Adding global IPv6 prefix %s/%u 
address %s\n",
                             inet_ntop(AF_INET6, 
&t->user_addr_ipv6_prefix.u.sin6.sin6_addr, &ip6strbuf[0][0], 
sizeof(ip6strbuf[0])),
                             opt_prefix->prefix_len,
-                            inet_ntop(AF_INET6, 
&t->user_addr.u.sin6.sin6_addr, &ip6strbuf[1][0], sizeof(ip6strbuf[1])));
+                            inet_ntop(AF_INET6, 
&t->user_addr_ipv6_global.u.sin6.sin6_addr, &ip6strbuf[1][0], 
sizeof(ip6strbuf[1])));

-                       if ((rc = osmo_netdev_add_addr(t->tun_dev->netdev, 
&t->user_addr, 64)) < 0) {
+                       if ((rc = osmo_netdev_add_addr(t->tun_dev->netdev, 
&t->user_addr_ipv6_global, 64)) < 0) {
                                LOGT(t, LOGL_ERROR, "Cannot add global IPv6 
user addr %s to tun device: %s\n",
-                                    inet_ntop(AF_INET6, 
&t->user_addr.u.sin6.sin6_addr, &ip6strbuf[1][0], sizeof(ip6strbuf[1])),
+                                    inet_ntop(AF_INET6, 
&t->user_addr_ipv6_global.u.sin6.sin6_addr, &ip6strbuf[1][0], 
sizeof(ip6strbuf[1])),
                                     strerror(-rc));
                        }

@@ -174,12 +175,12 @@
        struct osmo_icmpv6_radv_hdr *ra;
        switch (iph->version) {
        case 4:
-               if (t->user_addr.u.sa.sa_family != AF_INET) {
+               if (t->user_addr_ipv4.u.sa.sa_family != AF_INET) {
                        LOGT(t, LOGL_NOTICE, "Rx GTPU payload for unexpected 
IPv4 %s in non-IPv4 PDP Context\n",
                                inet_ntop(AF_INET, &iph->daddr, ip6strbuf, 
sizeof(ip6strbuf)));
                        goto unlock_ret;
                }
-               if (memcmp(&iph->daddr, &t->user_addr.u.sin.sin_addr, 4) != 0) {
+               if (memcmp(&iph->daddr, &t->user_addr_ipv4.u.sin.sin_addr, 4) 
!= 0) {
                        LOGT(t, LOGL_NOTICE, "Rx GTPU payload for unknown dst 
IP addr %s\n",
                                inet_ntop(AF_INET, &iph->daddr, ip6strbuf, 
sizeof(ip6strbuf)));
                        goto unlock_ret;
@@ -187,12 +188,12 @@
                break;
        case 6:
                ip6h = (struct ip6_hdr *)payload;
-               if (t->user_addr.u.sa.sa_family != AF_INET6) {
-                       LOGT(t, LOGL_NOTICE, "Rx GTPU payload for unexpected 
IPv6 %s in non-IPv6 PDP Context\n",
-                               inet_ntop(AF_INET6, &ip6h->ip6_dst, ip6strbuf, 
sizeof(ip6strbuf)));
-                       goto unlock_ret;
-               }
                if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) {
+                       if (t->user_addr_ipv6_ll.u.sa.sa_family != AF_INET6) {
+                               LOGT(t, LOGL_NOTICE, "Rx GTPU payload for 
unexpected IPv6 %s in non-IPv6 PDP Context\n",
+                                    inet_ntop(AF_INET6, &ip6h->ip6_dst, 
ip6strbuf, sizeof(ip6strbuf)));
+                               goto unlock_ret;
+                       }
                        if (memcmp(&ip6h->ip6_dst, 
&t->user_addr_ipv6_ll.u.sin6.sin6_addr, 16) != 0) {
                                LOGT(t, LOGL_NOTICE, "Rx GTPU payload for 
unknown link-local dst IP addr %s\n",
                                     inet_ntop(AF_INET6, &ip6h->ip6_dst, 
ip6strbuf, sizeof(ip6strbuf)));
@@ -203,11 +204,18 @@
                                handle_router_adv(t, (struct ip6_hdr *)payload, 
ra, ra_len);
                                goto unlock_ret;
                        }
-               /* Match by global IPv6 /64 prefix allocated through SLAAC: */
-               } else if (memcmp(&ip6h->ip6_dst, 
&t->user_addr.u.sin6.sin6_addr, 8) != 0) {
-                       LOGT(t, LOGL_NOTICE, "Rx GTPU payload for unknown 
global dst IP addr %s\n",
-                            inet_ntop(AF_INET6, &ip6h->ip6_dst, ip6strbuf, 
sizeof(ip6strbuf)));
-                       goto unlock_ret;
+               } else {
+                       /* Match by global IPv6 /64 prefix allocated through 
SLAAC: */
+                       if (t->user_addr_ipv6_global.u.sa.sa_family != 
AF_INET6) {
+                               LOGT(t, LOGL_NOTICE, "Rx GTPU payload for 
unexpected IPv6 %s in non-IPv6 PDP Context\n",
+                                    inet_ntop(AF_INET6, &ip6h->ip6_dst, 
ip6strbuf, sizeof(ip6strbuf)));
+                               goto unlock_ret;
+                       }
+                       if (memcmp(&ip6h->ip6_dst, 
&t->user_addr_ipv6_prefix.u.sin6.sin6_addr, 8) != 0) {
+                               LOGT(t, LOGL_NOTICE, "Rx GTPU payload for 
unknown global dst IP addr %s\n",
+                               inet_ntop(AF_INET6, &ip6h->ip6_dst, ip6strbuf, 
sizeof(ip6strbuf)));
+                               goto unlock_ret;
+                       }
                }
                break;
        default:
diff --git a/daemon/gtp_tunnel.c b/daemon/gtp_tunnel.c
index 2765488..fc99e4f 100644
--- a/daemon/gtp_tunnel.c
+++ b/daemon/gtp_tunnel.c
@@ -57,15 +57,28 @@
        t->rx_teid = cpars->rx_teid;
        t->tx_teid = cpars->tx_teid;
        memcpy(&t->exthdr, &cpars->exthdr, sizeof(t->exthdr));
-       memcpy(&t->user_addr_ipv6_ll, &cpars->user_addr, sizeof(t->user_addr));
-       memcpy(&t->user_addr, &t->user_addr_ipv6_ll, 
sizeof(t->user_addr_ipv6_ll));
-       memcpy(&t->remote_udp, &cpars->remote_udp, sizeof(t->remote_udp));

-       if ((rc = osmo_netdev_add_addr(t->tun_dev->netdev, &t->user_addr, 32)) 
< 0) {
-               LOGT(t, LOGL_ERROR, "Cannot add user addr to tun device: %s\n",
-                    strerror(-rc));
+       if (cpars->user_addr_type == GTP1U_EUA_TYPE_IPv4 || 
cpars->user_addr_type == GTP1U_EUA_TYPE_IPv4v6) {
+               memcpy(&t->user_addr_ipv4, &cpars->user_addr_ipv4, 
sizeof(t->user_addr_ipv4));
+               if ((rc = osmo_netdev_add_addr(t->tun_dev->netdev, 
&t->user_addr_ipv4, 32)) < 0) {
+                       LOGT(t, LOGL_ERROR, "Cannot add user addr to tun 
device: %s\n",
+                       strerror(-rc));
+               }
+       } else {
+               t->user_addr_ipv4.u.sa.sa_family = AF_UNSPEC;
        }

+       t->user_addr_type = cpars->user_addr_type;
+       if (cpars->user_addr_type == GTP1U_EUA_TYPE_IPv6 || 
cpars->user_addr_type == GTP1U_EUA_TYPE_IPv4v6)
+               memcpy(&t->user_addr_ipv6_ll, &cpars->user_addr_ipv6, 
sizeof(t->user_addr_ipv6_ll));
+       else
+               t->user_addr_ipv6_ll.u.sa.sa_family = AF_UNSPEC;
+
+       /* user_addr_ipv6_global will be set later on during IPv6 SLAAC 
procedure: */
+       t->user_addr_ipv6_global.u.sa.sa_family = AF_UNSPEC;
+
+       memcpy(&t->remote_udp, &cpars->remote_udp, sizeof(t->remote_udp));
+
        /* TODO: hash table? */
        llist_add_tail(&t->list, &d->gtp_tunnels);
        pthread_rwlock_unlock(&d->rwlock);
@@ -125,9 +138,23 @@

        llist_for_each_entry(t, &d->gtp_tunnels, list) {
                /* TODO: Find best matching filter */
-               if (t->tun_dev == tun &&
-                   osmo_sockaddr_cmp(osa, &t->user_addr) == 0)
+               if (t->tun_dev != tun)
+                       continue;
+               switch (osa->u.sa.sa_family) {
+               case AF_INET:
+                       if (t->user_addr_type == GTP1U_EUA_TYPE_IPv6)
+                               continue;
+                       if (osmo_sockaddr_cmp(osa, &t->user_addr_ipv4) != 0)
+                               continue;
                        return t;
+               case AF_INET6:
+                       if (t->user_addr_type == GTP1U_EUA_TYPE_IPv4)
+                               continue;
+                       if (osmo_sockaddr_cmp(osa, &t->user_addr_ipv6_ll) != 0 
&&
+                           osmo_sockaddr_cmp(osa, &t->user_addr_ipv6_global) 
!= 0)
+                               continue;
+                       return t;
+               }
        }
        return NULL;
 }
@@ -141,8 +168,18 @@
        /* talloc is not thread safe, all alloc/free must come from main thread 
*/
        ASSERT_MAIN_THREAD(t->d);

-       if ((rc = osmo_netdev_del_addr(t->tun_dev->netdev, &t->user_addr, 32)) 
< 0)
-               LOGT(t, LOGL_ERROR, "Cannot remove user address: %s\n", 
strerror(-rc));
+       if (t->user_addr_type == GTP1U_EUA_TYPE_IPv4 || t->user_addr_type == 
GTP1U_EUA_TYPE_IPv4v6) {
+               if ((rc = osmo_netdev_del_addr(t->tun_dev->netdev, 
&t->user_addr_ipv4, 32)) < 0)
+                       LOGT(t, LOGL_ERROR, "Cannot remove IPv4 user address: 
%s\n", strerror(-rc));
+       }
+       if (t->user_addr_type == GTP1U_EUA_TYPE_IPv6 || t->user_addr_type == 
GTP1U_EUA_TYPE_IPv4v6) {
+               if ((rc = osmo_netdev_del_addr(t->tun_dev->netdev, 
&t->user_addr_ipv6_ll, 32)) < 0)
+                       LOGT(t, LOGL_ERROR, "Cannot remove IPv6 link-local user 
address: %s\n", strerror(-rc));
+               if (t->user_addr_ipv6_global.u.sa.sa_family != AF_UNSPEC) {
+                       if ((rc = osmo_netdev_del_addr(t->tun_dev->netdev, 
&t->user_addr_ipv6_global, 32)) < 0)
+                               LOGT(t, LOGL_ERROR, "Cannot remove IPv6 global 
user address: %s\n", strerror(-rc));
+               }
+       }

        llist_del(&t->list);

@@ -180,9 +217,10 @@
        struct msgb *msg;
        int rc;

-       OSMO_ASSERT(t->user_addr.u.sa.sa_family == AF_INET6);
+       OSMO_ASSERT(t->user_addr_type == GTP1U_EUA_TYPE_IPv6 ||
+                   t->user_addr_type == GTP1U_EUA_TYPE_IPv4v6);

-       msg = osmo_icmpv6_construct_rs(&t->user_addr.u.sin6.sin6_addr);
+       msg = osmo_icmpv6_construct_rs(&t->user_addr_ipv6_ll.u.sin6.sin6_addr);

        pthread_rwlock_rdlock(&t->d->rwlock);
        rc = tx_gtp1u_pkt(t, msg->head, msgb_data(msg), msgb_length(msg));
diff --git a/daemon/internal.h b/daemon/internal.h
index 5d4b832..d9e040c 100644
--- a/daemon/internal.h
+++ b/daemon/internal.h
@@ -172,6 +172,12 @@
  *    this is what happens when IP arrives on the tun device
  */

+enum gtp1u_eua_type {
+       GTP1U_EUA_TYPE_IPv4,
+       GTP1U_EUA_TYPE_IPv6,
+       GTP1U_EUA_TYPE_IPv4v6,
+};
+
 struct gtp1u_exthdr_pdu_sess_container {
        bool enabled;
        uint8_t pdu_type; /* GTP1_EXTHDR_PDU_TYPE_* */
@@ -203,9 +209,11 @@
        uint32_t rx_teid;

        /* End user Address (inner IP) */
+       enum gtp1u_eua_type user_addr_type;
+       struct osmo_sockaddr user_addr_ipv4;
        struct osmo_sockaddr user_addr_ipv6_ll;
        struct osmo_sockaddr user_addr_ipv6_prefix;
-       struct osmo_sockaddr user_addr;
+       struct osmo_sockaddr user_addr_ipv6_global;

        /* Remote UDP IP/Port*/
        struct osmo_sockaddr remote_udp;
@@ -231,7 +239,9 @@
        struct gtp1u_exthdrs exthdr;

        /* end user address */
-       struct osmo_sockaddr user_addr;
+       enum gtp1u_eua_type user_addr_type;
+       struct osmo_sockaddr user_addr_ipv4;
+       struct osmo_sockaddr user_addr_ipv6;

        /* remote GTP/UDP IP+Port */
        struct osmo_sockaddr remote_udp;
diff --git a/ttcn3/UECUPS_Types.ttcn b/ttcn3/UECUPS_Types.ttcn
index 45466c8..ba4e7d4 100644
--- a/ttcn3/UECUPS_Types.ttcn
+++ b/ttcn3/UECUPS_Types.ttcn
@@ -7,7 +7,8 @@

 type enumerated UECUPS_AddrType {
        IPV4    (1),
-       IPV6    (2)
+       IPV6    (2),
+       IPV4V6  (3)
 };

 type enumerated UECUPS_Result {
@@ -43,7 +44,7 @@

        /* user address (allocated inside the tunnel) */
        UECUPS_AddrType         user_addr_type,
-       OCT4_16n                user_addr,
+       OCT4_20n                user_addr,

        /* GTP endpoint (UDP IP/Port tuples) */
        UECUPS_SockAddr         local_gtp_ep,

--
To view, visit https://gerrit.osmocom.org/c/osmo-uecups/+/42470?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: osmo-uecups
Gerrit-Branch: master
Gerrit-Change-Id: Ic2da7a761a8df7e006fc02ca6557a48f371e4151
Gerrit-Change-Number: 42470
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <[email protected]>

Reply via email to