diff --git a/contrib/osmo-pfcp-tool-scripts/osmo-upf-11.cfg b/contrib/osmo-pfcp-tool-scripts/osmo-upf-11.cfg index 10ecd8d..d619f54 100644 --- a/contrib/osmo-pfcp-tool-scripts/osmo-upf-11.cfg +++ b/contrib/osmo-pfcp-tool-scripts/osmo-upf-11.cfg @@ -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 diff --git a/contrib/osmo-pfcp-tool-scripts/osmo-upf-12.cfg b/contrib/osmo-pfcp-tool-scripts/osmo-upf-12.cfg index 272301a..8b77417 100644 --- a/contrib/osmo-pfcp-tool-scripts/osmo-upf-12.cfg +++ b/contrib/osmo-pfcp-tool-scripts/osmo-upf-12.cfg @@ -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 diff --git a/contrib/osmo-pfcp-tool-scripts/session_est_without_assoc.vty b/contrib/osmo-pfcp-tool-scripts/session_est_without_assoc.vty index 4ca669a..2efc68e 100644 --- a/contrib/osmo-pfcp-tool-scripts/session_est_without_assoc.vty +++ b/contrib/osmo-pfcp-tool-scripts/session_est_without_assoc.vty @@ -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 diff --git a/contrib/osmo-pfcp-tool-scripts/session_mod.vty b/contrib/osmo-pfcp-tool-scripts/session_mod.vty index 7645c05..58760a7 100644 --- a/contrib/osmo-pfcp-tool-scripts/session_mod.vty +++ b/contrib/osmo-pfcp-tool-scripts/session_mod.vty @@ -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 diff --git a/contrib/osmo-pfcp-tool-scripts/tunend_plus_tunmap.vty b/contrib/osmo-pfcp-tool-scripts/tunend_plus_tunmap.vty index 1cfcd6d..206766c 100644 --- a/contrib/osmo-pfcp-tool-scripts/tunend_plus_tunmap.vty +++ b/contrib/osmo-pfcp-tool-scripts/tunend_plus_tunmap.vty @@ -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 diff --git a/contrib/osmo-pfcp-tool-scripts/tunend_session_est.vty b/contrib/osmo-pfcp-tool-scripts/tunend_session_est.vty index 3862c15..89a4629 100644 --- a/contrib/osmo-pfcp-tool-scripts/tunend_session_est.vty +++ b/contrib/osmo-pfcp-tool-scripts/tunend_session_est.vty @@ -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 diff --git a/contrib/osmo-pfcp-tool-scripts/tunmap_session_est.vty b/contrib/osmo-pfcp-tool-scripts/tunmap_session_est.vty index b01b088..bff069c 100644 --- a/contrib/osmo-pfcp-tool-scripts/tunmap_session_est.vty +++ b/contrib/osmo-pfcp-tool-scripts/tunmap_session_est.vty @@ -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 diff --git a/src/osmo-pfcp-tool/pfcp_tool.c b/src/osmo-pfcp-tool/pfcp_tool.c index ae77f64..fcad7fd 100644 --- a/src/osmo-pfcp-tool/pfcp_tool.c +++ b/src/osmo-pfcp-tool/pfcp_tool.c @@ -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; diff --git a/src/osmo-pfcp-tool/pfcp_tool.h b/src/osmo-pfcp-tool/pfcp_tool.h index 9f04efd..dbfbb23 100644 --- a/src/osmo-pfcp-tool/pfcp_tool.h +++ b/src/osmo-pfcp-tool/pfcp_tool.h @@ -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 { diff --git a/src/osmo-pfcp-tool/pfcp_tool_vty.c b/src/osmo-pfcp-tool/pfcp_tool_vty.c index fcdbd67..dd76f9e 100644 --- a/src/osmo-pfcp-tool/pfcp_tool_vty.c +++ b/src/osmo-pfcp-tool/pfcp_tool_vty.c @@ -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); }