gtpv1u_eNB.c 17.5 KB
Newer Older
Cedric Roux's avatar
 
Cedric Roux committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
#include <stdio.h>
#include <errno.h>


#include "NwGtpv1u.h"
#include "NwGtpv1uMsg.h"
#include "NwLog.h"

#include "log.h"

#include "gtpv1u_eNB_defs.h"

#include "udp_primitives_client.h"
#include "UTIL/LOG/log.h"
#include "COMMON/platform_types.h"

#ifdef GTPU_IN_KERNEL
#include <netinet/in.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif


extern unsigned char pdcp_data_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rab_id, u32 muiP, u32 confirmP, sdu_size_t sdu_buffer_size, unsigned char* sdu_buffer, u8 is_data_pdu);


inline NwGtpv1uRcT gtpv1u_eNB_log_request(NwGtpv1uLogMgrHandleT hLogMgr,
        NwU32T                logLevel,
        NwCharT              *file,
        NwU32T                line,
        NwCharT              *logStr)
{
    logIt(GTPU, logLevel, "%s\n", logStr);
    return NW_GTPV1U_OK;
}

/* Callback called when a gtpv1u message arrived on UDP interface */
NwGtpv1uRcT gtpv1u_process_stack_req(
    NwGtpv1uUlpHandleT hUlp,
    NwGtpv1uUlpApiT *pUlpApi)
{
    switch(pUlpApi->apiType) {
            /* Here there are two type of messages handled:
             * - T-PDU
             * - END-MARKER
             */
        case NW_GTPV1U_ULP_API_RECV_TPDU: {
            uint8_t      buffer[4096];
            uint32_t     buffer_len;

            /* Nw-gptv1u stack has processed a PDU. we can schedule it to PDCP
             * for transmission.
             */
            if (NW_GTPV1U_OK != nwGtpv1uMsgGetTpdu(pUlpApi->apiInfo.recvMsgInfo.hMsg,
                                                   buffer, &buffer_len)) {
                GTPU_ERROR("Error while retrieving T-PDU");
            }
            GTPU_DEBUG("Received T-PDU from gtpv1u stack %u with size %d",
                       pUlpApi->apiInfo.recvMsgInfo.teid, buffer_len);

            pdcp_data_req(0, // module_id,
            		0, // frame
            		1, // enb flag
            		5, // rb id
            		0, // mui
            		0, // confirm
            		buffer_len,
            		buffer,
            		1);
        }
        break;
        default: {
            GTPU_ERROR("Received undefined UlpApi (%02x) from gtpv1u stack!\n",
                       pUlpApi->apiType);
        }
    }
    return NW_GTPV1U_OK;
}

NwGtpv1uRcT gtpv1u_eNB_udp_req(NwGtpv1uUdpHandleT udpHandle,
                               NwU8T             *dataBuf,
                               NwU32T             dataSize,
                               NwU32T             peerIpAddr,
                               NwU16T             peerPort)
{
    udp_data_t *udp_data_p;

    if (udpHandle == 0) {
        return NW_GTPV1U_FAILURE;
    }

    udp_data_p = (udp_data_t *)udpHandle;

    LOG_D(GTPU, "New udp req triggered with sd %d, data size %u\n",
          udp_data_p->sd, dataSize);

    if (udp_send_to(udp_data_p->sd, peerPort, peerIpAddr, dataBuf, dataSize) < 0) {
        return NW_GTPV1U_FAILURE;
    }

    return NW_GTPV1U_OK;
}

int data_recv_callback(uint16_t  port,
                       uint32_t  address,
                       uint8_t  *buffer,
                       uint32_t  length,
                       void     *arg_p)
{
    gtpv1u_data_t        *gtpv1u_data_p;

    if (arg_p == NULL) {
        return -1;
    }

    gtpv1u_data_p = (gtpv1u_data_t *)arg_p;

    return nwGtpv1uProcessUdpReq(gtpv1u_data_p->gtpv1u_stack,
    		buffer,
    		length,
    		port,
    		address);
}

