laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/libgtpnl/+/34735?usp=email )

Change subject: Add IPv6 support
......................................................................

Add IPv6 support

Implement IPv6 in libgtpnl and the gtp-tunnel testing tool. Allow to
combine:

- GTPA_MS_ADDRESS and GTPA_PEER_ADDR6
- GTPA_MS_ADDR6 and GTPA_PEER_ADDRESS

to specify IPv4-in-IPv6-GTP and IPv6-in-IPv4-GTP in the tunnel
declaration from control plane.

This patch is based on multiple patches from Pablo in OS#6123. I decided
to squash them to directly implement v4-in-v6 and vice versa, instead of
implementing another variant first and then changing it again.

Co-developed-by: Pablo Neira Ayuso <pa...@netfilter.org>
Related: OS#6096
Change-Id: If864c9170f74af52a95cbc4cdb1b866e0309306b
---
M include/libgtpnl/gtp.h
M include/linux/gtp.h
M src/gtp-genl.c
M src/gtp.c
M src/libgtpnl.map
M tools/gtp-tunnel.c
6 files changed, 145 insertions(+), 30 deletions(-)

Approvals:
  pespin: Looks good to me, but someone else must approve
  Jenkins Builder: Verified
  laforge: Looks good to me, approved




diff --git a/include/libgtpnl/gtp.h b/include/libgtpnl/gtp.h
index a6cd8e2..9b0bcf4 100644
--- a/include/libgtpnl/gtp.h
+++ b/include/libgtpnl/gtp.h
@@ -13,6 +13,8 @@
 void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx);
 void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr);
 void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr);
+void gtp_tunnel_set_ms_ip6(struct gtp_tunnel *t, const struct in6_addr 
*ms_addr);
+void gtp_tunnel_set_sgsn_ip6(struct gtp_tunnel *t, const struct in6_addr 
*sgsn_addr);
 void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version);
 void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid);
 void gtp_tunnel_set_i_tei(struct gtp_tunnel *t, uint32_t i_tei);
diff --git a/include/linux/gtp.h b/include/linux/gtp.h
index 3dcdb9e..40f5388 100644
--- a/include/linux/gtp.h
+++ b/include/linux/gtp.h
@@ -31,6 +31,9 @@
        GTPA_I_TEI,     /* for GTPv1 only */
        GTPA_O_TEI,     /* for GTPv1 only */
        GTPA_PAD,
+       GTPA_PEER_ADDR6,
+       GTPA_MS_ADDR6,
+       GTPA_FAMILY,
        __GTPA_MAX,
 };
 #define GTPA_MAX (__GTPA_MAX - 1)
diff --git a/src/gtp-genl.c b/src/gtp-genl.c
index 82ef8ab..447e1ea 100644
--- a/src/gtp-genl.c
+++ b/src/gtp-genl.c
@@ -44,14 +44,36 @@

 static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t)
 {
+       mnl_attr_put_u8(nlh, GTPA_FAMILY, t->ms_addr.family);
        mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version);
        if (t->ifns >= 0)
                mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns);
        mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx);
-       if (t->sgsn_addr.ip4.s_addr)
-               mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, 
t->sgsn_addr.ip4.s_addr);
-       if (t->ms_addr.ip4.s_addr)
+
+       switch (t->ms_addr.family) {
+       case AF_INET:
                mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.ip4.s_addr);
+               break;
+       case AF_INET6:
+               mnl_attr_put(nlh, GTPA_MS_ADDR6, sizeof(t->ms_addr.ip6), 
&t->ms_addr.ip6);
+               break;
+       default:
+               /* No addr is set when deleting a tunnel */
+               break;
+       }
+
+       switch (t->sgsn_addr.family) {
+       case AF_INET:
+               mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, 
t->sgsn_addr.ip4.s_addr);
+               break;
+       case AF_INET6:
+               mnl_attr_put(nlh, GTPA_PEER_ADDR6, sizeof(t->sgsn_addr.ip6), 
&t->sgsn_addr.ip6);
+               break;
+       default:
+               /* No addr is set when deleting a tunnel */
+               break;
+       }
+
        if (t->gtp_version == GTP_V0) {
                mnl_attr_put_u64(nlh, GTPA_TID, t->u.v0.tid);
                mnl_attr_put_u16(nlh, GTPA_FLOW, t->u.v0.flowid);
@@ -129,6 +151,12 @@
                return MNL_CB_OK;

        switch(type) {
+       case GTPA_FAMILY:
+               if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
+                       perror("mnl_attr_validate");
+                       return MNL_CB_ERROR;
+               }
+               break;
        case GTPA_TID:
                if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
                        perror("mnl_attr_validate");
@@ -145,6 +173,14 @@
                        return MNL_CB_ERROR;
                }
                break;
