osmo_pfcp_tool: make usable again

Some things in osmo-upf and libosmo-pfcp have changed without accounting
for that in osmo-pfcp-tool. (This tool is not that important, forgive me
for submitting various changes in one patch.)

Properly represent all of {access,core} x {local,remote} GTP F-TEIDs in
the internal osmo-pfcp-tool state.

Adjust and clarify osmo-pfcp-tool script commands.

Adjust the osmo-pfcp-tool scripts in contrib so that they work again.

Change-Id: I22cfaa4aedd465c81de85e673b9960eaf99c426b
This commit is contained in:
Neels Hofmeyr 2023-02-06 00:42:43 +01:00
parent 6c01708438
commit d8742f79ca
10 changed files with 176 additions and 111 deletions

View File

@ -23,5 +23,3 @@ pfcp
local-addr 127.0.0.11
tunend
dev create apn11 127.0.0.11
tunmap
table-name osmo-upf-11

View File

@ -21,7 +21,5 @@ ctrl
timer pfcp x24 5000
pfcp
local-addr 127.0.0.12
tunend
dev create apn12 127.0.0.12
tunmap
table-name osmo-upf-12

View File

@ -1,4 +1,6 @@
timer pfcp x23 0
pfcp-peer 127.0.0.1
session tunend
ue ip 127.127.127.127
gtp access remote f-teid 127.0.0.127 127
tx session-est-req

View File

@ -3,12 +3,14 @@ pfcp-peer 127.0.0.1
tx assoc-setup-req
sleep 1
session
ue ip 127.127.127.127
gtp access remote f-teid 127.0.0.127 127
tx session-est-req drop
sleep 3
tx session-mod-req forw
tx session-mod-req far forw
sleep 5
tx session-mod-req drop
tx session-mod-req far drop
sleep 3
tx session-mod-req forw
tx session-mod-req far forw
sleep 3
tx session-del-req

View File

@ -1,4 +1,4 @@
# ACCESS HOP CORE
# ACCESS UPF tunmap UPF tunend (CORE)
# session 23 = tunmap session 42 = encaps/decaps
# GTP 127.0.0.13 127.0.0.12 127.0.0.11
# TEID l:23 r:123 <---> r:23 l:123 | l:142 r:42 <---> r:142 l:42 | 192.168.100.42
@ -13,8 +13,8 @@ pfcp-peer 127.0.0.11
sleep 1
session tunend 42
ue ip 192.168.100.42
gtp access ip 127.0.0.12
gtp access teid local 42 remote 142
gtp access local f-teid 127.0.0.11 42
gtp access remote f-teid 127.0.0.12 142
tx session-est-req
sleep 1
@ -22,9 +22,9 @@ pfcp-peer 127.0.0.12
tx assoc-setup-req
sleep 1
session tunmap 23
gtp core ip 127.0.0.11
gtp core teid local 142 remote 42
gtp access ip 127.0.0.13
gtp access teid local 123 remote 23
gtp core remote f-teid 127.0.0.11 42
gtp core local f-teid 127.0.0.12 142
gtp access local f-teid 127.0.0.12 123
gtp access remote f-teid 127.0.0.13 23
tx session-est-req
sleep 1

View File

@ -3,6 +3,9 @@ pfcp-peer 127.0.0.1
tx assoc-setup-req
sleep 1
session tunend
ue ip 127.127.127.127
gtp access local f-teid choose
gtp access remote f-teid 127.0.0.12 142
tx session-est-req forw
sleep 5
tx session-del-req

View File

@ -3,6 +3,10 @@ pfcp-peer 127.0.0.1
tx assoc-setup-req
sleep 1
session tunmap
gtp core remote f-teid 127.0.0.11 42
gtp core local f-teid choose
gtp access local f-teid choose
gtp access remote f-teid 127.0.0.13 23
tx session-est-req
sleep 5
tx session-del-req

View File