int gtpv1u_create_tunnel_endpoint(gtpv1u_data_t *gtpv1u_data_p, uint8_t ue_id,
                                  uint8_t rab_id, char *sgw_ip_addr, uint16_t port)
{
    uint32_t                     teid;
    uint8_t                      max_attempt = 100;
    NwGtpv1uRcT                  rc;
    NwGtpv1uUlpApiT              ulp_req;
    struct gtpv1u_ue_data_s     *new_ue_p;
    struct gtpv1u_ue_data_s     *temp;
    struct gtpv1u_bearer_s      *bearer;
    hashtbl_rc_t                 hash_rc;

    if (rab_id > MAX_BEARERS_PER_UE) {
        LOG_E(GTPU, "Could not use rab_id %d > max %d\n",
              rab_id, MAX_BEARERS_PER_UE);
        return -1;
    }


    if ((hash_rc = hashtbl_get(gtpv1u_data_p->ue_mapping, (uint64_t)ue_id, (void**)&new_ue_p)) == HASH_TABLE_OK) {
        /* A context for this UE already exist in the tree, use it */
        /* We check that the tunnel is not already configured */
        if (new_ue_p->bearers[rab_id].state != BEARER_DOWN) {
            LOG_E(GTPU, "Cannot create new end-point over already existing tunnel\n");
            return -1;
        }
    } else {
        /* Context doesn't exist, create it */
        if (rab_id != 0) {
            /* UE should first establish Default bearer before trying to setup
             * additional bearers.
             */
            LOG_E(GTPU, "UE context is not known and rab_id != 0\n");
            return -1;
        }
        new_ue_p = calloc(1, sizeof(struct gtpv1u_ue_data_s));
        new_ue_p->ue_id = ue_id;

        hash_rc = hashtbl_insert(gtpv1u_data_p->ue_mapping, (uint64_t)ue_id, new_ue_p);

        if ((hash_rc != HASH_TABLE_OK) && (hash_rc != HASH_TABLE_INSERT_OVERWRITTEN_DATA)) {
            LOG_E(GTPU, "Failed to insert new UE context\n");
            free(new_ue_p);
            return -1;
        }
    }

    bearer = &new_ue_p->bearers[rab_id];

    /* Configure the bearer */
    bearer->state       = BEARER_IN_CONFIG;
    bearer->sgw_ip_addr = inet_addr(sgw_ip_addr);
    bearer->port        = port;

    /* Create the new stack api request */
    memset(&ulp_req, 0, sizeof(NwGtpv1uUlpApiT));
    ulp_req.apiType = NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT;

    /* Try to create new tunnel-endpoint.
     * If teid generated is already present in the stack, just peek another random
     * teid. This could be ok for small number of tunnel but more errors could be
     * thrown if we reached high number of tunnels.
     * TODO: find a solution for teid
     */
    do {
        /* Request for a new random TEID */
        teid = gtpv1u_new_teid();
        ulp_req.apiInfo.createTunnelEndPointInfo.teid = teid;

        rc = nwGtpv1uProcessUlpReq(gtpv1u_data_p->gtpv1u_stack, &ulp_req);

        if (rc == NW_GTPV1U_OK) {
//             LOG_D(GTPU, "Successfully created new tunnel endpoint for teid 0x%x\n",
//                   teid);
            bearer->teid_eNB = teid;
//             gtpv1u_initial_req(gtpv1u_data_p, teid, GTPV1U_UDP_PORT,
//                                inet_addr("192.168.56.101"));
            LOG_I(GTPU, "Created eNB tunnel endpoint %u for ue id %u, rab id %u\n", teid, ue_id, rab_id);
            return 0;
        } else {
            LOG_W(GTPU, "Teid %u already in use... %s\n",
                  teid, (max_attempt > 1) ? "Trying another one" : "Last chance");
        }
    } while(max_attempt-- && rc != NW_GTPV1U_OK);

    bearer->state = BEARER_DOWN;
    LOG_I(GTPU, "Failed to created eNB tunnel endpoint %u for ue id %u, rab id %u, bearer down\n", teid, ue_id, rab_id);

    return -1;
}

int gtpv1u_initial_req(gtpv1u_data_t *gtpv1u_data_p, uint32_t teid,
                       uint16_t port, uint32_t address)
{
    NwGtpv1uUlpApiT ulp_req;
    NwGtpv1uRcT     rc;

    memset(&ulp_req, 0, sizeof(NwGtpv1uUlpApiT));

    ulp_req.apiType = NW_GTPV1U_ULP_API_INITIAL_REQ;
    ulp_req.apiInfo.initialReqInfo.teid     = teid;
    ulp_req.apiInfo.initialReqInfo.peerPort = port;
    ulp_req.apiInfo.initialReqInfo.peerIp   = address;

    rc = nwGtpv1uProcessUlpReq(gtpv1u_data_p->gtpv1u_stack, &ulp_req);
    if (rc == NW_GTPV1U_OK) {
        LOG_D(GTPU, "Successfully sent initial req for teid %u\n", teid);
    } else {
        LOG_W(GTPU, "Could not send initial req for teid %u\n", teid);
    }
    return (rc == NW_GTPV1U_OK) ? 0 : -1;
}