+       case GTPA_PEER_ADDR6:
+       case GTPA_MS_ADDR6:
+               if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
+                                      sizeof(struct in6_addr)) < 0) {
+                       perror("mnl_attr_validate");
+                       return MNL_CB_ERROR;
+               }
+               break;
        default:
                break;
        }
@@ -160,36 +196,56 @@
        struct genlmsghdr *genl;

        mnl_attr_parse(nlh, sizeof(*genl), genl_gtp_validate_cb, tb);
+
        if (tb[GTPA_TID])
                pdp.u.v0.tid = mnl_attr_get_u64(tb[GTPA_TID]);
        if (tb[GTPA_I_TEI])
                pdp.u.v1.i_tei = mnl_attr_get_u32(tb[GTPA_I_TEI]);
        if (tb[GTPA_O_TEI])
                pdp.u.v1.o_tei = mnl_attr_get_u32(tb[GTPA_O_TEI]);
+
        if (tb[GTPA_PEER_ADDRESS]) {
                pdp.sgsn_addr.family = AF_INET;
-               pdp.sgsn_addr.ip4.s_addr =
-                       mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]);
+               pdp.sgsn_addr.ip4.s_addr = 
mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]);
+       } else if (tb[GTPA_PEER_ADDR6]) {
+               pdp.sgsn_addr.family = AF_INET6;
+               memcpy(&pdp.sgsn_addr.ip6, 
mnl_attr_get_payload(tb[GTPA_PEER_ADDR6]),
+                      sizeof(struct in6_addr));
+       } else {
+               fprintf(stderr, "sgsn_addr: no IPv4 nor IPv6 set\n");
+               return MNL_CB_ERROR;
        }
+
        if (tb[GTPA_MS_ADDRESS]) {
                pdp.ms_addr.family = AF_INET;
                pdp.ms_addr.ip4.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]);
-       }
-       if (tb[GTPA_VERSION]) {
-               pdp.version = mnl_attr_get_u32(tb[GTPA_VERSION]);
+       } else if (tb[GTPA_MS_ADDR6]) {
+               pdp.ms_addr.family = AF_INET6;
+               memcpy(&pdp.ms_addr.ip6, 
mnl_attr_get_payload(tb[GTPA_MS_ADDR6]), sizeof(struct in6_addr));
+       } else {
+               fprintf(stderr, "ms_addr: no IPv4 nor IPv6 set\n");
+               return MNL_CB_ERROR;
        }

-       printf("version %u ", pdp.version);
-       if (pdp.version == GTP_V0) {
-               inet_ntop(AF_INET, &pdp.ms_addr.ip4, buf, sizeof(buf));
-               printf("tid %"PRIu64" ms_addr %s ",
-                      pdp.u.v0.tid, buf);
-       } else if (pdp.version == GTP_V1) {
-               inet_ntop(AF_INET, &pdp.ms_addr.ip4, buf, sizeof(buf));
-               printf("tei %u/%u ms_addr %s ", pdp.u.v1.i_tei,
-                      pdp.u.v1.o_tei, buf);
+       if (tb[GTPA_FAMILY] && mnl_attr_get_u32(tb[GTPA_FAMILY]) != 
pdp.ms_addr.family) {
+               fprintf(stderr, "ms_addr family does not match GTPA_FAMILY\n");
+               return MNL_CB_ERROR;
        }
-       inet_ntop(AF_INET, &pdp.sgsn_addr.ip4, buf, sizeof(buf));
+
+       if (tb[GTPA_VERSION])
+               pdp.version = mnl_attr_get_u32(tb[GTPA_VERSION]);
+
+       printf("version %u ", pdp.version);
+
+       if (pdp.version == GTP_V0)
+               printf("tid %"PRIu64" ", pdp.u.v0.tid);
+       else if (pdp.version == GTP_V1)
+               printf("tei %u/%u ", pdp.u.v1.i_tei, pdp.u.v1.o_tei);
+
+       inet_ntop(pdp.ms_addr.family, &pdp.ms_addr.ip4, buf, sizeof(buf));
+       printf("ms_addr %s ", buf);
+
+       inet_ntop(pdp.sgsn_addr.family, &pdp.sgsn_addr.ip4, buf, sizeof(buf));
        printf("sgsn_addr %s\n", buf);

        return MNL_CB_OK;
diff --git a/src/gtp.c b/src/gtp.c
index 4eadc29..657eb7a 100644
--- a/src/gtp.c
+++ b/src/gtp.c
@@ -72,6 +72,20 @@
 }
 EXPORT_SYMBOL(gtp_tunnel_set_sgsn_ip4);

