Preparation for packet mis-ordering stats
[samplevnf.git] / VNFs / DPPD-PROX / handle_nat.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <rte_mbuf.h>
18 #include <rte_hash.h>
19 #include <rte_hash_crc.h>
20 #include <rte_ether.h>
21 #include <rte_ip.h>
22 #include <rte_version.h>
23 #include <rte_byteorder.h>
24
25 #include "prox_lua_types.h"
26 #include "prox_lua.h"
27 #include "prox_malloc.h"
28 #include "prox_cksum.h"
29 #include "prefetch.h"
30 #include "etypes.h"
31 #include "log.h"
32 #include "quit.h"
33 #include "task_init.h"
34 #include "task_base.h"
35 #include "lconf.h"
36 #include "log.h"
37 #include "prox_port_cfg.h"
38
39 struct task_nat {
40         struct task_base base;
41         struct rte_hash  *hash;
42         uint32_t         *entries;
43         int              use_src;
44         int              offload_crc;
45 };
46
47 struct pkt_eth_ipv4 {
48         prox_rte_ether_hdr ether_hdr;
49         prox_rte_ipv4_hdr  ipv4_hdr;
50 } __attribute__((packed));
51
52 static int handle_nat(struct task_nat *task, struct rte_mbuf *mbuf)
53 {
54         uint32_t *ip_addr;
55         struct pkt_eth_ipv4 *pkt = rte_pktmbuf_mtod(mbuf, struct pkt_eth_ipv4 *);
56         int ret;
57
58         /* Currently, only support eth/ipv4 packets */
59         if (pkt->ether_hdr.ether_type != ETYPE_IPv4)
60                 return OUT_DISCARD;
61         if (task->use_src)
62                 ip_addr = &(pkt->ipv4_hdr.src_addr);
63         else
64                 ip_addr = &(pkt->ipv4_hdr.dst_addr);
65
66         ret = rte_hash_lookup(task->hash, ip_addr);
67
68         /* Drop all packets for which no translation has been
69            configured. */
70         if (ret < 0)
71                 return OUT_DISCARD;
72
73         *ip_addr = task->entries[ret];
74         prox_ip_udp_cksum(mbuf, &pkt->ipv4_hdr, sizeof(prox_rte_ether_hdr), sizeof(prox_rte_ipv4_hdr), task->offload_crc);
75         return 0;
76 }
77
78 static int handle_nat_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
79 {
80         struct task_nat *task = (struct task_nat *)tbase;
81         uint8_t out[MAX_PKT_BURST];
82         uint16_t j;
83         prefetch_first(mbufs, n_pkts);
84         for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
85 #ifdef PROX_PREFETCH_OFFSET
86                 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
87                 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
88 #endif
89                 out[j] = handle_nat(task, mbufs[j]);
90         }
91 #ifdef PROX_PREFETCH_OFFSET
92         PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
93         for (; j < n_pkts; ++j) {
94                 out[j] = handle_nat(task, mbufs[j]);
95         }
96 #endif
97         return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
98 }
99
100 static int lua_to_hash_nat(struct lua_State *L, enum lua_place from, const char *name,
101                            uint8_t socket, struct rte_hash **hash, uint32_t **entries)
102 {
103         struct rte_hash *ret_hash;
104         uint32_t *ret_entries;
105         uint32_t n_entries;
106         uint32_t ip_from, ip_to;
107         int ret, pop;
108
109         if ((pop = lua_getfrom(L, from, name)) < 0)
110                 return -1;
111
112         lua_len(L, -1);
113         n_entries = lua_tointeger(L, -1);
114         lua_pop(L, 1);
115
116         PROX_PANIC(n_entries == 0, "No entries for NAT\n");
117
118         static char hash_name[30] = "000_hash_nat_table";
119
120         const struct rte_hash_parameters hash_params = {
121                 .name = hash_name,
122                 .entries = n_entries * 4,
123                 .key_len = sizeof(ip_from),
124                 .hash_func = rte_hash_crc,
125                 .hash_func_init_val = 0,
126         };
127
128         ret_hash = rte_hash_create(&hash_params);
129         PROX_PANIC(ret_hash == NULL, "Failed to set up hash table for NAT\n");
130         name++;
131         ret_entries = prox_zmalloc(n_entries * sizeof(ip_to), socket);
132         PROX_PANIC(ret_entries == NULL, "Failed to allocate memory for NAT %u entries\n", n_entries);
133
134         lua_pushnil(L);
135         while (lua_next(L, -2)) {
136                 if (lua_to_ip(L, TABLE, "from", &ip_from) ||
137                     lua_to_ip(L, TABLE, "to", &ip_to))
138                         return -1;
139
140                 ip_from = rte_bswap32(ip_from);
141                 ip_to = rte_bswap32(ip_to);
142
143                 ret = rte_hash_lookup(ret_hash, (const void *)&ip_from);
144                 PROX_PANIC(ret >= 0, "Key %x already exists in NAT hash table\n", ip_from);
145
146                 ret = rte_hash_add_key(ret_hash, (const void *)&ip_from);
147
148                 PROX_PANIC(ret < 0, "Failed to add Key %x to NAT hash table\n", ip_from);
149                 ret_entries[ret] = ip_to;
150                 lua_pop(L, 1);
151         }
152
153         lua_pop(L, pop);
154
155         *hash = ret_hash;
156         *entries = ret_entries;
157         return 0;
158 }
159
160 static void init_task_nat(struct task_base *tbase, struct task_args *targ)
161 {
162         struct task_nat *task = (struct task_nat *)tbase;
163         const int socket_id = rte_lcore_to_socket_id(targ->lconf->id);
164         int ret;
165
166         /* Use destination IP by default. */
167         task->use_src = targ->use_src;
168
169         PROX_PANIC(!strcmp(targ->nat_table, ""), "No nat table specified\n");
170         ret = lua_to_hash_nat(prox_lua(), GLOBAL, targ->nat_table, socket_id, &task->hash, &task->entries);
171         PROX_PANIC(ret != 0, "Failed to load NAT table from lua:\n%s\n", get_lua_to_errors());
172         struct prox_port_cfg *port = find_reachable_port(targ);
173         if (port) {
174                 task->offload_crc = port->requested_tx_offload & (DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM);
175         }
176
177 }
178
179 /* Basic static nat. */
180 static struct task_init task_init_nat = {
181         .mode_str = "nat",
182         .init = init_task_nat,
183         .handle = handle_nat_bulk,
184 #ifdef SOFT_CRC
185         .flag_features = TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS,
186 #else
187         .flag_features = 0,
188 #endif
189         .size = sizeof(struct task_nat),
190 };
191
192 __attribute__((constructor)) static void reg_task_nat(void)
193 {
194         reg_task(&task_init_nat);
195 }