int gtpv1u_new_data_req(gtpv1u_data_t *gtpv1u_data_p,
                        uint8_t ue_id, uint8_t rab_id,
                        uint8_t *buffer, uint32_t buf_len)
{
#ifdef GTPU_IN_KERNEL
    struct sockaddr_in          dummy_dest_addr;
    socklen_t                   socklen = sizeof(struct sockaddr_in);
#endif
    NwGtpv1uUlpApiT          stack_req;
    NwGtpv1uRcT              rc;
    struct gtpv1u_ue_data_s  ue;
    struct gtpv1u_ue_data_s *ue_inst_p;
    struct gtpv1u_bearer_s  *bearer_p;
    hashtbl_rc_t             hash_rc;

    memset(&ue, 0, sizeof(struct gtpv1u_ue_data_s));

    ue.ue_id = ue_id;

    assert(gtpv1u_data_p != NULL);
    assert(rab_id <= MAX_BEARERS_PER_UE);

    /* Check that UE context is present in ue map. */
    hash_rc = hashtbl_get(gtpv1u_data_p->ue_mapping, (uint64_t)ue_id, (void**)&ue_inst_p);

    if (hash_rc ==  HASH_TABLE_KEY_NOT_EXISTS ) {
        LOG_E(GTPU, "[UE %d] Trying to send data on non-existing UE context\n", ue_id);
        return -1;
    }

    bearer_p = &ue_inst_p->bearers[rab_id];

    /* Ensure the bearer in ready.
     * TODO: handle the cases where the bearer is in HANDOVER state.
     * In such case packets should be placed in FIFO.
     */
    if (bearer_p->state != BEARER_UP) {
        LOG_W(GTPU, "Trying to send data over bearer with state(%u) != BEARER_UP\n",
              bearer_p->state);
#warning  LG: HACK WHILE WAITING FOR NAS, normally return -1
        if (bearer_p->state != BEARER_IN_CONFIG)
        return -1;
    }
#ifdef GTPU_IN_KERNEL
    dummy_dest_addr.sin_family      = AF_INET;
    dummy_dest_addr.sin_port        = 5001;
    dummy_dest_addr.sin_addr.s_addr = inet_addr("178.179.180.181");
    if (sendto(gtpv1u_data_p->sock_desc[rab_id], (void *)buffer, buf_len, 0, (struct sockaddr *)&dummy_dest_addr, socklen) < 0) {
        LOG_E(GTPU, "Error during send to socket %d : (%s:%d)\n", gtpv1u_data_p->sock_desc[rab_id], strerror(errno), errno);
        return -1;
    } else {
        LOG_D(GTPU, "send to UDP socket %d, packet should be handled by iptables\n", gtpv1u_data_p->sock_desc[rab_id]);
    }
#else

    memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT));

    stack_req.apiType                   = NW_GTPV1U_ULP_API_SEND_TPDU;
    // LG HACK stack_req.apiInfo.sendtoInfo.teid   = bearer_p->teid_sgw;
    stack_req.apiInfo.sendtoInfo.teid   = 1;// LG HACK
    stack_req.apiInfo.sendtoInfo.ipAddr = bearer_p->sgw_ip_addr;

    rc = nwGtpv1uGpduMsgNew(gtpv1u_data_p->gtpv1u_stack,
            //bearer_p->teid_sgw,
            1, // LG FORCING 1 instead of bearer_p->teid_sgw
                            NW_FALSE,
                            gtpv1u_data_p->seq_num++,
                            buffer,
                            buf_len,
                            &(stack_req.apiInfo.sendtoInfo.hMsg));

    if (rc != NW_GTPV1U_OK) {
        LOG_E(GTPU, "nwGtpv1uGpduMsgNew failed: 0x%x\n", rc);
        return -1;
    }
    rc = nwGtpv1uProcessUlpReq(gtpv1u_data_p->gtpv1u_stack,
                               &stack_req);
    if (rc != NW_GTPV1U_OK) {
        LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: 0x%x\n", rc);
        return -1;
    }
    rc = nwGtpv1uMsgDelete(gtpv1u_data_p->gtpv1u_stack,
                           stack_req.apiInfo.sendtoInfo.hMsg);
    if (rc != NW_GTPV1U_OK) {
        LOG_E(GTPU, "nwGtpv1uMsgDelete failed: 0x%x\n", rc);
        return -1;
    }
