forked from acouzens/open5gs
Add tuntap interface to PGW
This commit is contained in:
parent
bebf14e361
commit
4b9e499ea7
|
@ -266,6 +266,11 @@ CORE_DECLARE(int) net_unregister_link(net_link_t *net_link);
|
|||
*/
|
||||
CORE_DECLARE(int) net_fds_read_run(long timeout);
|
||||
|
||||
/** TunTap interface */
|
||||
CORE_DECLARE(int) net_tuntap_open(net_link_t **net_link, char *tuntap_dev_name,
|
||||
int is_tap);
|
||||
|
||||
CORE_DECLARE(int) net_tuntap_close(net_link_t *net_link);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#if LINUX == 1
|
||||
#include <netpacket/packet.h>
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#define NET_FD_TYPE_SOCK 0
|
||||
|
@ -1170,6 +1171,53 @@ int net_raw_open(net_link_t **net_link, int proto)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Create tuntap socket */
|
||||
int net_tuntap_open(net_link_t **net_link, char *tuntap_dev_name,
|
||||
int is_tap)
|
||||
{
|
||||
int rc,sock;
|
||||
net_link_t *new_link = NULL;
|
||||
char *dev = "/dev/net/tun";
|
||||
struct ifreq ifr;
|
||||
int flags = IFF_NO_PI;
|
||||
|
||||
sock = open(dev, O_RDWR);
|
||||
if (sock < 0)
|
||||
{
|
||||
d_error("Can not open %s",dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pool_alloc_node(&link_pool, &new_link);
|
||||
d_assert(new_link != NULL, return -1,"No link pool is availabe\n");
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
ifr.ifr_flags = (is_tap ? (flags | IFF_TAP) : (flags | IFF_TUN));
|
||||
strncpy(ifr.ifr_name, tuntap_dev_name, IFNAMSIZ);
|
||||
|
||||
rc = ioctl(sock, TUNSETIFF, (void *)&ifr);
|
||||
if (rc < 0)
|
||||
{
|
||||
d_error("iotcl error(dev:%s flags = %d)", tuntap_dev_name, flags);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Save socket descriptor */
|
||||
new_link->fd = sock;
|
||||
/* Save the interface name */
|
||||
strncpy(new_link->ifname, tuntap_dev_name, IFNAMSIZ);
|
||||
|
||||
*net_link = new_link;
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
pool_free_node(&link_pool, new_link);
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int net_link_open(net_link_t **net_link, char *device, int proto)
|
||||
{
|
||||
int sock,ioctl_sock;
|
||||
|
@ -1313,6 +1361,14 @@ int net_raw_close(net_link_t *net_link)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int net_tuntap_close(net_link_t *net_link)
|
||||
{
|
||||
d_assert(net_link,return -1, "net_link is NULL\n");
|
||||
close(net_link->fd);
|
||||
pool_free_node(&link_pool, net_link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_link_write(net_link_t *net_link, char *buf, int len)
|
||||
{
|
||||
d_assert(net_link && buf, return -1, "Invalid params\n");
|
||||
|
@ -1360,7 +1416,7 @@ int net_link_read(net_link_t *net_link, char *buffer, int size, int timeout)
|
|||
|
||||
rc = recvfrom(net_link->fd, buffer, size, 0, &remote_addr, &addr_len);
|
||||
#else
|
||||
rc = recvfrom(net_link->fd, buffer, size, 0, NULL, NULL);
|
||||
rc = read(net_link->fd, buffer, size);
|
||||
#endif
|
||||
}
|
||||
else /* Timeout */
|
||||
|
|
|
@ -15,6 +15,25 @@ extern "C" {
|
|||
#define GTP_COMPARE_NODE(__id1, __id2) \
|
||||
(((__id1)->addr) == ((__id2)->addr) && ((__id1)->port) == ((__id2)->port))
|
||||
|
||||
/* GTP-U message type, defined in 3GPP TS 29.281 Release 11 */
|
||||
#define GTPU_MSGTYPE_ECHO_REQ 1
|
||||
#define GTPU_MSGTYPE_ECHO_RSP 2
|
||||
#define GTPU_MSGTYPE_ERR_IND 26
|
||||
#define GTPU_MSGTYPE_SUPP_EXTHDR_NOTI 31
|
||||
#define GTPU_MSGTYPE_END_MARKER 254
|
||||
#define GTPU_MSGTYPE_GPDU 255
|
||||
|
||||
/* GTU-U flags */
|
||||
#define GTPU_FLAGS_PN 0x1
|
||||
#define GTPU_FLAGS_S 0x2
|
||||
|
||||
typedef struct _gtp_header
|
||||
{
|
||||
c_uint8_t flags;
|
||||
c_uint8_t type;
|
||||
c_uint16_t length;
|
||||
c_uint32_t teid;
|
||||
} gtp_header_t;
|
||||
/**
|
||||
* This structure represents the commonalities of GTP node such as MME, SGW,
|
||||
* PGW gateway. Some of members may not be used by the specific type of node */
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#define MIN_EPS_BEARER_ID 5
|
||||
#define MAX_EPS_BEARER_ID 15
|
||||
|
||||
#define DEFAULT_IP_ADDR "127.0.0.1"
|
||||
|
||||
static mme_context_t self;
|
||||
|
||||
pool_declare(mme_sgw_pool, mme_sgw_t, MAX_NUM_OF_SGW);
|
||||
|
@ -46,7 +48,7 @@ status_t mme_context_init()
|
|||
index_init(&mme_bearer_pool, MAX_NUM_OF_UE_BEARER);
|
||||
pool_init(&mme_pdn_pool, MAX_NUM_OF_UE_PDN);
|
||||
|
||||
self.mme_addr = inet_addr("127.0.0.1");
|
||||
self.mme_addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
|
||||
self.mme_ue_s1ap_id_hash = hash_make();
|
||||
|
||||
|
@ -60,7 +62,7 @@ status_t mme_context_init()
|
|||
self.s11_port = GTPV2_C_UDP_PORT;
|
||||
|
||||
/* FIXME : It should be removed */
|
||||
sgw->gnode.addr = inet_addr("127.0.0.1");
|
||||
sgw->gnode.addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
sgw->gnode.port = GTPV2_C_UDP_PORT+1;
|
||||
|
||||
/* MCC : 001, MNC : 01 */
|
||||
|
|
|
@ -24,7 +24,7 @@ AM_CPPFLAGS = \
|
|||
-I$(top_srcdir)/lib/gtp
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall -Werror
|
||||
-Wall -Werror @OSCPPFLAGS@
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
MOSTLYCLEANFILES = core *.stackdump
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
#include "pgw_context.h"
|
||||
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#define DEFAULT_IP_ADDR "127.0.0.1"
|
||||
|
||||
static pgw_context_t self;
|
||||
|
||||
index_declare(pgw_sess_pool, pgw_sess_t, MAX_NUM_OF_UE);
|
||||
|
@ -30,12 +34,12 @@ status_t pgw_context_init()
|
|||
|
||||
pool_init(&pgw_pdn_pool, MAX_NUM_OF_UE_PDN);
|
||||
|
||||
self.pgw_addr = inet_addr("127.0.0.1");
|
||||
self.pgw_addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
|
||||
self.s5c_addr = self.pgw_addr;
|
||||
self.s5c_port = GTPV2_C_UDP_PORT + 3;
|
||||
/* FIXME : It shoud be removed */
|
||||
self.s5c_node.addr = inet_addr("127.0.0.1");
|
||||
self.s5c_node.addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
self.s5c_node.port = GTPV2_C_UDP_PORT + 2;
|
||||
list_init(&self.s5c_node.local_list);
|
||||
list_init(&self.s5c_node.remote_list);
|
||||
|
@ -43,7 +47,7 @@ status_t pgw_context_init()
|
|||
self.s5u_addr = self.pgw_addr;
|
||||
self.s5u_port = GTPV1_U_UDP_PORT + 1;
|
||||
/* FIXME : It shoud be removed */
|
||||
self.s5u_node.addr = inet_addr("127.0.0.1");
|
||||
self.s5u_node.addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
self.s5u_node.port = GTPV1_U_UDP_PORT;
|
||||
|
||||
self.primary_dns_addr = inet_addr("8.8.8.8");
|
||||
|
@ -319,3 +323,57 @@ pgw_bearer_t* pgw_bearer_next(pgw_bearer_t *bearer)
|
|||
return list_next(bearer);
|
||||
}
|
||||
|
||||
pgw_bearer_t* pgw_bearer_find_by_packet(pkbuf_t *pkt)
|
||||
{
|
||||
pgw_bearer_t *bearer = NULL;
|
||||
pgw_sess_t *iter_session = NULL;
|
||||
pgw_bearer_t *iter_bearer = NULL;
|
||||
pdn_t *iter_pdn = NULL;
|
||||
struct iphdr *iph = NULL;
|
||||
|
||||
d_assert(pkt, return NULL, "pkt is NULL");
|
||||
|
||||
iph = (struct iphdr *)pkt->payload;
|
||||
|
||||
/* FIXME : Only support IPV4 */
|
||||
if (iph->version != 4) /* IPv4 */
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: Need API to find the bearer with packet filter */
|
||||
/* Iterate session */
|
||||
for (iter_session = pgw_sess_first(); iter_session ;
|
||||
iter_session = pgw_sess_next(iter_session))
|
||||
{
|
||||
/* Iterate bearer in session */
|
||||
for (iter_bearer = pgw_bearer_first(iter_session);
|
||||
iter_bearer;
|
||||
iter_bearer = pgw_bearer_next(iter_bearer))
|
||||
{
|
||||
/* Iterate pdn in session */
|
||||
for (iter_pdn = pgw_pdn_first(iter_bearer->sess);
|
||||
iter_pdn;
|
||||
iter_pdn = pgw_pdn_next(iter_pdn))
|
||||
{
|
||||
char buf1[INET_ADDRSTRLEN];
|
||||
char buf2[INET_ADDRSTRLEN];
|
||||
|
||||
d_trace(3,"Src_IP(%s) in Pkt : PAA(%s) in PDN\n",
|
||||
INET_NTOP(iph->saddr,buf1),
|
||||
INET_NTOP(iter_pdn->paa.ipv4_addr, buf2));
|
||||
|
||||
if (iph->saddr == iter_pdn->paa.ipv4_addr)
|
||||
{
|
||||
/* Found */
|
||||
bearer = iter_bearer;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return bearer;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ typedef struct _pgw_context_t {
|
|||
c_uint32_t primary_dns_addr;
|
||||
c_uint32_t secondary_dns_addr;
|
||||
|
||||
net_link_t* tun_link; /* PGW Tun Interace for U-plane */
|
||||
|
||||
list_t sess_list;
|
||||
} pgw_context_t;
|
||||
|
||||
|
@ -99,6 +101,8 @@ CORE_DECLARE(pgw_bearer_t*) pgw_bearer_find_by_id(
|
|||
CORE_DECLARE(pgw_bearer_t*) pgw_bearer_first(pgw_sess_t *sess);
|
||||
CORE_DECLARE(pgw_bearer_t*) pgw_bearer_next(pgw_bearer_t *bearer);
|
||||
|
||||
CORE_DECLARE(pgw_bearer_t*) pgw_bearer_find_by_packet(pkbuf_t *pkt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -10,6 +10,68 @@
|
|||
#include "pgw_event.h"
|
||||
#include "pgw_path.h"
|
||||
|
||||
#if LINUX == 1
|
||||
static int _gtpv1_tun_recv_cb(net_link_t *net_link, void *data)
|
||||
{
|
||||
pkbuf_t *recvbuf = NULL;
|
||||
int n;
|
||||
status_t rv;
|
||||
pgw_bearer_t *bearer = NULL;
|
||||
|
||||
recvbuf = pkbuf_alloc(sizeof(gtp_header_t), MAX_SDU_LEN);
|
||||
d_assert(recvbuf, return -1, "pkbuf_alloc error");
|
||||
|
||||
n = net_link_read(net_link, recvbuf->payload, recvbuf->len, 0);
|
||||
if (n <= 0)
|
||||
{
|
||||
pkbuf_free(recvbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find the bearer by packet filter */
|
||||
bearer = pgw_bearer_find_by_packet(recvbuf);
|
||||
if (bearer)
|
||||
{
|
||||
gtp_header_t *gtp_h = NULL;
|
||||
gtp_node_t gnode;
|
||||
|
||||
/* Add GTP-U header */
|
||||
rv = pkbuf_header(recvbuf, sizeof(gtp_header_t));
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("pkbuf_header error");
|
||||
pkbuf_free(recvbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Bits 8 7 6 5 4 3 2 1
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* |version |PT| 1| E| S|PN|
|
||||
* +--+--+--+--+--+--+--+--+
|
||||
* 0 0 1 1 0 0 0 0
|
||||
*/
|
||||
gtp_h->flags = 0x30;
|
||||
gtp_h->type = GTPU_MSGTYPE_GPDU;
|
||||
gtp_h->length = n;
|
||||
gtp_h->teid = bearer->sgw_s5u_teid;
|
||||
|
||||
/* Send to SGW */
|
||||
gnode.addr = bearer->sgw_s5u_addr;
|
||||
gnode.port = GTPV1_U_UDP_PORT;
|
||||
|
||||
rv = gtp_send(pgw_self()->s5u_sock, &gnode, recvbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_error("Can not find bearer");
|
||||
}
|
||||
|
||||
pkbuf_free(recvbuf);
|
||||
return 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _gtpv2_c_recv_cb(net_sock_t *sock, void *data)
|
||||
{
|
||||
event_t e;
|
||||
|
@ -93,6 +155,44 @@ status_t pgw_path_open()
|
|||
return rv;
|
||||
}
|
||||
|
||||
#if LINUX == 1
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* FIXME : dev_name should be configured */
|
||||
char *tun_dev_name = "pgwtun";
|
||||
|
||||
/* NOTE : tun device can be created via following command.
|
||||
*
|
||||
* $ sudo ip tuntap add name pgwtun mode tun
|
||||
*
|
||||
* Also, before running pgw, assign the one IP from IP pool of UE
|
||||
* to pgwtun. The IP should not be assigned to UE
|
||||
*
|
||||
* $ sudo ifconfig pgwtun 45.45.0.1/16 up
|
||||
*
|
||||
*/
|
||||
|
||||
/* Open Tun interface */
|
||||
rc = net_tuntap_open(&pgw_self()->tun_link, tun_dev_name, 0);
|
||||
if (rc != 0)
|
||||
{
|
||||
d_error("Can not open tun(dev : %s)",tun_dev_name);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
rc = net_register_link(pgw_self()->tun_link, _gtpv1_tun_recv_cb, NULL);
|
||||
if (rc != 0)
|
||||
{
|
||||
d_error("Can not register tun(dev : %s)",tun_dev_name);
|
||||
net_tuntap_close(pgw_self()->tun_link);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
|
@ -114,6 +214,11 @@ status_t pgw_path_close()
|
|||
return rv;
|
||||
}
|
||||
|
||||
#if LINUX == 1
|
||||
net_unregister_link(pgw_self()->tun_link);
|
||||
net_link_close(pgw_self()->tun_link);
|
||||
#endif
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "sgw_context.h"
|
||||
|
||||
#define DEFAULT_IP_ADDR "127.0.0.1"
|
||||
|
||||
static sgw_context_t self;
|
||||
|
||||
index_declare(sgw_sess_pool, sgw_sess_t, MAX_NUM_OF_UE);
|
||||
|
@ -27,12 +29,12 @@ status_t sgw_context_init()
|
|||
index_init(&sgw_bearer_pool, MAX_NUM_OF_UE_BEARER);
|
||||
list_init(&self.sess_list);
|
||||
|
||||
self.sgw_addr = inet_addr("127.0.0.1");
|
||||
self.sgw_addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
|
||||
self.s11_addr = self.sgw_addr;
|
||||
self.s11_port = GTPV2_C_UDP_PORT + 1;
|
||||
/* FIXME : It shoud be removed */
|
||||
self.s11_node.addr = inet_addr("127.0.0.1");
|
||||
self.s11_node.addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
self.s11_node.port = GTPV2_C_UDP_PORT;
|
||||
list_init(&self.s11_node.local_list);
|
||||
list_init(&self.s11_node.remote_list);
|
||||
|
@ -40,7 +42,7 @@ status_t sgw_context_init()
|
|||
self.s5c_addr = self.sgw_addr;
|
||||
self.s5c_port = GTPV2_C_UDP_PORT + 2;
|
||||
/* FIXME : It shoud be removed */
|
||||
self.s5c_node.addr = inet_addr("127.0.0.1");
|
||||
self.s5c_node.addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
self.s5c_node.port = GTPV2_C_UDP_PORT + 3;
|
||||
list_init(&self.s5c_node.local_list);
|
||||
list_init(&self.s5c_node.remote_list);
|
||||
|
@ -48,13 +50,13 @@ status_t sgw_context_init()
|
|||
self.s1u_addr = self.sgw_addr;
|
||||
self.s1u_port = GTPV1_U_UDP_PORT;
|
||||
/* FIXME : It shoud be removed */
|
||||
self.s1u_node.addr = inet_addr("127.0.0.1");
|
||||
self.s1u_node.addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
self.s1u_node.port = GTPV1_U_UDP_PORT;
|
||||
|
||||
self.s5u_addr = self.sgw_addr;
|
||||
self.s5u_port = GTPV1_U_UDP_PORT;
|
||||
/* FIXME : It shoud be removed */
|
||||
self.s5u_node.addr = inet_addr("127.0.0.1");
|
||||
self.s5u_node.addr = inet_addr(DEFAULT_IP_ADDR);
|
||||
self.s5u_node.port = GTPV1_U_UDP_PORT + 1;
|
||||
|
||||
context_initialized = 1;
|
||||
|
|
Loading…
Reference in New Issue