oml: encode IPv6 NSVC using the new OML attribute NM_ATT_OSMO_NS_LINK_CFG

The old IE NM_ATT_IPACC_NS_LINK_CFG didn't support IPv6 NSVC.

Depends: Ic261bc43a07fa741b97a9c6ec5a9ed6f5ecae588 (libosmocore)
Depends: I9e279bb20940c66eea5196f281184cb4f8a5cc5f (libosmocore)
Change-Id: I6529876a3c1116a79dd624312243d8ae48a41fe2
This commit is contained in:
Alexander Couzens 2020-09-21 18:35:24 +02:00 committed by laforge
parent 37474b2b38
commit 2f9df96eba
8 changed files with 115 additions and 26 deletions

View File

@ -8,6 +8,7 @@
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/gsm/bts_features.h>
@ -745,9 +746,7 @@ struct gsm_bts_gprs_nsvc {
int id;
uint16_t nsvci;
uint16_t local_port; /* on the BTS */
uint16_t remote_port; /* on the SGSN */
uint32_t remote_ip; /* on the SGSN */
struct osmo_sockaddr remote;
struct gsm_abis_mo mo;
};

View File

@ -36,9 +36,11 @@
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/gsm23236.h>
#include <osmocom/core/sockaddr_str.h>
#include <arpa/inet.h>
#include <osmocom/core/byteswap.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/socket.h>
#include <osmocom/bsc/gsm_data.h>
@ -762,17 +764,27 @@ static void config_write_bts_gprs(struct vty *vty, struct gsm_bts *bts)
for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
struct gsm_bts_gprs_nsvc *nsvc =
&bts->gprs.nsvc[i];
struct in_addr ia;
struct osmo_sockaddr_str remote = {};
uint16_t port;
ia.s_addr = htonl(nsvc->remote_ip);
vty_out(vty, " gprs nsvc %u nsvci %u%s", i,
nsvc->nsvci, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u local udp port %u%s", i,
nsvc->local_port, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u remote udp port %u%s", i,
nsvc->remote_port, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u remote ip %s%s", i,
inet_ntoa(ia), VTY_NEWLINE);
osmo_sockaddr_str_from_sockaddr(&remote, &nsvc->remote.u.sas);
if (remote.af != AF_UNSPEC) {
vty_out(vty, " gprs nsvc %u remote ip %s%s", i,
remote.ip, VTY_NEWLINE);
}
/* Can't use remote.port because it's only valid when family != AF_UNSPEC, but the
* port can be even configured when the IP isn't */
port = osmo_htons(nsvc->remote.u.sin.sin_port);
if (port)
vty_out(vty, " gprs nsvc %u remote udp port %u%s", i,
port, VTY_NEWLINE);
}
/* EGPRS specific parameters */
@ -3010,26 +3022,41 @@ DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd,
GPRS_CHECK_ENABLED(bts);
bts->gprs.nsvc[idx].remote_port = atoi(argv[1]);
/* sockaddr_in and sockaddr_in6 have the port at the same position */
bts->gprs.nsvc[idx].remote.u.sin.sin_port = htons(atoi(argv[1]));
return CMD_SUCCESS;
}
DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd,
"gprs nsvc <0-1> remote ip A.B.C.D",
"gprs nsvc <0-1> remote ip " VTY_IPV46_CMD,
GPRS_TEXT NSVC_TEXT
"GPRS NS Remote IP Address\n"
"GPRS NS Remote IP Address\n"
"GPRS NS Remote IP Address\n")
"GPRS NS Remote IPv4 Address\n"
"GPRS NS Remote IPv6 Address\n")
{
struct gsm_bts *bts = vty->index;
struct osmo_sockaddr_str remote;
int idx = atoi(argv[0]);
struct in_addr ia;
int ret;
GPRS_CHECK_ENABLED(bts);
inet_aton(argv[1], &ia);
bts->gprs.nsvc[idx].remote_ip = ntohl(ia.s_addr);
ret = osmo_sockaddr_str_from_str2(&remote, argv[1]);
if (ret) {
vty_out(vty, "%% Invalid IP address %s%s", argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
/* Can't use osmo_sockaddr_str_to_sockaddr() because the port would be overriden */
bts->gprs.nsvc[idx].remote.u.sas.ss_family = remote.af;
switch (remote.af) {
case AF_INET:
osmo_sockaddr_str_to_in_addr(&remote, &bts->gprs.nsvc[idx].remote.u.sin.sin_addr);
case AF_INET6:
osmo_sockaddr_str_to_in6_addr(&remote, &bts->gprs.nsvc[idx].remote.u.sin6.sin6_addr);
}
return CMD_SUCCESS;
}

View File

@ -227,6 +227,12 @@ static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd)
/* We skip NSVC1 since we only use NSVC0 */
if (nsvc->id == 1)
break;
if (!osmo_bts_has_feature(&bts->features, BTS_FEAT_IPV6_NSVC) &&
nsvc->remote.u.sa.sa_family == AF_INET6) {
LOGP(DLINP, LOGL_ERROR, "BTS %d does not support IPv6 but an IPv6 address was configured!\n", bts->nr);
break;
}
if ((new_state->availability == NM_AVSTATE_OFF_LINE) ||
(new_state->availability == NM_AVSTATE_DEPENDENCY)) {
msgb = nanobts_attr_nscv_get(bts);

View File

@ -24,6 +24,7 @@
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/abis_nm.h>
#include <osmocom/bsc/bts.h>
#include <osmocom/gsm/bts_features.h>
struct msgb *nanobts_attr_bts_get(struct gsm_bts *bts)
{
@ -202,13 +203,33 @@ struct msgb *nanobts_attr_nscv_get(struct gsm_bts *bts)
buf[1] = bts->gprs.nsvc[0].nsvci & 0xff;
msgb_tl16v_put(msgb, NM_ATT_IPACC_NSVCI, 2, buf);
/* remote udp port */
osmo_store16be(bts->gprs.nsvc[0].remote_port, &buf[0]);
/* remote ip address */
osmo_store32be(bts->gprs.nsvc[0].remote_ip, &buf[2]);
/* local udp port */
osmo_store16be(bts->gprs.nsvc[0].local_port, &buf[6]);
msgb_tl16v_put(msgb, NM_ATT_IPACC_NS_LINK_CFG, 8, buf);
switch (bts->gprs.nsvc->remote.u.sa.sa_family) {
case AF_INET6:
/* all fields are encoded in network byte order */
/* protocol family */
buf[0] = OSMO_NSVC_ADDR_IPV6;
/* padding */
buf[1] = 0x00;
/* local udp port */
osmo_store16be(bts->gprs.nsvc[0].local_port, &buf[2]);
/* remote udp port */
memcpy(&buf[4], &bts->gprs.nsvc[0].remote.u.sin6.sin6_port, sizeof(uint16_t));
/* remote ip address */
memcpy(&buf[6], &bts->gprs.nsvc[0].remote.u.sin6.sin6_addr, sizeof(struct in6_addr));
msgb_tl16v_put(msgb, NM_ATT_OSMO_NS_LINK_CFG, 6 + sizeof(struct in6_addr), buf);
break;
case AF_INET:
/* remote udp port */
memcpy(&buf[0], &bts->gprs.nsvc[0].remote.u.sin.sin_port, sizeof(uint16_t));
/* remote ip address */
memcpy(&buf[2], &bts->gprs.nsvc[0].remote.u.sin.sin_addr, sizeof(struct in_addr));
/* local udp port */
osmo_store16be(bts->gprs.nsvc[0].local_port, &buf[6]);
msgb_tl16v_put(msgb, NM_ATT_IPACC_NS_LINK_CFG, 8, buf);
break;
default:
break;
}
return msgb;
}

View File

@ -61,5 +61,7 @@ int bts_model_sysmobts_init(void)
osmo_bts_set_feature(&model_sysmobts.features, BTS_FEAT_EGPRS);
osmo_bts_set_feature(&model_sysmobts.features, BTS_FEAT_PAGING_COORDINATION);
model_sysmobts.nm_att_tlvdef.def[NM_ATT_OSMO_NS_LINK_CFG].type = TLV_TYPE_TL16V;
return gsm_bts_model_register(&model_sysmobts);
}

View File

@ -30,6 +30,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <osmocom/core/byteswap.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
@ -190,10 +191,18 @@ static int pcu_tx_info_ind(struct gsm_bts *bts)
/* NSVC */
for (i = 0; i < ARRAY_SIZE(info_ind->nsvci); i++) {
nsvc = &bts->gprs.nsvc[i];
if (nsvc->remote.u.sa.sa_family == AF_INET6) {
LOGP(DPCU, LOGL_ERROR, "PCU does not support IPv6 NSVC but an IPv6 NSVC was configured!\n");
continue;
}
if (nsvc->remote.u.sa.sa_family != AF_INET)
continue;
info_ind->nsvci[i] = nsvc->nsvci;
info_ind->local_port[i] = nsvc->local_port;
info_ind->remote_port[i] = nsvc->remote_port;
info_ind->remote_ip[i] = nsvc->remote_ip;
info_ind->remote_port[i] = osmo_ntohs(nsvc->remote.u.sin.sin_port);
info_ind->remote_ip[i] = osmo_ntohl(nsvc->remote.u.sin.sin_addr.s_addr);
}
for (i = 0; i < ARRAY_SIZE(info_ind->trx); i++) {

View File

@ -27,6 +27,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/application.h>
#include <osmocom/core/sockaddr_str.h>
#include <stdio.h>
#include <string.h>
@ -263,9 +264,10 @@ int main(int argc, char **argv)
};
/* Parameters needed to test nanobts_attr_nscv_get() */
struct osmo_sockaddr_str addr;
osmo_sockaddr_str_from_str(&addr, "10.9.1.101", 23000);
osmo_sockaddr_str_to_sockaddr(&addr, &bts->gprs.nsvc[0].remote.u.sas);
bts->gprs.nsvc[0].nsvci = 0x65;
bts->gprs.nsvc[0].remote_port = 0x59d8;
bts->gprs.nsvc[0].remote_ip = 0x0a090165;
bts->gprs.nsvc[0].local_port = 0x5a3c;
uint8_t attr_nscv_expected[] =
{ 0x9f, 0x00, 0x02, 0x00, 0x65, 0xa2, 0x00, 0x08, 0x59, 0xd8, 0x0a,
@ -286,6 +288,24 @@ int main(int argc, char **argv)
test_nanobts_attr_nscv_get(bts, attr_nscv_expected);
test_nanobts_attr_radio_get(bts, trx, attr_radio_expected);
/* NSVC IPv6 test */
struct osmo_sockaddr_str addr6;
osmo_sockaddr_str_from_str(&addr6, "fd00:5678:9012:3456:7890:1234:5678:9012", 23010);
osmo_sockaddr_str_to_sockaddr(&addr6, &bts->gprs.nsvc[0].remote.u.sas);
bts->gprs.nsvc[0].nsvci = 0x65;
bts->gprs.nsvc[0].local_port = 0x5a3c;
uint8_t attr_nscv6_expected[] =
/* |- oml attr |-16bit length */
{ 0x9f, 0x00, 0x02, 0x00, 0x65, 0xfd, 0x00, 0x16,
/* 1b type, 1b padding, 2b local port, 2b remote port */
0x29, 0x00, 0x5a, 0x3c, 0x59, 0xe2,
/* 128bit / 16b ipv6 address */
0xfd, 0x00, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
};
test_nanobts_attr_nscv_get(bts, attr_nscv6_expected);
printf("Done\n");
talloc_free(bts);
talloc_free(net);

View File

@ -23,4 +23,9 @@ result= 2d0b0500020362
expected=2d0b0500020362
ok.
Testing nanobts_attr_nscv_get()...
result= 9f00020065fd001629005a3c59e2fd005678901234567890123456789012
expected=9f00020065fd001629005a3c59e2fd005678901234567890123456789012
ok.
Done