#endif
    LOG_E(GTPU, "%s() return code OK\n", __FUNCTION__);
    return 0;
}

#ifdef GTPU_IN_KERNEL

#undef GTPV1U_PACKET_RX_RING
/// The number of frames in the ring
//  This number is not set in stone. Nor are block_size, block_nr or frame_size
#define CONF_RING_FRAMES          128

/// Offset of data from start of frame
#define PKT_OFFSET      (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + \
                         TPACKET_ALIGN(sizeof(struct sockaddr_ll)))

int gtpv1u_eNB_create_sockets(gtpv1u_data_t *gtpv1u_data_p)
{
    int                     value, mark;
    const int              *val_p=&value;
    struct ifreq            ifr;
#ifdef GTPV1U_PACKET_RX_RING
    struct tpacket_req      tp;
#endif
    int                     i;

    if (gtpv1u_data_p == NULL) {
        return -1;
    }

    GTPU_DEBUG("Creating socket for GTPV1U on %s if index %u\n", gtpv1u_data_p->interface_name, gtpv1u_data_p->interface_index);

    for (mark = 0; mark <= 15; mark++) {

        gtpv1u_data_p->sock_desc[mark] = socket( PF_INET , SOCK_DGRAM, 0);
        if (gtpv1u_data_p->sock_desc[mark] < 0) {
            GTPU_ERROR("Error during socket creation (%s:%d)\n",strerror(errno), errno);
            goto error;
        }

//      // socket options, tell the kernel we provide the IP structure
//      if(setsockopt(sgi_data_p->sd[rab_id], IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)
//        {
//            SGI_IF_ERROR("Error during socket setsockopt IP_HDRINCL (%s:%d)\n", strerror(errno), errno);
//          goto error;
//      }
//
//
        // setting socket option to use MARK value
        //value = rab_id + SGI_MIN_EPS_BEARER_ID;
        value = mark;
        if (setsockopt (gtpv1u_data_p->sock_desc[mark], SOL_SOCKET, SO_MARK, val_p, sizeof (value)) < 0)
        {
            GTPU_ERROR("error notifying kernel about MARK");
            goto error;
        }
        GTPU_DEBUG("Created socket %d for rab_id %d (for any UE context)\n", gtpv1u_data_p->sock_desc[mark], value);

#ifdef SGI_PACKET_RX_RING
        // tell kernel to export data through mmap()ped ring
        tp.tp_block_size = CONF_RING_FRAMES * getpagesize();
        tp.tp_block_nr   = 1;
        tp.tp_frame_size = getpagesize();
        tp.tp_frame_nr   = CONF_RING_FRAMES;

        if (setsockopt(gtpv1u_data_p->sock_desc[mark], SOL_PACKET, PACKET_RX_RING, (void*) &tp, sizeof(tp))) {
        	GTPU_ERROR("setsockopt() ring\n");
            goto error;
        }

        // open ring
        gtpv1u_data_p->sock_mmap_ring[mark] = mmap(0, tp.tp_block_size * tp.tp_block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, sgi_data_p->sd[mark], 0);
        if (!gtpv1u_data_p->sock_mmap_ring[mark]) {
        	GTPU_ERROR("Failed to mmap socket (%s:%d)\n", strerror(errno), errno);
            goto error;
        }
        /* Setup our ringbuffer */
        gtpv1u_data_p->malloc_ring[mark] = malloc(tp.tp_frame_nr * sizeof(struct iovec));
        for(i=0; i<tp.tp_frame_nr; i++) {
        	gtpv1u_data_p->malloc_ring[mark][i].iov_base=(void *)((long)gtpv1u_data_p->sock_mmap_ring[mark])+(i*tp.tp_frame_size);
        	gtpv1u_data_p->malloc_ring[mark][i].iov_len=tp.tp_frame_size;
        }

#endif

        memset(&ifr, 0, sizeof(ifr));
        snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), gtpv1u_data_p->interface_name);
        if (setsockopt (gtpv1u_data_p->sock_desc[mark], SOL_SOCKET, SO_BINDTODEVICE,(void *)&ifr, sizeof(ifr)) < 0)
        {
            GTPU_ERROR("error notifying kernel about MARK");
            goto error;
        }
        GTPU_DEBUG("Created socket %d for rab_id %d (for any UE context)\n", gtpv1u_data_p->sock_desc[mark], value);
    }
    return 0;
