2 // Copyright (c) 2010-2017 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <rte_hash_crc.h>
20 #include <rte_ether.h>
22 #include <rte_version.h>
23 #include <rte_byteorder.h>
25 #include "prox_lua_types.h"
27 #include "prox_malloc.h"
28 #include "prox_cksum.h"
33 #include "task_init.h"
34 #include "task_base.h"
37 #include "prox_port_cfg.h"
40 struct task_base base;
41 struct rte_hash *hash;
48 prox_rte_ether_hdr ether_hdr;
49 prox_rte_ipv4_hdr ipv4_hdr;
50 } __attribute__((packed));
52 static int handle_nat(struct task_nat *task, struct rte_mbuf *mbuf)
55 struct pkt_eth_ipv4 *pkt = rte_pktmbuf_mtod(mbuf, struct pkt_eth_ipv4 *);
58 /* Currently, only support eth/ipv4 packets */
59 if (pkt->ether_hdr.ether_type != ETYPE_IPv4)
62 ip_addr = &(pkt->ipv4_hdr.src_addr);
64 ip_addr = &(pkt->ipv4_hdr.dst_addr);
66 ret = rte_hash_lookup(task->hash, ip_addr);
68 /* Drop all packets for which no translation has been
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);
78 static int handle_nat_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
80 struct task_nat *task = (struct task_nat *)tbase;
81 uint8_t out[MAX_PKT_BURST];
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 *));
89 out[j] = handle_nat(task, mbufs[j]);
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]);
97 return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
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)
103 struct rte_hash *ret_hash;
104 uint32_t *ret_entries;
106 uint32_t ip_from, ip_to;
109 if ((pop = lua_getfrom(L, from, name)) < 0)
113 n_entries = lua_tointeger(L, -1);
116 PROX_PANIC(n_entries == 0, "No entries for NAT\n");
118 static char hash_name[30] = "000_hash_nat_table";
120 const struct rte_hash_parameters hash_params = {
122 .entries = n_entries * 4,
123 .key_len = sizeof(ip_from),
124 .hash_func = rte_hash_crc,
125 .hash_func_init_val = 0,
128 ret_hash = rte_hash_create(&hash_params);
129 PROX_PANIC(ret_hash == NULL, "Failed to set up hash table for NAT\n");
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);
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))
140 ip_from = rte_bswap32(ip_from);
141 ip_to = rte_bswap32(ip_to);
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);
146 ret = rte_hash_add_key(ret_hash, (const void *)&ip_from);
148 PROX_PANIC(ret < 0, "Failed to add Key %x to NAT hash table\n", ip_from);
149 ret_entries[ret] = ip_to;
156 *entries = ret_entries;
160 static void init_task_nat(struct task_base *tbase, struct task_args *targ)
162 struct task_nat *task = (struct task_nat *)tbase;
163 const int socket_id = rte_lcore_to_socket_id(targ->lconf->id);
166 /* Use destination IP by default. */
167 task->use_src = targ->use_src;
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);
174 task->offload_crc = port->requested_tx_offload & (DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM);
179 /* Basic static nat. */
180 static struct task_init task_init_nat = {
182 .init = init_task_nat,
183 .handle = handle_nat_bulk,
185 .flag_features = TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS,
189 .size = sizeof(struct task_nat),
192 __attribute__((constructor)) static void reg_task_nat(void)
194 reg_task(&task_init_nat);