+void gtp_tunnel_set_ms_ip6(struct gtp_tunnel *t, const struct in6_addr 
*ms_addr)
+{
+       t->ms_addr.family = AF_INET6;
+       t->ms_addr.ip6 = *ms_addr;
+}
+EXPORT_SYMBOL(gtp_tunnel_set_ms_ip6);
+
+void gtp_tunnel_set_sgsn_ip6(struct gtp_tunnel *t, const struct in6_addr 
*sgsn_addr)
+{
+       t->sgsn_addr.family = AF_INET6;
+       t->sgsn_addr.ip6 = *sgsn_addr;
+}
+EXPORT_SYMBOL(gtp_tunnel_set_sgsn_ip6);
+
 void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version)
 {
        t->gtp_version = version;
diff --git a/src/libgtpnl.map b/src/libgtpnl.map
index 804f8b3..1237e69 100644
--- a/src/libgtpnl.map
+++ b/src/libgtpnl.map
@@ -38,3 +38,8 @@

 local: *;
 };
+
+LIBGTPNL_1.1 {
+  gtp_tunnel_set_ms_ip6;
+  gtp_tunnel_set_sgsn_ip6;
+} LIBGTPNL_1.0;
diff --git a/tools/gtp-tunnel.c b/tools/gtp-tunnel.c
index 1868097..b29e386 100644
--- a/tools/gtp-tunnel.c
+++ b/tools/gtp-tunnel.c
@@ -49,12 +49,32 @@
               name);
 }

+static void set_addr(const char *addr, bool is_ms, struct gtp_tunnel *t)
+{
+       struct in_addr ip4;
+       struct in6_addr ip6;
+
+       if (inet_pton(AF_INET, addr, &ip4) == 1) {
+               if (is_ms)
+                       return gtp_tunnel_set_ms_ip4(t, &ip4);
+               return gtp_tunnel_set_sgsn_ip4(t, &ip4);
+       }
+
+       if (inet_pton(AF_INET6, addr, &ip6) == 1) {
+               if (is_ms)
+                       return gtp_tunnel_set_ms_ip6(t, &ip6);
+               return gtp_tunnel_set_sgsn_ip6(t, &ip6);
+       }
+
+       fprintf(stderr, "bad address: %s\n", addr);
+       exit(EXIT_FAILURE);
+}
+
 static int
 add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
 {
        struct gtp_tunnel *t;
        uint32_t gtp_ifidx;
-       struct in_addr ms, sgsn;
        uint32_t gtp_version;
        int optidx;

@@ -95,17 +115,8 @@
                gtp_tunnel_set_o_tei(t, atoi(argv[optidx++]));
        }

-       if (inet_aton(argv[optidx++], &ms) < 0) {
-               perror("bad address for ms");
-               exit(EXIT_FAILURE);
-       }
-       gtp_tunnel_set_ms_ip4(t, &ms);
-
-       if (inet_aton(argv[optidx++], &sgsn) < 0) {
-               perror("bad address for sgsn");
-               exit(EXIT_FAILURE);
-       }
-       gtp_tunnel_set_sgsn_ip4(t, &sgsn);
+       set_addr(argv[optidx++], true, t);
+       set_addr(argv[optidx++], false, t);

        gtp_add_tunnel(genl_id, nl, t);


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

Gerrit-Project: libgtpnl
Gerrit-Branch: master
Gerrit-Change-Id: If864c9170f74af52a95cbc4cdb1b866e0309306b
Gerrit-Change-Number: 34735
Gerrit-PatchSet: 5
Gerrit-Owner: osmith <osm...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanits...@sysmocom.de>
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: osmith <osm...@sysmocom.de>
Gerrit-Reviewer: pespin <pes...@sysmocom.de>
Gerrit-MessageType: merged

Reply via email to