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
This commit is contained in:
Pablo Neira Ayuso 2023-10-05 00:43:01 +02:00 committed by Oliver Smith
parent 86d1bc36b7
commit b9c3b49410
3 changed files with 62 additions and 34 deletions

View File

@ -53,11 +53,18 @@ static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t)
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 @@ struct gtp_pdp {
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 @@ static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data)
{
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 @@ static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data)
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 @@ static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data)
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;

View File

@ -16,16 +16,14 @@ struct gtp_tunnel {
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 {

View File

@ -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 @@ add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
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 @@ add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
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;