Add tuntap interface to PGW

This commit is contained in:
James Park 2017-04-18 10:22:55 +09:00
parent bebf14e361
commit 4b9e499ea7
9 changed files with 263 additions and 12 deletions

View File

@ -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
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -24,7 +24,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/lib/gtp
AM_CFLAGS = \
-Wall -Werror
-Wall -Werror @OSCPPFLAGS@
MAINTAINERCLEANFILES = Makefile.in
MOSTLYCLEANFILES = core *.stackdump

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;