error:
    GTPU_ERROR("ERROR (%s)\n", strerror(errno));
    for (mark = 0; mark <= 15; mark++) {
        if (gtpv1u_data_p->sock_desc[mark] > 0) {
            close(gtpv1u_data_p->sock_desc[mark]);
        }
        gtpv1u_data_p->sock_desc[mark] = -1;
    }
    return -1;
}
#endif

int gtpv1u_eNB_init(gtpv1u_data_t *gtpv1u_data_p)
{
    NwGtpv1uRcT             rc;
    NwGtpv1uLogMgrEntityT   log;
    NwGtpv1uUdpEntityT      udp;
    NwGtpv1uUlpEntityT      ulp;

    if (gtpv1u_data_p == NULL) {
        return -1;
    }

    //(gtpv1u_data_p was allocated with calloc (zeroed))

//     GTPU_INFO("Initializing GTPU stack for eNB %u\n",
//               gtpv1u_data_p->eNB_id);

    /* Initialize UE tree */
    //RB_INIT(&gtpv1u_data_p->gtpv1u_ue_map_head);

#ifdef GTPU_IN_KERNEL
#warning hardcoded ENB GTPV1U interface name
    gtpv1u_data_p->interface_name = "upenb0";
    gtpv1u_data_p->interface_index = if_nametoindex(gtpv1u_data_p->interface_name);

    gtpv1u_eNB_create_sockets(gtpv1u_data_p);
#endif
    /* Initialize UE hashtable */
    gtpv1u_data_p->ue_mapping = hashtbl_create (256, NULL, NULL);
    if (gtpv1u_data_p->ue_mapping == NULL) {
        perror("hashtbl_create");
        GTPU_ERROR("Initializing TASK_GTPV1_U task interface: ERROR\n");
        return -1;
    }

    if (udp_create_connection(gtpv1u_data_p->ip_addr, GTPV1U_UDP_PORT,
                              &gtpv1u_data_p->udp_data, data_recv_callback, (void *)gtpv1u_data_p) < 0) {
        return -1;
    }

    /* Initializing GTPv1-U stack */
    if ((rc = nwGtpv1uInitialize(&gtpv1u_data_p->gtpv1u_stack)) != NW_GTPV1U_OK) {
        GTPU_ERROR("Failed to setup nwGtpv1u stack %x\n", rc);
        return -1;
    }

    /* Set up the log interface and register the log entity */
    log.logReqCallback = gtpv1u_eNB_log_request;

    if ((rc = nwGtpv1uSetLogMgrEntity(gtpv1u_data_p->gtpv1u_stack,
                                      &log)) != NW_GTPV1U_OK) {
        GTPU_ERROR("nwGtpv1uSetLogMgrEntity: %x\n", rc);
        return -1;
    }

    udp.hUdp = (NwGtpv1uUdpHandleT) &gtpv1u_data_p->udp_data;
    udp.udpDataReqCallback = gtpv1u_eNB_udp_req;

    if ((rc = nwGtpv1uSetUdpEntity(gtpv1u_data_p->gtpv1u_stack,
                                   &udp)) != NW_GTPV1U_OK) {
        GTPU_ERROR("nwGtpv1uSetUdpEntity: %x\n", rc);
        return -1;
    }

    /* Set the ULP API callback. Called once message have been processed by the
     * nw-gtpv1u stack.
     */
    ulp.ulpReqCallback = gtpv1u_process_stack_req;

    if ((rc = nwGtpv1uSetUlpEntity(gtpv1u_data_p->gtpv1u_stack,
                                   &ulp)) != NW_GTPV1U_OK) {
        GTPU_ERROR("nwGtpv1uSetUlpEntity: %x\n", rc);
        return -1;
    }

    if ((rc = nwGtpv1uSetLogLevel(gtpv1u_data_p->gtpv1u_stack,
                                  NW_LOG_LEVEL_DEBG)) != NW_GTPV1U_OK) {
        GTPU_ERROR("nwGtpv1uSetLogLevel: %x\n", rc);
        return -1;
    }

    gtpv1u_create_tunnel_endpoint(gtpv1u_data_p, 0, 0, "192.168.1.1", 2152);

//     GTPU_INFO("Initializing GTPU stack for eNB %u: DONE\n",
//               gtpv1u_data_p->eNB_id);

    return 0;
}