@ -85,7 +85,7 @@ struct pfcp_tool_session *pfcp_tool_session_find(struct pfcp_tool_peer *peer, ui
}
struct pfcp_tool_session *pfcp_tool_session_find_or_create(struct pfcp_tool_peer *peer, uint64_t cp_seid,
enum up_gtp_action_kind gtp_action)
enum up_gtp_action_kind kind)
{
struct pfcp_tool_session *session = pfcp_tool_session_find(peer, cp_seid);
if (session)
@ -95,7 +95,7 @@ struct pfcp_tool_session *pfcp_tool_session_find_or_create(struct pfcp_tool_peer
*session = (struct pfcp_tool_session){
.peer = peer,
.cp_seid = cp_seid,
.gtp_action = gtp_action,
.kind = kind,
};
llist_add(&session->entry, &peer->sessions);
return session;

View File

@ -51,30 +51,43 @@ struct pfcp_tool_peer {
struct llist_head sessions;
};
struct pfcp_tool_teid_pair {
uint32_t local;
uint32_t remote;
struct pfcp_tool_gtp_tun_ep {
struct osmo_sockaddr_str addr;
uint32_t teid;
};
struct pfcp_tool_gtp_tun {
struct pfcp_tool_gtp_tun_ep local;
struct pfcp_tool_gtp_tun_ep remote;
};
struct pfcp_tool_tunend_desc {
struct pfcp_tool_gtp_tun access;
struct {
struct osmo_sockaddr_str ue_local_addr;
} core;
};
struct pfcp_tool_tunmap_desc {
struct pfcp_tool_gtp_tun access;
struct pfcp_tool_gtp_tun core;
};
struct pfcp_tool_session {
struct llist_head entry;
enum up_gtp_action_kind gtp_action;
struct pfcp_tool_peer *peer;
uint64_t cp_seid;
struct osmo_pfcp_ie_f_seid up_f_seid;
struct {
struct pfcp_tool_teid_pair teid;
struct osmo_sockaddr_str gtp_ip;
} access;
enum up_gtp_action_kind kind;
union {
/* En-/De-capsulate GTP: add/remove a GTP header and forward the GTP payload from/to plain IP. */
struct pfcp_tool_tunend_desc tunend;
struct {
struct pfcp_tool_teid_pair teid;
struct osmo_sockaddr_str gtp_ip;
struct osmo_sockaddr_str ue_addr;
} core;
/* Tunnel-map GTP: translate from one TEID to another and forward */
struct pfcp_tool_tunmap_desc tunmap;
};
};
struct g_pfcp_tool {

View File

@ -234,7 +234,7 @@ DEFUN(peer_retrans_req, peer_retrans_req_cmd,
else
*m = peer->last_resp;
OSMO_LOG_PFCP_MSG(m, LOGL_DEBUG, "retrans %s\n", argv[0]);
OSMO_LOG_PFCP_MSG(m, LOGL_INFO, "retrans %s\n", argv[0]);
rc = osmo_pfcp_endpoint_tx_data(g_pfcp_tool->ep, m);
if (rc) {
@ -261,15 +261,15 @@ DEFUN(session, session_cmd,
{
struct pfcp_tool_peer *peer = vty->index;
struct pfcp_tool_session *session;
enum up_gtp_action_kind gtp_action = UP_GTP_U_TUNEND;
enum up_gtp_action_kind kind = UP_GTP_U_TUNEND;
if (argc > 0 && !strcmp(argv[0], "tunmap"))
gtp_action = UP_GTP_U_TUNMAP;
kind = UP_GTP_U_TUNMAP;
if (argc > 1)
session = pfcp_tool_session_find_or_create(peer, atoll(argv[1]), gtp_action);
session = pfcp_tool_session_find_or_create(peer, atoll(argv[1]), kind);
else
session = pfcp_tool_session_find_or_create(peer, peer_new_seid(peer), gtp_action);
session = pfcp_tool_session_find_or_create(peer, peer_new_seid(peer), kind);
vty->index = session;
vty->node = SESSION_NODE;
@ -288,54 +288,112 @@ DEFUN(s_ue, s_ue_cmd,
"IP address assigned to the UE\n")
{
struct pfcp_tool_session *session = vty->index;
if (osmo_sockaddr_str_from_str2(&session->core.ue_addr, argv[0])) {
if (session->kind != UP_GTP_U_TUNEND) {
vty_out(vty, "%% Error: 'ue ip' makes no sense in a 'tunmap' session%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (osmo_sockaddr_str_from_str2(&session->tunend.core.ue_local_addr, argv[0])) {
vty_out(vty, "Error setting UE IP address%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(s_teid, s_teid_cmd,
"gtp (access|core) teid local <0-4294967295> remote <0-4294967295>",
"Setup TEID used in GTP\n"
"Set the TEIDs towards the ACCESS network (towards the radio network and the actual UE)\n"
"Set the TEIDs towards the CORE network (towards the internet)\n"
"Local TEID, which the UPF expects to see in incoming GTP packets\n"
"Local TEID, when 0 tell the UPF to choose (PFCP: FAR F-TEID: CHOOSE=1)\n"
"Remote TEID, which the UPF sends out in GTP packets\n"
"Remote TEID, which the GTP peer has assigned for itself\n")
#define GTP_ACCESS_CORE_STRS \
"Setup GTP\n" \
"Setup GTP towards ACCESS (towards the radio network and the actual UE)\n" \
"Setup GTP towards CORE (towards the internet)\n"
#define GTP_LOCAL_STR "Setup GTP on the local side (UPF's local GTP endpoint)\n"
#define GTP_REMOTE_STR "Setup GTP on the remote side (UPF's remote GTP peer)\n"
#define F_TEID_STR "Set the fully-qualified TEID, i.e. GTP IP address and TEID\n"
DEFUN(s_f_teid, s_f_teid_cmd,
"gtp (access|core) (local|remote) f-teid A.B.C.D <0-4294967295>",
GTP_ACCESS_CORE_STRS
GTP_LOCAL_STR GTP_REMOTE_STR
F_TEID_STR
"GTP peer IP address\n"
"GTP TEID\n")
{
struct pfcp_tool_session *session = vty->index;
struct pfcp_tool_teid_pair *dst;
if (!strcmp(argv[0], "access"))
dst = &session->access.teid;
else
dst = &session->core.teid;
*dst = (struct pfcp_tool_teid_pair){
.local = atoi(argv[1]),
.remote = atoi(argv[2]),
};
const char *tun_side = argv[0];
const char *local_remote = argv[1];
const char *addr_str = argv[2];
const char *teid_str = argv[3];
struct pfcp_tool_gtp_tun_ep *dst;
switch (session->kind) {
case UP_GTP_U_TUNEND:
if (!strcmp(tun_side, "access")) {
if (!strcmp(local_remote, "local"))
dst = &session->tunend.access.local;
else
dst = &session->tunend.access.remote;
} else {
vty_out(vty, "%% Error: 'gtp core (local|remote) f-teid': 'tunend' only has GTP on"
" the 'access' side%s", VTY_NEWLINE);
return CMD_WARNING;
}
break;
case UP_GTP_U_TUNMAP:
if (!strcmp(tun_side, "access")) {
if (!strcmp(local_remote, "local"))
dst = &session->tunmap.access.local;
else
dst = &session->tunmap.access.remote;
} else {
if (!strcmp(local_remote, "local"))
dst = &session->tunmap.core.local;
else
dst = &session->tunmap.core.remote;
}
break;
default:
OSMO_ASSERT(0);
}
if (osmo_sockaddr_str_from_str2(&dst->addr, addr_str)) {
vty_out(vty, "Error setting GTP IP address from %s%s",
osmo_quote_cstr_c(OTC_SELECT, addr_str, -1), VTY_NEWLINE);
return CMD_WARNING;
}
dst->teid = atoi(teid_str);
return CMD_SUCCESS;
}
DEFUN(s_gtp, s_gtp_cmd,
"gtp (access|core) ip A.B.C.D",
"Setup GTP peer\n"
"Set the GTP peer towards the ACCESS network (towards the radio network and the actual UE)\n"
"Set the GTP peer towards the CORE network (towards the internet)\n"
"Set the GTP peer IP address, where to send GTP packets to / receive GTP packets from\n"
"GTP peer IP address\n")
DEFUN(s_f_teid_choose, s_f_teid_choose_cmd,
"gtp (access|core) local f-teid choose",
GTP_ACCESS_CORE_STRS
GTP_LOCAL_STR
F_TEID_STR
"Send F-TEID with CHOOSE=1, i.e. the UPF shall return the local F-TEID in a PFCP Created PDR IE\n")
{
struct pfcp_tool_session *session = vty->index;
struct osmo_sockaddr_str *dst;
if (!strcmp(argv[0], "access"))
dst = &session->access.gtp_ip;
else
dst = &session->core.gtp_ip;
if (osmo_sockaddr_str_from_str2(dst, argv[1])) {
vty_out(vty, "Error setting GTP IP address%s", VTY_NEWLINE);
return CMD_WARNING;
const char *tun_side = argv[0];
struct pfcp_tool_gtp_tun_ep *dst;
switch (session->kind) {
case UP_GTP_U_TUNEND:
if (!strcmp(tun_side, "access")) {
dst = &session->tunend.access.local;
} else {
vty_out(vty, "%% Error: 'gtp core local choose': 'tunend' only has GTP on"
" the 'access' side%s", VTY_NEWLINE);
return CMD_WARNING;
}
break;
case UP_GTP_U_TUNMAP:
if (!strcmp(tun_side, "access"))
dst = &session->tunmap.access.local;
else
dst = &session->tunmap.core.local;
break;
default:
OSMO_ASSERT(0);
}
*dst = (struct pfcp_tool_gtp_tun_ep){};
return CMD_SUCCESS;
}
@ -351,6 +409,8 @@ int session_tunend_tx_est_req(struct vty *vty, const char **argv, int argc)
struct osmo_sockaddr ue_addr;
struct osmo_pfcp_ie_f_seid cp_f_seid;
OSMO_ASSERT(session->kind == UP_GTP_U_TUNEND);
if (!g_pfcp_tool->ep) {
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
return CMD_WARNING;
@ -361,12 +421,17 @@ int session_tunend_tx_est_req(struct vty *vty, const char **argv, int argc)
else
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_FORW, true);
if (osmo_sockaddr_str_to_sockaddr(&session->core.ue_addr, &ue_addr.u.sas)) {
vty_out(vty, "Error in UE IP%s", VTY_NEWLINE);
return CMD_WARNING;
}
#define STR_TO_ADDR(DST, SRC) do { \
if (osmo_sockaddr_str_to_sockaddr(&SRC, &DST.u.sas)) { \
vty_out(vty, "Error in " #SRC ": " OSMO_SOCKADDR_STR_FMT "%s", \
OSMO_SOCKADDR_STR_FMT_ARGS(&SRC), VTY_NEWLINE); \
return CMD_WARNING; \
} \
} while (0)
if (session->access.teid.local == 0) {
STR_TO_ADDR(ue_addr, session->tunend.core.ue_local_addr);
if (session->tunend.access.local.teid == 0) {
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
.choose_flag = true,
.choose = {
@ -376,29 +441,22 @@ int session_tunend_tx_est_req(struct vty *vty, const char **argv, int argc)
} else {
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
.fixed = {
.teid = session->access.teid.local,
.teid = session->tunend.access.local.teid,
.ip_addr = {
.v4_present = true,
.v4 = osmo_pfcp_endpoint_get_cfg(g_pfcp_tool->ep)->local_addr,
},
},
};
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &f_teid_access_local.fixed.ip_addr.v4.u.sas)) {
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
return CMD_WARNING;
}
STR_TO_ADDR(f_teid_access_local.fixed.ip_addr.v4, session->tunend.access.local.addr);
}
ohc_access = (struct osmo_pfcp_ie_outer_header_creation){
.teid_present = true,
.teid = session->access.teid.remote,
.teid = session->tunend.access.remote.teid,
.ip_addr.v4_present = true,
};
osmo_pfcp_bits_set(ohc_access.desc_bits, OSMO_PFCP_OUTER_HEADER_CREATION_GTP_U_UDP_IPV4, true);
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &ohc_access.ip_addr.v4.u.sas)) {
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
return CMD_WARNING;
}
STR_TO_ADDR(ohc_access.ip_addr.v4, session->tunend.access.remote.addr);
cp_f_seid = (struct osmo_pfcp_ie_f_seid){
.seid = session->cp_seid,
@ -507,7 +565,7 @@ int session_tunmap_tx_est_req(struct vty *vty, const char **argv, int argc)
else
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_FORW, true);
if (session->access.teid.local == 0) {
if (session->tunmap.access.local.teid == 0) {
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
.choose_flag = true,
.choose = {
@ -517,31 +575,25 @@ int session_tunmap_tx_est_req(struct vty *vty, const char **argv, int argc)
} else {
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
.fixed = {
.teid = session->access.teid.local,
.teid = session->tunmap.access.local.teid,
.ip_addr = {
.v4_present = true,
.v4 = osmo_pfcp_endpoint_get_cfg(g_pfcp_tool->ep)->local_addr,
},
},
};
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &f_teid_access_local.fixed.ip_addr.v4.u.sas)) {
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
return CMD_WARNING;
}
STR_TO_ADDR(f_teid_access_local.fixed.ip_addr.v4, session->tunmap.access.local.addr);
}
ohc_access = (struct osmo_pfcp_ie_outer_header_creation){
.teid_present = true,
.teid = session->access.teid.remote,
.teid = session->tunmap.access.remote.teid,
.ip_addr.v4_present = true,
};
osmo_pfcp_bits_set(ohc_access.desc_bits, OSMO_PFCP_OUTER_HEADER_CREATION_GTP_U_UDP_IPV4, true);
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &ohc_access.ip_addr.v4.u.sas)) {
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
return CMD_WARNING;
}
STR_TO_ADDR(ohc_access.ip_addr.v4, session->tunmap.access.remote.addr);
if (session->core.teid.local == 0) {
if (session->tunmap.core.local.teid == 0) {
f_teid_core_local = (struct osmo_pfcp_ie_f_teid){
.choose_flag = true,
.choose = {
@ -551,28 +603,21 @@ int session_tunmap_tx_est_req(struct vty *vty, const char **argv, int argc)
} else {
f_teid_core_local = (struct osmo_pfcp_ie_f_teid){
.fixed = {
.teid = session->core.teid.local,
.teid = session->tunmap.core.local.teid,
.ip_addr = {
.v4_present = true,
.v4 = osmo_pfcp_endpoint_get_cfg(g_pfcp_tool->ep)->local_addr,
},
},
};
if (osmo_sockaddr_str_to_sockaddr(&session->core.gtp_ip, &f_teid_core_local.fixed.ip_addr.v4.u.sas)) {
vty_out(vty, "Error in GTP IP towards Core%s", VTY_NEWLINE);
return CMD_WARNING;
}
STR_TO_ADDR(f_teid_core_local.fixed.ip_addr.v4, session->tunmap.core.local.addr);
}
ohc_core = (struct osmo_pfcp_ie_outer_header_creation){
.teid_present = true,
.teid = session->core.teid.remote,
.teid = session->tunmap.core.remote.teid,
.ip_addr.v4_present = true,
};
osmo_pfcp_bits_set(ohc_core.desc_bits, OSMO_PFCP_OUTER_HEADER_CREATION_GTP_U_UDP_IPV4, true);
if (osmo_sockaddr_str_to_sockaddr(&session->core.gtp_ip, &ohc_core.ip_addr.v4.u.sas)) {
vty_out(vty, "Error in GTP IP towards Core%s", VTY_NEWLINE);
return CMD_WARNING;
}
STR_TO_ADDR(ohc_core.ip_addr.v4, session->tunmap.core.remote.addr);
cp_f_seid = (struct osmo_pfcp_ie_f_seid){
.seid = session->cp_seid,
@ -660,7 +705,7 @@ DEFUN(session_tx_est_req, session_tx_est_req_cmd,
"Set FAR to DROP = 1\n")
{
struct pfcp_tool_session *session = vty->index;
switch (session->gtp_action) {
switch (session->kind) {
case UP_GTP_U_TUNEND:
return session_tunend_tx_est_req(vty, argv, argc);
case UP_GTP_U_TUNMAP:
@ -790,6 +835,6 @@ void pfcp_tool_vty_init_cmds()
install_element(SESSION_NODE, &session_tx_mod_req_cmd);
install_element(SESSION_NODE, &session_tx_del_req_cmd);
install_element(SESSION_NODE, &s_ue_cmd);
install_element(SESSION_NODE, &s_gtp_cmd);
install_element(SESSION_NODE, &s_teid_cmd);
install_element(SESSION_NODE, &s_f_teid_cmd);
install_element(SESSION_NODE, &s_f_teid_choose_cmd);
}