osmith has uploaded this change for review. ( https://gerrit.osmocom.org/c/libgtpnl/+/34739?usp=email )
Change subject: IPv4-in-IPv6-GTP and IPv6-in-IPv4-GTP ......................................................................
IPv4-in-IPv6-GTP and IPv6-in-IPv4-GTP
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.
Remove union in gtp_pdp and gtp_tunnel objects, since ms and sgsn fields might now use different IP family. Update listing to support too to deal with this new feature.
Update syntax of gtp-tunnel tool:
add <gtp device> <v0> <tid> <family> <ms-addr> <family> <sgsn-addr> add <gtp device> <v1> <i_tei> <o_tei> <family> <ms-addr> <family> <sgsn-addr>
to allow specify the family for the peer (sgsn) address too.
Changes by Oliver: - cosmetics
Change-Id: Ibc581a92a561dc0bd9924d9f15c7a27dc513c8d7 --- M src/gtp-genl.c M src/internal.h M tools/gtp-tunnel.c 3 files changed, 93 insertions(+), 34 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libgtpnl refs/changes/39/34739/1
diff --git a/src/gtp-genl.c b/src/gtp-genl.c index 4e4e63d..2cf4102 100644 --- a/src/gtp-genl.c +++ b/src/gtp-genl.c @@ -53,11 +53,18 @@ case AF_INET: if (t->ip.sgsn_addr.s_addr) mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, t->ip.sgsn_addr.s_addr); + else + mnl_attr_put(nlh, GTPA_PEER_ADDR6, sizeof(t->ip6.sgsn_addr), &t->ip6.sgsn_addr); + if (t->ip.ms_addr.s_addr) mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ip.ms_addr.s_addr); break; case AF_INET6: - mnl_attr_put(nlh, GTPA_PEER_ADDR6, sizeof(t->ip6.sgsn_addr), &t->ip6.sgsn_addr); + if (t->ip.sgsn_addr.s_addr) + mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, t->ip.sgsn_addr.s_addr); + else + mnl_attr_put(nlh, GTPA_PEER_ADDR6, sizeof(t->ip6.sgsn_addr), &t->ip6.sgsn_addr); + mnl_attr_put(nlh, GTPA_MS_ADDR6, sizeof(t->ip6.ms_addr), &t->ip6.ms_addr); break; } @@ -126,16 +133,14 @@ uint32_t o_tei; } v1; } u; - union { - struct { - struct in_addr sgsn_addr; - struct in_addr ms_addr; - } ip; - struct { - struct in6_addr sgsn_addr; - struct in6_addr ms_addr; - } ip6; - }; + struct { + struct in_addr sgsn_addr; + struct in_addr ms_addr; + } ip; + struct { + struct in6_addr sgsn_addr; + struct in6_addr ms_addr; + } ip6; };
static int genl_gtp_validate_cb(const struct nlattr *attr, void *data) @@ -188,6 +193,7 @@ { struct nlattr *tb[GTPA_MAX + 1] = {}; char buf[INET6_ADDRSTRLEN]; + int peer_family = AF_UNSPEC; struct gtp_pdp pdp = {}; struct genlmsghdr *genl;
@@ -204,16 +210,21 @@ if (tb[GTPA_O_TEI]) pdp.u.v1.o_tei = mnl_attr_get_u32(tb[GTPA_O_TEI]);
+ if (tb[GTPA_PEER_ADDRESS]) { + pdp.ip.sgsn_addr.s_addr = mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]); + peer_family = AF_INET; + } else if (tb[GTPA_PEER_ADDR6]) { + memcpy(&pdp.ip6.sgsn_addr, mnl_attr_get_payload(tb[GTPA_PEER_ADDR6]), + sizeof(struct in6_addr)); + peer_family = AF_INET6; + } + switch (pdp.family) { case AF_INET: - if (tb[GTPA_PEER_ADDRESS]) - pdp.ip.sgsn_addr.s_addr = mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]); if (tb[GTPA_MS_ADDRESS]) pdp.ip.ms_addr.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]); break; case AF_INET6: - if (tb[GTPA_PEER_ADDR6]) - memcpy(&pdp.ip6.sgsn_addr, mnl_attr_get_payload(tb[GTPA_PEER_ADDR6]), sizeof(struct in6_addr)); if (tb[GTPA_MS_ADDR6]) memcpy(&pdp.ip6.ms_addr, mnl_attr_get_payload(tb[GTPA_MS_ADDR6]), sizeof(struct in6_addr)); break; @@ -228,18 +239,27 @@ else if (pdp.version == GTP_V1) printf("tei %u/%u ", pdp.u.v1.i_tei, pdp.u.v1.o_tei);
- printf("family %s ", pdp.family == AF_INET6 ? "ip6" : "ip"); + printf("%s ", pdp.family == AF_INET6 ? "ip6" : "ip");
switch (pdp.family) { case AF_INET: inet_ntop(AF_INET, &pdp.ip.ms_addr, buf, sizeof(buf)); printf("ms_addr %s ", buf); - inet_ntop(AF_INET, &pdp.ip.sgsn_addr, buf, sizeof(buf)); - printf("sgsn_addr %s\n", buf); break; case AF_INET6: inet_ntop(AF_INET6, &pdp.ip6.ms_addr, buf, sizeof(buf)); printf("ms_addr6 %s ", buf); + break; + } + + printf("%s ", peer_family == AF_INET6 ? "ip6" : "ip"); + + switch (peer_family) { + case AF_INET: + inet_ntop(AF_INET, &pdp.ip.sgsn_addr, buf, sizeof(buf)); + printf("sgsn_addr %s\n", buf); + break; + case AF_INET6: inet_ntop(AF_INET6, &pdp.ip6.sgsn_addr, buf, sizeof(buf)); printf("sgsn_addr6 %s\n", buf); break; diff --git a/src/internal.h b/src/internal.h index 8e8b3c5..10be913 100644 --- a/src/internal.h +++ b/src/internal.h @@ -16,16 +16,14 @@ uint8_t family; int ifns; uint32_t ifidx; - union { - struct { - struct in_addr ms_addr; - struct in_addr sgsn_addr; - } ip; - struct { - struct in6_addr ms_addr; - struct in6_addr sgsn_addr; - } ip6; - }; + struct { + struct in_addr ms_addr; + struct in_addr sgsn_addr; + } ip; + struct { + struct in6_addr ms_addr; + struct in6_addr sgsn_addr; + } ip6; int gtp_version; union { struct { diff --git a/tools/gtp-tunnel.c b/tools/gtp-tunnel.c index 3f5de5f..3033d64 100644 --- a/tools/gtp-tunnel.c +++ b/tools/gtp-tunnel.c @@ -43,9 +43,9 @@
static void add_usage(const char *name) { - printf("%s add <gtp device> <v0> <tid> <family> <ms-addr> <sgsn-addr>\n", + printf("%s add <gtp device> <v0> <tid> <family> <ms-addr> <family> <sgsn-addr>\n", name); - printf("%s add <gtp device> <v1> <i_tei> <o_tei> <family> <ms-addr> <sgsn-addr>\n", + printf("%s add <gtp device> <v1> <i_tei> <o_tei> <family> <ms-addr> <family> <sgsn-addr>\n", name); }
@@ -60,12 +60,12 @@ struct in_addr addr; struct in6_addr addr6; } sgsn; + int optidx, family, peer_family; struct gtp_tunnel *t; uint32_t gtp_version; uint32_t gtp_ifidx; - int optidx, family;
- if (argc < 8 || argc > 9) { + if (argc < 9 || argc > 10) { add_usage(argv[0]); return EXIT_FAILURE; } @@ -129,12 +129,22 @@ break; }
- if (inet_pton(family, argv[optidx++], &sgsn) <= 0) { + if (!strcmp(argv[optidx], "ip")) { + peer_family = AF_INET; + } else if (!strcmp(argv[optidx], "ip6")) { + peer_family = AF_INET6; + } else { + fprintf(stderr, "wrong family `%s', expecting `ip' or `ip6'\n", argv[optidx]); + return EXIT_FAILURE; + } + optidx++; + + if (inet_pton(peer_family, argv[optidx++], &sgsn) <= 0) { fprintf(stderr, "bad address for sgsn\n"); exit(EXIT_FAILURE); }
- switch (family) { + switch (peer_family) { case AF_INET: gtp_tunnel_set_sgsn_ip4(t, &sgsn.addr); break;