blob: c5cca747ee308a17e9b1996b57d5d055ef1be127 [file] [log] [blame]
Harald Weltef7365592020-04-15 21:48:45 +02001#include <string.h>
2#include <stdint.h>
3#include <inttypes.h>
4#include <netinet/in.h>
5#include <arpa/inet.h>
6#include <netdb.h>
7
8#include <osmocom/core/talloc.h>
9#include <osmocom/core/utils.h>
10#include <osmocom/core/rate_ctr.h>
11
12#include <osmocom/vty/command.h>
13#include <osmocom/vty/vty.h>
14#include <osmocom/vty/misc.h>
15
16#include "internal.h"
17#include "gtp.h"
18
19#define TUN_STR "tun device commands\n"
20#define GTP_EP_STR "GTP endpoint commands\n"
21#define TUNNEL_STR "GTP tunnel commands\n"
22
23static void show_tun_hdr(struct vty *vty)
24{
25 vty_out(vty,
26 " tun device name | netwk namespace | use count%s", VTY_NEWLINE);
27 vty_out(vty,
28 "---------------- | ---------------- | ---------%s", VTY_NEWLINE);
29}
30
31static void show_one_tun(struct vty *vty, const struct tun_device *tun)
32{
33 vty_out(vty, "%16s | %16s | %lu%s",
34 tun->devname, tun->netns_name, tun->use_count, VTY_NEWLINE);
35}
36
37DEFUN(show_tun, show_tun_cmd,
38 "show tun-device [IFNAME]",
39 SHOW_STR TUN_STR
40 "Name of TUN network device\n")
41{
42 struct tun_device *tun;
43
44 show_tun_hdr(vty);
45 pthread_rwlock_rdlock(&g_daemon->rwlock);
46 if (argc) {
47 tun = _tun_device_find(g_daemon, argv[0]);
48 if (!tun) {
49 pthread_rwlock_unlock(&g_daemon->rwlock);
50 vty_out(vty, "Cannot find TUN device '%s'%s", argv[0], VTY_NEWLINE);
51 return CMD_WARNING;
52 }
53 show_one_tun(vty, tun);
54 } else {
55 llist_for_each_entry(tun, &g_daemon->tun_devices, list)
56 show_one_tun(vty, tun);
57 }
58 pthread_rwlock_unlock(&g_daemon->rwlock);
59
60 return CMD_SUCCESS;
61}
62
63DEFUN(tun_create, tun_create_cmd,
64 "tun-device create IFNAME [NETNS]",
65 TUN_STR "Create a new TUN interface\n"
66 "Name of TUN network device\n"
67 "Name of network namespace for tun device\n"
68 )
69{
70 struct tun_device *tun;
71 const char *ifname = argv[0];
72 const char *netns_name = NULL;
73
74 if (argc > 1)
75 netns_name = argv[1];
76
77 tun = tun_device_find_or_create(g_daemon, ifname, netns_name);
78 if (!tun) {
79 vty_out(vty, "Error creating TUN%s", VTY_NEWLINE);
80 return CMD_WARNING;
81 }
82
83 return CMD_SUCCESS;
84}
85
86DEFUN(tun_destroy, tun_destroy_cmd,
87 "tun-device destroy IFNAME",
88 TUN_STR "Destroy a TUN interface\n"
89 "Name of TUN network device\n"
90 )
91{
92 struct tun_device *tun;
93 const char *ifname = argv[0];
94
95 pthread_rwlock_wrlock(&g_daemon->rwlock);
96 tun = _tun_device_find(g_daemon, ifname);
97 if (!tun) {
98 pthread_rwlock_unlock(&g_daemon->rwlock);
99 vty_out(vty, "Cannot destrory non-existant TUN%s", VTY_NEWLINE);
100 return CMD_WARNING;
101 }
Pau Espin Pedrola459b5c2022-04-11 17:00:36 +0200102 _tun_device_deref_release(tun);
Harald Weltef7365592020-04-15 21:48:45 +0200103 pthread_rwlock_unlock(&g_daemon->rwlock);
104
105 return CMD_SUCCESS;
106}
107
108
109static void show_ep_hdr(struct vty *vty)
110{
111 vty_out(vty,
112 " address port | use count%s", VTY_NEWLINE);
113 vty_out(vty,
114 " ------------------------------- | ---------%s", VTY_NEWLINE);
115}
116
117static void show_one_ep(struct vty *vty, const struct gtp_endpoint *ep)
118{
119 vty_out(vty, "%32s | %lu%s",
120 ep->name, ep->use_count, VTY_NEWLINE);
121
122}
123
124DEFUN(show_gtp, show_gtp_cmd,
125 "show gtp-endpoint [(A.B.C.D|X:X::X:X) [<0-65535>]]",
126 SHOW_STR GTP_EP_STR
127 "Local IP address\n" "Local UDP Port\n")
128{
129 struct gtp_endpoint *ep;
Harald Weltef23abd72020-04-20 12:09:32 +0200130 struct addrinfo *ai = NULL;
Harald Weltef7365592020-04-15 21:48:45 +0200131 const char *ipstr;
132 uint16_t port = GTP1U_PORT;
133
134 if (argc > 0) {
135 ipstr = argv[0];
136 if (argc > 1)
137 port = atoi(argv[1]);
138
139 ai = addrinfo_helper(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, ipstr, port, true);
140 if (!ai) {
141 vty_out(vty, "Error parsing IP/Port%s", VTY_NEWLINE);
142 return CMD_WARNING;
143 }
144 }
145
146 show_ep_hdr(vty);
147 pthread_rwlock_rdlock(&g_daemon->rwlock);
Harald Weltee36dbcb2023-07-18 14:35:41 +0200148 if (argc > 0) {
Harald Weltef7365592020-04-15 21:48:45 +0200149 ep = _gtp_endpoint_find(g_daemon, (const struct sockaddr_storage *) ai->ai_addr);
150 if (!ep) {
151 pthread_rwlock_unlock(&g_daemon->rwlock);
152 vty_out(vty, "Cannot find GTP endpoint %s:%s%s", argv[0], argv[1], VTY_NEWLINE);
153 freeaddrinfo(ai);
154 return CMD_WARNING;
155 }
156 show_one_ep(vty, ep);
157 } else {
158 llist_for_each_entry(ep, &g_daemon->gtp_endpoints, list)
159 show_one_ep(vty, ep);
160 }
161 pthread_rwlock_unlock(&g_daemon->rwlock);
162
163 freeaddrinfo(ai);
164 return CMD_SUCCESS;
165}
166
167DEFUN(gtp_create, gtp_create_cmd,
168 "gtp-endpoint create (A.B.C.D|X:X::X:X) [<0-65535>]",
169 GTP_EP_STR "Create a new GTP endpoint (UDP socket)\n"
170 "Local IP address\n" "Local UDP Port\n")
171{
172 struct addrinfo *ai;
173 struct gtp_endpoint *ep;
174 const char *ipstr = argv[0];
175 uint16_t port = GTP1U_PORT;
176
177 if (argc > 1)
178 port = atoi(argv[1]);
179
180 ai = addrinfo_helper(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, ipstr, port, true);
181 if (!ai) {
182 vty_out(vty, "Error parsing IP/Port%s", VTY_NEWLINE);
183 return CMD_WARNING;
184 }
185
186 ep = gtp_endpoint_find_or_create(g_daemon, (struct sockaddr_storage *) ai->ai_addr);
187 if (!ep) {
188 vty_out(vty, "Error creating endpoint%s", VTY_NEWLINE);
189 freeaddrinfo(ai);
190 return CMD_WARNING;
191 }
192
193 freeaddrinfo(ai);
194 return CMD_SUCCESS;
195}
196
197DEFUN(gtp_destroy, gtp_destroy_cmd,
198 "gtp-endpoint destroy (A.B.C.D|X:X::X:X) [<0-65535>]",
199 GTP_EP_STR "Destroy a GTP endpoint\n"
200 "Local IP address\n" "Local UDP Port\n")
201{
202 struct addrinfo *ai;
203 struct gtp_endpoint *ep;
204 const char *ipstr = argv[0];
205 uint16_t port = GTP1U_PORT;
206
207 if (argc > 1)
208 port = atoi(argv[1]);
209
210 ai = addrinfo_helper(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, ipstr, port, true);
211 if (!ai) {
212 vty_out(vty, "Error parsing IP/Port%s", VTY_NEWLINE);
213 return CMD_WARNING;
214 }
215
216 pthread_rwlock_wrlock(&g_daemon->rwlock);
217 ep = _gtp_endpoint_find(g_daemon, (struct sockaddr_storage *) ai->ai_addr);
218 if (!ep) {
219 pthread_rwlock_unlock(&g_daemon->rwlock);
220 vty_out(vty, "Cannot find to-be-destoryed endpoint%s", VTY_NEWLINE);
221 freeaddrinfo(ai);
222 return CMD_WARNING;
223 }
224 _gtp_endpoint_deref_destroy(ep);
225 pthread_rwlock_unlock(&g_daemon->rwlock);
226
227 freeaddrinfo(ai);
228 return CMD_SUCCESS;
229}
230
231static void show_one_tunnel(struct vty *vty, const struct gtp_tunnel *t)
232{
233 char remote_ip[64], remote_port[16], user_addr[64];
234
235 getnameinfo((struct sockaddr *) &t->remote_udp, sizeof(t->remote_udp),
236 remote_ip, sizeof(remote_ip), remote_port, sizeof(remote_port),
237 NI_NUMERICHOST|NI_NUMERICSERV);
238
239 getnameinfo((struct sockaddr *) &t->user_addr, sizeof(t->user_addr),
240 user_addr, sizeof(user_addr), NULL, 0,
241 NI_NUMERICHOST|NI_NUMERICSERV);
242
243
244 vty_out(vty, "%s/%08X - %s:%s/%08X %s(%s) %s%s",
245 t->gtp_ep->name, t->rx_teid, remote_ip, remote_port, t->tx_teid,
246 t->tun_dev->devname, t->tun_dev->netns_name, user_addr, VTY_NEWLINE);
247}
248
249DEFUN(show_tunnel, show_tunnel_cmd,
250 "show gtp-tunnel",
251 SHOW_STR TUNNEL_STR)
252{
253 struct gtp_tunnel *t;
254
255 pthread_rwlock_rdlock(&g_daemon->rwlock);
256 llist_for_each_entry(t, &g_daemon->gtp_tunnels, list) {
257 show_one_tunnel(vty, t);
258 }
259 pthread_rwlock_unlock(&g_daemon->rwlock);
260 return CMD_SUCCESS;
261}
262
Harald Welte8362efe2020-04-26 22:42:02 +0200263#define UECUPS_NODE (_LAST_OSMOVTY_NODE+1)
264
265static struct cmd_node uecups_node = {
266 UECUPS_NODE,
267 "%s(config-uecups)# ",
268 1,
269};
270
271static int config_write_uecups(struct vty *vty)
272{
273 vty_out(vty, "uecups%s", VTY_NEWLINE);
274 vty_out(vty, " local-ip %s%s", g_daemon->cfg.cups_local_ip, VTY_NEWLINE);
275
276 return CMD_SUCCESS;
277}
278
279DEFUN(cfg_uecups, cfg_uecups_cmd,
280 "uecups",
281 "Configure the UE Control/User Plane Socket\n")
282{
283 vty->node = UECUPS_NODE;
284 return CMD_SUCCESS;
285}
286
287DEFUN(cfg_uecups_local_ip, cfg_uecups_local_ip_cmd,
288 "local-ip A.B.C.D",
289 "Set the IP address to which we bind locally\n"
290 "IP Address\n")
291{
292 osmo_talloc_replace_string(g_daemon, &g_daemon->cfg.cups_local_ip, argv[0]);
293 return CMD_SUCCESS;
294}
295
Harald Weltef7365592020-04-15 21:48:45 +0200296
297int gtpud_vty_init(void)
298{
299 install_element_ve(&show_tun_cmd);
300 install_element(ENABLE_NODE, &tun_create_cmd);
301 install_element(ENABLE_NODE, &tun_destroy_cmd);
302
303 install_element_ve(&show_gtp_cmd);
304 install_element(ENABLE_NODE, &gtp_create_cmd);
305 install_element(ENABLE_NODE, &gtp_destroy_cmd);
306
307 install_element_ve(&show_tunnel_cmd);
308
Harald Welte8362efe2020-04-26 22:42:02 +0200309 install_element(CONFIG_NODE, &cfg_uecups_cmd);
310 install_node(&uecups_node, config_write_uecups);
311 install_element(UECUPS_NODE, &cfg_uecups_local_ip_cmd);
312
Harald Weltef7365592020-04-15 21:48:45 +0200313 return 0;
314}
315
316
317static const char copyright[] =
318 "Copyright (C) 2020 Harald Welte <laforge@gnumonks.org>\r\n"
319 "License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl-2.0.html>\r\n"
320 "This is free software: you are free to change and redistribute it.\r\n"
321 "There is NO WARRANTY, to the extent permitted by law.\r\n";
322
323struct vty_app_info g_vty_info = {
324 .name = "osmo-gtpud",
325 .version = PACKAGE_VERSION,
326 .copyright = copyright,
327};