Fix potential core dump when closing ports at exit
[samplevnf.git] / VNFs / DPPD-PROX / handle_master.c
1 /*
2 // Copyright (c) 2010-2020 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 <fcntl.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <linux/netlink.h>
21 #include <linux/rtnetlink.h>
22 #include <net/if.h>
23
24 #include <rte_hash.h>
25 #include <rte_hash_crc.h>
26 #include <rte_ether.h>
27
28 #include "prox_cfg.h"
29 #include "prox_globals.h"
30 #include "rx_pkt.h"
31 #include "arp.h"
32 #include "handle_master.h"
33 #include "log.h"
34 #include "mbuf_utils.h"
35 #include "etypes.h"
36 #include "defaults.h"
37 #include "prox_malloc.h"
38 #include "quit.h"
39 #include "task_init.h"
40 #include "prox_port_cfg.h"
41 #include "main.h"
42 #include "lconf.h"
43 #include "input.h"
44 #include "tx_pkt.h"
45 #include "defines.h"
46 #include "prox_ipv6.h"
47 #include "packet_utils.h"
48
49 #define PROX_MAX_ARP_REQUESTS   32      // Maximum number of tasks requesting the same MAC address
50 #define NETLINK_BUF_SIZE        16384
51
52 static char netlink_buf[NETLINK_BUF_SIZE];
53
54 const char *actions_string[] = {
55         "MAC_INFO_FROM_MASTER",         // Controlplane sending a MAC update to dataplane
56         "MAC_INFO_FROM_MASTER_FOR_IPV6",// Controlplane sending a MAC update to dataplane
57         "IPV6_INFO_FROM_MASTER",        // Controlplane IPv6 Global IP info to dataplane
58         "ROUTE_ADD_FROM_MASTER",        // Controlplane sending a new route to dataplane
59         "ROUTE_DEL_FROM_MASTER",        // Controlplane deleting a new route from dataplane
60         "SEND_ARP_REQUEST_FROM_MASTER", // Controlplane requesting dataplane to send ARP request
61         "SEND_ARP_REPLY_FROM_MASTER",   // Controlplane requesting dataplane to send ARP reply
62         "SEND_NDP_FROM_MASTER",         // Controlplane requesting dataplane to send NDP
63         "SEND_ICMP_FROM_MASTER",        // Controlplane requesting dataplane to send ICMP message
64         "SEND_BGP_FROM_MASTER",         // Controlplane requesting dataplane to send BGP message
65         "ARP_PKT_FROM_NET_TO_MASTER",   // ARP sent by datplane to Controlpane for handling
66         "NDP_PKT_FROM_NET_TO_MASTER,"   // NDP sent by datplane to Controlpane for handling
67         "ICMP_TO_MASTER",               // ICMP sent by datplane to Controlpane for handling
68         "BGP_TO_MASTER"                 // BGP sent by datplane to Controlpane for handling
69         "IP4_REQ_MAC_TO_MASTER",        // Dataplane requesting MAC resolution to Controlplane
70         "IP6_REQ_MAC_TO_MASTER",        // Dataplane requesting MAC resolution to Controlplane
71         "PKT_FROM_TAP"                  // Packet received by Controlplane from kernel and forwarded to dataplane for sending
72
73 };
74
75 static struct my_arp_t arp_reply = {
76         .htype = 0x100,
77         .ptype = 8,
78         .hlen = 6,
79         .plen = 4,
80         .oper = 0x200
81 };
82 static struct my_arp_t arp_request = {
83         .htype = 0x100,
84         .ptype = 8,
85         .hlen = 6,
86         .plen = 4,
87         .oper = 0x100
88 };
89
90 struct ip_port {
91         uint32_t ip;
92         uint8_t port;
93 } __attribute__((packed));
94
95 struct ip6_port {
96         struct ipv6_addr ip6;
97         uint8_t port;
98 } __attribute__((packed));
99
100 void register_router_to_ctrl_plane(struct task_base *tbase, uint8_t port_id, uint8_t core_id, uint8_t task_id, struct ipv6_addr *local_ipv6_addr, struct ipv6_addr *global_ipv6_addr, struct ipv6_addr *router_prefix)
101 {
102         struct task_master *task = (struct task_master *)tbase;
103         task->internal_port_table[port_id].flags |= IPV6_ROUTER;
104         memcpy(&task->internal_port_table[port_id].router_prefix, router_prefix, sizeof(struct ipv6_addr));
105         register_node_to_ctrl_plane(tbase, local_ipv6_addr, global_ipv6_addr, port_id, core_id, task_id);
106 }
107
108 void register_node_to_ctrl_plane(struct task_base *tbase, struct ipv6_addr *local_ipv6_addr, struct ipv6_addr *global_ipv6_addr, uint8_t port_id, uint8_t core_id, uint8_t task_id)
109 {
110         struct task_master *task = (struct task_master *)tbase;
111         if (task->internal_port_table[port_id].flags & IPV6_ROUTER)
112                 plogx_dbg("\tregistering router with port %d core %d and task %d\n", port_id, core_id, task_id);
113         else
114                 plogx_dbg("\tregistering node with port %d core %d and task %d\n", port_id, core_id, task_id);
115
116         if (port_id >= PROX_MAX_PORTS) {
117                 plog_err("Unable to register router, port %d\n", port_id);
118                 return;
119         }
120         task->internal_port_table[port_id].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
121         memcpy(&task->internal_port_table[port_id].mac, &prox_port_cfg[port_id].eth_addr, sizeof(prox_rte_ether_addr));
122         memcpy(&task->internal_port_table[port_id].local_ipv6_addr, local_ipv6_addr, sizeof(struct ipv6_addr));
123         if (memcmp(local_ipv6_addr, &prox_cfg.random_ip, sizeof(struct ipv6_addr)) == 0) {
124                 task->internal_port_table[port_id].flags |= HANDLE_RANDOM_LOCAL_IP_FLAG;
125                 return;
126         }
127         memcpy(&task->internal_port_table[port_id].global_ipv6_addr, global_ipv6_addr, sizeof(struct ipv6_addr));
128         if (memcmp(global_ipv6_addr, &prox_cfg.random_ip, sizeof(struct ipv6_addr)) == 0) {
129                 task->internal_port_table[port_id].flags |= HANDLE_RANDOM_GLOBAL_IP_FLAG;
130                 return;
131         }
132         struct ip6_port key;
133         memcpy(&key.ip6, local_ipv6_addr, sizeof(struct ipv6_addr));
134         key.port = port_id;
135         int ret = rte_hash_add_key(task->internal_ip6_hash, (const void *)&key);
136         if (unlikely(ret < 0)) {
137                 plog_err("Unable to register ip "IPv6_BYTES_FMT"\n", IPv6_BYTES(local_ipv6_addr->bytes));
138                 return;
139         }
140         memcpy(&key.ip6, global_ipv6_addr, sizeof(struct ipv6_addr));
141         ret = rte_hash_add_key(task->internal_ip6_hash, (const void *)&key);
142         if (unlikely(ret < 0)) {
143                 plog_err("Unable to register ip "IPv6_BYTES_FMT"\n", IPv6_BYTES(global_ipv6_addr->bytes));
144                 return;
145         }
146         memcpy(&task->internal_ip6_table[ret].mac, &prox_port_cfg[port_id].eth_addr, sizeof(prox_rte_ether_addr));
147         task->internal_ip6_table[ret].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
148 }
149
150 void master_init_vdev(struct task_base *tbase, uint8_t port_id, uint8_t core_id, uint8_t task_id)
151 {
152         struct task_master *task = (struct task_master *)tbase;
153         uint8_t vdev_port = prox_port_cfg[port_id].dpdk_mapping;
154         int rc, i;
155         if (vdev_port != NO_VDEV_PORT) {
156                 for (i = 0; i < task->max_vdev_id; i++) {
157                         if (task->all_vdev[i].port_id == vdev_port)
158                                 break;
159                 }
160                 if (i <  task->max_vdev_id) {
161                         // Already initialized (e.g. by another core handling the same port).
162                         return;
163                 }
164                 task->all_vdev[task->max_vdev_id].port_id = vdev_port;
165                 task->all_vdev[task->max_vdev_id].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
166
167                 struct sockaddr_in dst, src;
168                 src.sin_family = AF_INET;
169                 src.sin_addr.s_addr = prox_port_cfg[vdev_port].ip;
170                 src.sin_port = rte_cpu_to_be_16(PROX_PSEUDO_PKT_PORT);
171
172                 int fd = socket(AF_INET,  SOCK_DGRAM, 0);
173                 PROX_PANIC(fd < 0, "Failed to open socket(AF_INET,  SOCK_DGRAM, 0)\n");
174                 prox_port_cfg[vdev_port].fd = fd;
175                 rc = bind(fd,(struct sockaddr *)&src, sizeof(struct sockaddr_in));
176                 PROX_PANIC(rc, "Failed to bind("IPv4_BYTES_FMT":%d): errno = %d\n", IPv4_BYTES(((uint8_t*)&src.sin_addr.s_addr)), src.sin_port, errno);
177                 plog_info("DPDK port %d bound("IPv4_BYTES_FMT":%d) to fd %d\n", port_id, IPv4_BYTES(((uint8_t*)&src.sin_addr.s_addr)), src.sin_port, fd);
178                 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
179                 task->max_vdev_id++;
180         }
181 }
182
183 void register_ip_to_ctrl_plane(struct task_base *tbase, uint32_t ip, uint8_t port_id, uint8_t core_id, uint8_t task_id)
184 {
185         struct task_master *task = (struct task_master *)tbase;
186         struct ip_port key;
187         plogx_info("\tregistering IP "IPv4_BYTES_FMT" with port %d core %d and task %d\n", IP4(ip), port_id, core_id, task_id);
188
189         if (port_id >= PROX_MAX_PORTS) {
190                 plog_err("Unable to register ip "IPv4_BYTES_FMT", port %d\n", IP4(ip), port_id);
191                 return;
192         }
193
194         /* TODO - store multiple rings if multiple cores able to handle IP
195            Remove them when such cores are stopped and de-register IP
196         */
197         task->internal_port_table[port_id].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
198         memcpy(&task->internal_port_table[port_id].mac, &prox_port_cfg[port_id].eth_addr, sizeof(prox_rte_ether_addr));
199         task->internal_port_table[port_id].ip = ip;
200
201         if (ip == RANDOM_IP) {
202                 task->internal_port_table[port_id].flags |= HANDLE_RANDOM_IP_FLAG;
203                 return;
204         }
205
206         key.ip = ip;
207         key.port = port_id;
208         int ret = rte_hash_add_key(task->internal_ip_hash, (const void *)&key);
209         if (unlikely(ret < 0)) {
210                 plog_err("Unable to register ip "IPv4_BYTES_FMT"\n", IP4(ip));
211                 return;
212         }
213         memcpy(&task->internal_ip_table[ret].mac, &prox_port_cfg[port_id].eth_addr, sizeof(prox_rte_ether_addr));
214         task->internal_ip_table[ret].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
215 }
216
217 static inline void handle_arp_reply(struct task_base *tbase, struct rte_mbuf *mbuf)
218 {
219         struct task_master *task = (struct task_master *)tbase;
220         struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
221         int i, ret;
222         uint32_t key = hdr_arp->arp.data.spa;
223         plogx_dbg("\tMaster handling ARP reply for ip "IPv4_BYTES_FMT"\n", IP4(key));
224
225         ret = rte_hash_lookup(task->external_ip_hash, (const void *)&key);
226         if (unlikely(ret < 0)) {
227                 // entry not found for this IP: we did not ask a request, delete the reply
228                 tx_drop(mbuf);
229         } else {
230                 // entry found for this IP
231                 uint16_t nb_requests = task->external_ip_table[ret].nb_requests;
232                 // If we receive a request from multiple task for the same IP, then we update all tasks
233                 if (task->external_ip_table[ret].nb_requests) {
234                         rte_mbuf_refcnt_set(mbuf, nb_requests);
235                         for (int i = 0; i < nb_requests; i++) {
236                                 struct rte_ring *ring = task->external_ip_table[ret].rings[i];
237                                 tx_ring_ip(tbase, ring, MAC_INFO_FROM_MASTER, mbuf, key);
238                         }
239                         task->external_ip_table[ret].nb_requests = 0;
240                 } else {
241                         tx_drop(mbuf);
242                 }
243         }
244 }
245
246 static inline void handle_arp_request(struct task_base *tbase, struct rte_mbuf *mbuf)
247 {
248         struct task_master *task = (struct task_master *)tbase;
249         struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
250         int i, ret;
251         uint8_t port = get_port(mbuf);
252
253         struct ip_port key;
254         key.ip = hdr_arp->arp.data.tpa;
255         key.port = port;
256         if (task->internal_port_table[port].flags & HANDLE_RANDOM_IP_FLAG) {
257                 prox_rte_ether_addr mac;
258                 plogx_dbg("\tMaster handling ARP request for ip "IPv4_BYTES_FMT" on port %d which supports random ip\n", IP4(key.ip), key.port);
259                 struct rte_ring *ring = task->internal_port_table[port].ring;
260                 create_mac(hdr_arp, &mac);
261                 mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);
262                 build_arp_reply(hdr_arp, &mac);
263                 tx_ring(tbase, ring, SEND_ARP_REPLY_FROM_MASTER, mbuf);
264                 return;
265         }
266
267         plogx_dbg("\tMaster handling ARP request for ip "IPv4_BYTES_FMT"\n", IP4(key.ip));
268
269         ret = rte_hash_lookup(task->internal_ip_hash, (const void *)&key);
270         if (unlikely(ret < 0)) {
271                 // entry not found for this IP.
272                 plogx_dbg("Master ignoring ARP REQUEST received on un-registered IP "IPv4_BYTES_FMT" on port %d\n", IP4(hdr_arp->arp.data.tpa), port);
273                 tx_drop(mbuf);
274         } else {
275                 struct rte_ring *ring = task->internal_ip_table[ret].ring;
276                 mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);
277                 build_arp_reply(hdr_arp, &task->internal_ip_table[ret].mac);
278                 tx_ring(tbase, ring, SEND_ARP_REPLY_FROM_MASTER, mbuf);
279         }
280 }
281
282 static inline int record_request(struct task_base *tbase, uint32_t ip_dst, uint8_t port, struct rte_ring *ring)
283 {
284         struct task_master *task = (struct task_master *)tbase;
285         int ret = rte_hash_add_key(task->external_ip_hash, (const void *)&ip_dst);
286         int i;
287
288         if (unlikely(ret < 0)) {
289                 plogx_dbg("Unable to add IP "IPv4_BYTES_FMT" in external_ip_hash\n", IP4(ip_dst));
290                 return -1;
291         }
292
293         // If multiple tasks requesting the same info, we will need to send a reply to all of them
294         // However if one task sends multiple requests to the same IP (e.g. because it is not answering)
295         // then we should not send multiple replies to the same task
296         if (task->external_ip_table[ret].nb_requests >= PROX_MAX_ARP_REQUESTS) {
297                 // This can only happen if really many tasks requests the same IP
298                 plogx_dbg("Unable to add request for IP "IPv4_BYTES_FMT" in external_ip_table\n", IP4(ip_dst));
299                 return -1;
300         }
301         for (i = 0; i < task->external_ip_table[ret].nb_requests; i++) {
302                 if (task->external_ip_table[ret].rings[i] == ring)
303                         break;
304         }
305         if (i >= task->external_ip_table[ret].nb_requests) {
306                 // If this is a new request i.e. a new task requesting a new IP
307                 task->external_ip_table[ret].rings[task->external_ip_table[ret].nb_requests] = ring;
308                 task->external_ip_table[ret].nb_requests++;
309         }
310         return 0;
311 }
312
313 static inline void handle_unknown_ip(struct task_base *tbase, struct rte_mbuf *mbuf)
314 {
315         struct task_master *task = (struct task_master *)tbase;
316         struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
317         uint8_t port = get_port(mbuf);
318         uint32_t ip_dst = get_ip(mbuf);
319
320         plogx_dbg("\tMaster handling unknown ip "IPv4_BYTES_FMT" for port %d\n", IP4(ip_dst), port);
321         if (unlikely(port >= PROX_MAX_PORTS)) {
322                 plogx_dbg("Port %d not found", port);
323                 tx_drop(mbuf);
324                 return;
325         }
326         uint32_t ip_src = task->internal_port_table[port].ip;
327         struct rte_ring *ring = task->ctrl_tx_rings[get_core(mbuf) * MAX_TASKS_PER_CORE + get_task(mbuf)];
328
329         if (ring == NULL) {
330                 plogx_dbg("Port %d not registered", port);
331                 tx_drop(mbuf);
332                 return;
333         }
334
335         if (record_request(tbase, ip_dst, port, ring) < 0) {
336                 tx_drop(mbuf);
337                 return;
338         }
339         // We send an ARP request even if one was just sent (and not yet answered) by another task
340         mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);
341         build_arp_request(mbuf, &task->internal_port_table[port].mac, ip_dst, ip_src);
342         tx_ring(tbase, ring, SEND_ARP_REQUEST_FROM_MASTER, mbuf);
343 }
344
345 static inline void build_icmp_reply_message(struct task_base *tbase, struct rte_mbuf *mbuf)
346 {
347         struct task_master *task = (struct task_master *)tbase;
348         struct ip_port key;
349         key.port = mbuf->port;
350         prox_rte_ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
351         prox_rte_ether_addr dst_mac;
352         prox_rte_ether_addr_copy(&hdr->s_addr, &dst_mac);
353         prox_rte_ether_addr_copy(&hdr->d_addr, &hdr->s_addr);
354         prox_rte_ether_addr_copy(&dst_mac, &hdr->d_addr);
355         prox_rte_ipv4_hdr *ip_hdr = (prox_rte_ipv4_hdr *)(hdr + 1);
356         key.ip = ip_hdr->dst_addr;
357         ip_hdr->dst_addr = ip_hdr->src_addr;
358         ip_hdr->src_addr = key.ip;
359         prox_rte_icmp_hdr *picmp = (prox_rte_icmp_hdr *)(ip_hdr + 1);
360         picmp->icmp_type = PROX_RTE_IP_ICMP_ECHO_REPLY;
361
362         int ret = rte_hash_lookup(task->internal_ip_hash, (const void *)&key);
363         if (unlikely(ret < 0)) {
364                 // entry not found for this IP.
365                 plogx_dbg("Master ignoring ICMP received on un-registered IP "IPv4_BYTES_FMT" on port %d\n", IP4(key.ip), mbuf->port);
366                 tx_drop(mbuf);
367         } else {
368                 struct rte_ring *ring = task->internal_ip_table[ret].ring;
369                 mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);
370                 tx_ring(tbase, ring, SEND_ICMP_FROM_MASTER, mbuf);
371         }
372 }
373
374 static inline void handle_icmp(struct task_base *tbase, struct rte_mbuf *mbuf)
375 {
376         struct task_master *task = (struct task_master *)tbase;
377         uint8_t port_id = mbuf->port;
378         struct port_table *port = &task->internal_port_table[port_id];
379         prox_rte_ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
380         if (hdr->ether_type != ETYPE_IPv4) {
381                 tx_drop(mbuf);
382                 return;
383         }
384         prox_rte_ipv4_hdr *ip_hdr = (prox_rte_ipv4_hdr *)(hdr + 1);
385         if (ip_hdr->next_proto_id != IPPROTO_ICMP) {
386                 tx_drop(mbuf);
387                 return;
388         }
389         if (ip_hdr->dst_addr != port->ip) {
390                 tx_drop(mbuf);
391                 return;
392         }
393
394         prox_rte_icmp_hdr *picmp = (prox_rte_icmp_hdr *)(ip_hdr + 1);
395         uint8_t type = picmp->icmp_type;
396         if (type == PROX_RTE_IP_ICMP_ECHO_REQUEST) {
397                 port->n_echo_req++;
398                 if (rte_rdtsc() - port->last_echo_req_rcvd_tsc > rte_get_tsc_hz()) {
399                         plog_dbg("Received %u Echo Request on IP "IPv4_BYTES_FMT" (last received from IP "IPv4_BYTES_FMT")\n", port->n_echo_req, IPv4_BYTES(((uint8_t*)&ip_hdr->dst_addr)), IPv4_BYTES(((uint8_t*)&ip_hdr->src_addr)));
400                         port->n_echo_req = 0;
401                         port->last_echo_req_rcvd_tsc = rte_rdtsc();
402                 }
403                 build_icmp_reply_message(tbase, mbuf);
404         } else if (type == PROX_RTE_IP_ICMP_ECHO_REPLY) {
405                 port->n_echo_rep++;
406                 if (rte_rdtsc() - port->last_echo_rep_rcvd_tsc > rte_get_tsc_hz()) {
407                         plog_info("Received %u Echo Reply on IP "IPv4_BYTES_FMT" (last received from IP "IPv4_BYTES_FMT")\n", port->n_echo_rep, IPv4_BYTES(((uint8_t*)&ip_hdr->dst_addr)), IPv4_BYTES(((uint8_t*)&ip_hdr->src_addr)));
408                         port->n_echo_rep = 0;
409                         port->last_echo_rep_rcvd_tsc = rte_rdtsc();
410                 }
411         }
412         tx_drop(mbuf);
413         return;
414 }
415
416 static inline void handle_unknown_ip6(struct task_base *tbase, struct rte_mbuf *mbuf)
417 {
418         struct task_master *task = (struct task_master *)tbase;
419         struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
420         uint8_t port = get_port(mbuf);
421         struct ipv6_addr *ip_dst = ctrl_ring_get_ipv6_addr(mbuf);
422         int ret1, ret2, i;
423
424         plogx_dbg("\tMaster trying to find MAC of external IP "IPv6_BYTES_FMT" for port %d\n", IPv6_BYTES(ip_dst->bytes), port);
425         if (unlikely(port >= PROX_MAX_PORTS)) {
426                 plogx_dbg("Port %d not found", port);
427                 tx_drop(mbuf);
428                 return;
429         }
430         struct ipv6_addr *local_ip_src = &task->internal_port_table[port].local_ipv6_addr;
431         struct ipv6_addr *global_ip_src = &task->internal_port_table[port].global_ipv6_addr;
432         struct ipv6_addr *ip_src;
433         if (memcmp(local_ip_src, ip_dst, 8) == 0)
434                 ip_src = local_ip_src;
435         else if (memcmp(global_ip_src,  &null_addr, 16))
436                 ip_src = global_ip_src;
437         else {
438                 plogx_dbg("Unable to find a src ip for dst ip "IPv6_BYTES_FMT"\n", IPv6_BYTES(ip_dst->bytes));
439                 tx_drop(mbuf);
440                 return;
441         }
442         struct rte_ring *ring = task->ctrl_tx_rings[get_core(mbuf) * MAX_TASKS_PER_CORE + get_task(mbuf)];
443
444         if (ring == NULL) {
445                 plogx_dbg("Port %d not registered", port);
446                 tx_drop(mbuf);
447                 return;
448         }
449
450         ret2 = rte_hash_add_key(task->external_ip6_hash, (const void *)ip_dst);
451         if (unlikely(ret2 < 0)) {
452                 plogx_dbg("Unable to add IP "IPv6_BYTES_FMT" in external_ip6_hash\n", IPv6_BYTES(ip_dst->bytes));
453                 tx_drop(mbuf);
454                 return;
455         }
456
457         // If multiple tasks requesting the same info, we will need to send a reply to all of them
458         // However if one task sends multiple requests to the same IP (e.g. because it is not answering)
459         // then we should not send multiple replies to the same task
460         if (task->external_ip6_table[ret2].nb_requests >= PROX_MAX_ARP_REQUESTS) {
461                 // This can only happen if really many tasks requests the same IP
462                 plogx_dbg("Unable to add request for IP "IPv6_BYTES_FMT" in external_ip6_table\n", IPv6_BYTES(ip_dst->bytes));
463                 tx_drop(mbuf);
464                 return;
465         }
466         for (i = 0; i < task->external_ip6_table[ret2].nb_requests; i++) {
467                 if (task->external_ip6_table[ret2].rings[i] == ring)
468                         break;
469         }
470         if (i >= task->external_ip6_table[ret2].nb_requests) {
471                 // If this is a new request i.e. a new task requesting a new IP
472                 task->external_ip6_table[ret2].rings[task->external_ip6_table[ret2].nb_requests] = ring;
473                 task->external_ip6_table[ret2].nb_requests++;
474                 // Only needed for first request - but avoid test and copy the same 6 bytes
475                 // In most cases we will only have one request per IP.
476                 //memcpy(&task->external_ip6_table[ret2].mac, &task->internal_port_table[port].mac, sizeof(prox_rte_ether_addr));
477         }
478
479         // As timers are not handled by master, we might send an NS request even if one was just sent
480         // (and not yet answered) by another task
481         build_neighbour_sollicitation(mbuf, &task->internal_port_table[port].mac, ip_dst, ip_src);
482         tx_ring(tbase, ring, SEND_NDP_FROM_MASTER, mbuf);
483 }
484
485 static inline void handle_rs(struct task_base *tbase, struct rte_mbuf *mbuf)
486 {
487         struct task_master *task = (struct task_master *)tbase;
488         prox_rte_ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
489         prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(hdr + 1);
490         int i, ret;
491         uint8_t port = get_port(mbuf);
492
493         if (task->internal_port_table[port].flags & IPV6_ROUTER) {
494                 plogx_dbg("\tMaster handling Router Solicitation from ip "IPv6_BYTES_FMT" on port %d\n", IPv6_BYTES(ipv6_hdr->src_addr), port);
495                 struct rte_ring *ring = task->internal_port_table[port].ring;
496                 build_router_advertisement(mbuf, &prox_port_cfg[port].eth_addr, &task->internal_port_table[port].local_ipv6_addr, &task->internal_port_table[port].router_prefix);
497                 tx_ring(tbase, ring, SEND_NDP_FROM_MASTER, mbuf);
498                 return;
499         }
500 }
501
502 static inline void handle_ra(struct task_base *tbase, struct rte_mbuf *mbuf)
503 {
504         struct task_master *task = (struct task_master *)tbase;
505         prox_rte_ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
506         prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(hdr + 1);
507         int i, ret, send = 0;
508         uint8_t port = get_port(mbuf);
509         struct rte_ring *ring = task->internal_port_table[port].ring;
510
511         plog_dbg("Master handling Router Advertisement from ip "IPv6_BYTES_FMT" on port %d - len = %d; payload_len = %d\n", IPv6_BYTES(ipv6_hdr->src_addr), port, rte_pktmbuf_pkt_len(mbuf), rte_be_to_cpu_16(ipv6_hdr->payload_len));
512         if (rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr) > rte_pktmbuf_pkt_len(mbuf)) {
513                 plog_err("Unexpected length received: pkt_len = %d, ipv6 hdr length = %ld, ipv6 payload len = %d\n", rte_pktmbuf_pkt_len(mbuf), sizeof(prox_rte_ipv6_hdr), rte_be_to_cpu_16(ipv6_hdr->payload_len));
514                 tx_drop(mbuf);
515                 return;
516         }
517         if (ring == NULL) {
518                 plog_info("TX side not initialized yet => dropping\n");
519                 tx_drop(mbuf);
520                 return;
521         }
522         int16_t option_len = rte_be_to_cpu_16(ipv6_hdr->payload_len) - sizeof(struct icmpv6_RA) + sizeof(struct icmpv6_option);
523         struct icmpv6_RA *router_advertisement = (struct icmpv6_RA *)(ipv6_hdr + 1);
524         struct icmpv6_option *option = (struct icmpv6_option *)&router_advertisement->options;
525         struct icmpv6_prefix_option *prefix_option;
526         while(option_len > 0) {
527                 uint8_t   type = option->type;
528                 switch(type) {
529                         case ICMPv6_source_link_layer_address:
530                                 plog_dbg("\tOption %d = Source Link Layer Address\n", type);
531                                 break;
532                         case ICMPv6_prefix_information:
533                                 prefix_option = (struct icmpv6_prefix_option *)option;
534                                 plog_dbg("\tOption %d = Prefix Information = %s\n", type, IP6_Canonical(&prefix_option->prefix));
535                                 send = 1;
536                                 break;
537                         case ICMPv6_mtu:
538                                 plog_dbg("\tOption %d = MTU\n", type);
539                                 break;
540                         default:
541                                 plog_dbg("\tOption %d = Unknown Option\n", type);
542                                 break;
543                 }
544                 if ((option->length == 0) || (option->length *8 > option_len)) {
545                         plog_err("Unexpected option length (%d) received in option %d: %d\n", option->length, option->type, option->length);
546                         send = 0;
547                         break;
548                 }
549                 option_len -=option->length * 8;
550                 option = (struct icmpv6_option *)(((uint8_t *)option) + option->length * 8);
551         }
552         if (send) {
553                 struct ipv6_addr global_ipv6;
554                 memcpy(&global_ipv6, &prefix_option->prefix, sizeof(struct ipv6_addr));
555                 set_EUI(&global_ipv6, &task->internal_port_table[port].mac);
556                 tx_ring_ip6(tbase, ring, IPV6_INFO_FROM_MASTER, mbuf, &global_ipv6);
557         } else
558                 tx_drop(mbuf);
559 }
560
561 static inline void handle_ns(struct task_base *tbase, struct rte_mbuf *mbuf)
562 {
563         struct task_master *task = (struct task_master *)tbase;
564         prox_rte_ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
565         prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(hdr + 1);
566         struct icmpv6_NS *neighbour_sollicitation = (struct icmpv6_NS *)(ipv6_hdr + 1);
567         int i, ret;
568         uint8_t port = get_port(mbuf);
569         struct rte_ring *ring = task->internal_port_table[port].ring;
570
571         plog_dbg("Master handling Neighbour Sollicitation for ip "IPv6_BYTES_FMT" on port %d - len = %d; payload_len = %d\n", IPv6_BYTES(neighbour_sollicitation->target_address.bytes), port, rte_pktmbuf_pkt_len(mbuf), rte_be_to_cpu_16(ipv6_hdr->payload_len));
572         if (rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr) > rte_pktmbuf_pkt_len(mbuf)) {
573                 plog_err("Unexpected length received: pkt_len = %d, ipv6 hdr length = %ld, ipv6 payload len = %d\n", rte_pktmbuf_pkt_len(mbuf), sizeof(prox_rte_ipv6_hdr), rte_be_to_cpu_16(ipv6_hdr->payload_len));
574                 tx_drop(mbuf);
575                 return;
576         }
577         int16_t option_len = rte_be_to_cpu_16(ipv6_hdr->payload_len) - sizeof(struct icmpv6_NS) + sizeof(struct icmpv6_option);
578         struct icmpv6_option *option = (struct icmpv6_option *)&neighbour_sollicitation->options;
579         while(option_len > 0) {
580                 uint8_t   type = option->type;
581                 switch(type) {
582                         case ICMPv6_source_link_layer_address:
583                                 plog_dbg("Option %d = Source Link Layer Address\n", type);
584                                 break;
585                         default:
586                                 plog_dbg("Option %d = Unknown Option\n", type);
587                                 break;
588                 }
589                 if ((option->length == 0) || (option->length *8 > option_len)) {
590                         plog_err("Unexpected option length (%d) received in option %d: %d\n", option->length, option->type, option->length);
591                         tx_drop(mbuf);
592                         return;
593                 }
594                 option_len -=option->length * 8;
595                 option = (struct icmpv6_option *)(((uint8_t *)option) + option->length * 8);
596         }
597         struct ip6_port key;
598         memcpy(&key.ip6, &neighbour_sollicitation->target_address, sizeof(struct ipv6_addr));
599         key.port = port;
600
601         if (memcmp(&neighbour_sollicitation->target_address, &task->internal_port_table[port].local_ipv6_addr, 8) == 0) {
602                 // Local IP
603                 if (task->internal_port_table[port].flags & HANDLE_RANDOM_LOCAL_IP_FLAG) {
604                         prox_rte_ether_addr mac;
605                         plogx_dbg("\tMaster handling NS request for ip "IPv6_BYTES_FMT" on port %d which supports random ip\n", IPv6_BYTES(key.ip6.bytes), key.port);
606                         struct rte_ring *ring = task->internal_port_table[port].ring;
607                         create_mac_from_EUI(&key.ip6, &mac);
608                         build_neighbour_advertisement(tbase, mbuf, &mac, &task->internal_port_table[port].local_ipv6_addr, PROX_SOLLICITED);
609                         tx_ring(tbase, ring, SEND_NDP_FROM_MASTER, mbuf);
610                         return;
611                 }
612         } else {
613                 if (task->internal_port_table[port].flags & HANDLE_RANDOM_GLOBAL_IP_FLAG) {
614                         prox_rte_ether_addr mac;
615                         plogx_dbg("\tMaster handling NS request for ip "IPv6_BYTES_FMT" on port %d which supports random ip\n", IPv6_BYTES(key.ip6.bytes), key.port);
616                         struct rte_ring *ring = task->internal_port_table[port].ring;
617                         create_mac_from_EUI(&key.ip6, &mac);
618                         build_neighbour_advertisement(tbase, mbuf, &mac, &task->internal_port_table[port].global_ipv6_addr, PROX_SOLLICITED);
619                         tx_ring(tbase, ring, SEND_NDP_FROM_MASTER, mbuf);
620                         return;
621                 }
622         }
623
624         ret = rte_hash_lookup(task->internal_ip6_hash, (const void *)&key);
625         if (unlikely(ret < 0)) {
626                 // entry not found for this IP.
627                 plogx_dbg("Master ignoring Neighbour Sollicitation received on un-registered IP "IPv6_BYTES_FMT" on port %d\n", IPv6_BYTES(key.ip6.bytes), port);
628                 tx_drop(mbuf);
629         } else {
630                 struct rte_ring *ring = task->internal_ip6_table[ret].ring;
631                 build_neighbour_advertisement(tbase, mbuf, &task->internal_ip6_table[ret].mac, &key.ip6, PROX_SOLLICITED);
632                 tx_ring(tbase, ring, SEND_NDP_FROM_MASTER, mbuf);
633         }
634 }
635
636 static inline void handle_na(struct task_base *tbase, struct rte_mbuf *mbuf)
637 {
638         struct task_master *task = (struct task_master *)tbase;
639         prox_rte_ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
640         prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(hdr + 1);
641         struct icmpv6_NA *neighbour_advertisement = (struct icmpv6_NA *)(ipv6_hdr + 1);
642         int i, ret;
643         uint8_t port = get_port(mbuf);
644         struct rte_ring *ring = task->internal_port_table[port].ring;
645
646         plog_dbg("Master handling Neighbour Advertisement for ip "IPv6_BYTES_FMT" on port %d - len = %d; payload_len = %d\n", IPv6_BYTES(neighbour_advertisement->destination_address.bytes), port, rte_pktmbuf_pkt_len(mbuf), rte_be_to_cpu_16(ipv6_hdr->payload_len));
647         if (rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr) > rte_pktmbuf_pkt_len(mbuf)) {
648                 plog_err("Unexpected length received: pkt_len = %d, ipv6 hdr length = %ld, ipv6 payload len = %d\n", rte_pktmbuf_pkt_len(mbuf), sizeof(prox_rte_ipv6_hdr), rte_be_to_cpu_16(ipv6_hdr->payload_len));
649                 tx_drop(mbuf);
650                 return;
651         }
652         int16_t option_len = rte_be_to_cpu_16(ipv6_hdr->payload_len) - sizeof(struct icmpv6_NA) + sizeof(struct icmpv6_option);
653         struct icmpv6_option *option = (struct icmpv6_option *)&neighbour_advertisement->options;
654         uint8_t *target_address = NULL;
655         while(option_len > 0) {
656                 uint8_t   type = option->type;
657                 switch(type) {
658                         case ICMPv6_source_link_layer_address:
659                                 plog_dbg("Option %d = Source Link Layer Address\n", type);
660                                 break;
661                         case ICMPv6_target_link_layer_address:
662                                 if (option->length != 1) {
663                                         plog_err("Unexpected option length = %u for Target Link Layer Address\n", option->length);
664                                         break;
665                                 }
666                                 target_address = option->data;
667                                 plog_dbg("Option %d = Target Link Layer Address = "MAC_BYTES_FMT"\n", type, MAC_BYTES(target_address));
668                                 break;
669                         default:
670                                 plog_dbg("Option %d = Unknown Option\n", type);
671                                 break;
672                 }
673                 if ((option->length == 0) || (option->length *8 > option_len)) {
674                         plog_err("Unexpected option length (%d) received in option %d: %d\n", option->length, option->type, option->length);
675                         tx_drop(mbuf);
676                         return;
677                 }
678                 option_len -=option->length * 8;
679                 option = (struct icmpv6_option *)(((uint8_t *)option) + option->length * 8);
680         }
681
682         if (target_address == NULL) {
683                 tx_drop(mbuf);
684         }
685         struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
686         struct ipv6_addr *key = &neighbour_advertisement->destination_address;
687
688         ret = rte_hash_lookup(task->external_ip6_hash, (const void *)key);
689         if (unlikely(ret < 0)) {
690                 // entry not found for this IP: we did not ask a request, delete the reply
691                 tx_drop(mbuf);
692         } else {
693                 // entry found for this IP
694                 uint16_t nb_requests = task->external_ip6_table[ret].nb_requests;
695                 //memcpy(&hdr->d_addr.addr_bytes, &task->external_ip6_table[ret].mac, sizeof(prox_rte_ether_addr));
696                 // If we receive a request from multiple task for the same IP, then we update all tasks
697                 if (task->external_ip6_table[ret].nb_requests) {
698                         rte_mbuf_refcnt_set(mbuf, nb_requests);
699                         for (int i = 0; i < nb_requests; i++) {
700                                 struct rte_ring *ring = task->external_ip6_table[ret].rings[i];
701                                 tx_ring_ip6_data(tbase, ring, MAC_INFO_FROM_MASTER_FOR_IPV6, mbuf, &neighbour_advertisement->destination_address, *(uint64_t *)target_address);
702                         }
703                         task->external_ip6_table[ret].nb_requests = 0;
704                 } else {
705                         tx_drop(mbuf);
706                 }
707         }
708 }
709
710 static inline void handle_message(struct task_base *tbase, struct rte_mbuf *mbuf, int ring_id)
711 {
712         struct task_master *task = (struct task_master *)tbase;
713         struct ether_hdr_arp *hdr_arp;
714         prox_rte_ether_hdr *hdr;
715         struct icmpv6 *icmpv6;
716         int command = get_command(mbuf);
717         uint8_t port = get_port(mbuf);
718         uint32_t ip;
719         uint8_t vdev_port = prox_port_cfg[port].dpdk_mapping;
720         plogx_dbg("\tMaster received %s (%x) from mbuf %p\n", actions_string[command], command, mbuf);
721
722         switch(command) {
723         case BGP_TO_MASTER:
724                 if (vdev_port != NO_VDEV_PORT) {
725                         // If a virtual (net_tap) device is attached, send the (BGP) packet to this device
726                         // The kernel will receive and handle it.
727                         plogx_dbg("\tMaster forwarding BGP packet to TAP\n");
728                         int n = rte_eth_tx_burst(prox_port_cfg[port].dpdk_mapping, 0, &mbuf, 1);
729                         return;
730                 }
731                 tx_drop(mbuf);
732                 break;
733         case ICMP_TO_MASTER:
734                 if (vdev_port != NO_VDEV_PORT) {
735                         // If a virtual (net_tap) device is attached, send the (PING) packet to this device
736                         // The kernel will receive and handle it.
737                         plogx_dbg("\tMaster forwarding packet to TAP\n");
738                         int n = rte_eth_tx_burst(prox_port_cfg[port].dpdk_mapping, 0, &mbuf, 1);
739                         return;
740                 }
741                 handle_icmp(tbase, mbuf);
742                 break;
743         case ARP_PKT_FROM_NET_TO_MASTER:
744                 if (vdev_port != NO_VDEV_PORT) {
745                         // If a virtual (net_tap) device is attached, send the (ARP) packet to this device
746                         // The kernel will receive and handle it.
747                         plogx_dbg("\tMaster forwarding packet to TAP\n");
748                         int n = rte_eth_tx_burst(prox_port_cfg[port].dpdk_mapping, 0, &mbuf, 1);
749                         return;
750                 }
751                 hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
752                 if (hdr_arp->ether_hdr.ether_type != ETYPE_ARP) {
753                         plog_err("\tUnexpected message received: ARP_PKT_FROM_NET_TO_MASTER with ether_type %x\n", hdr_arp->ether_hdr.ether_type);
754                         tx_drop(mbuf);
755                         return;
756                 } else if (arp_is_gratuitous(hdr_arp)) {
757                         plog_info("\tReceived gratuitous packet \n");
758                         tx_drop(mbuf);
759                         return;
760                 } else if (memcmp(&hdr_arp->arp, &arp_reply, 8) == 0) {
761                         uint32_t ip = hdr_arp->arp.data.spa;
762                         handle_arp_reply(tbase, mbuf);
763                 } else if (memcmp(&hdr_arp->arp, &arp_request, 8) == 0) {
764                         handle_arp_request(tbase, mbuf);
765                 } else {
766                         plog_info("\tReceived unexpected ARP operation %d\n", hdr_arp->arp.oper);
767                         tx_drop(mbuf);
768                         return;
769                 }
770                 break;
771         case IP4_REQ_MAC_TO_MASTER:
772                 if (vdev_port != NO_VDEV_PORT) {
773                         // We send a packet to the kernel with the proper destnation IP address and our src IP address
774                         // This means that if a generator sends packets from many sources all ARP will still
775                         // be sent from the same IP src. This might be a limitation.
776                         // This prevent to have to open as many sockets as there are sources MAC addresses
777                         // We also always use the same UDP ports - as the packet will finally not leave the system anyhow
778
779                         struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
780                         uint32_t ip = get_ip(mbuf);
781                         struct rte_ring *ring = task->ctrl_tx_rings[get_core(mbuf) * MAX_TASKS_PER_CORE + get_task(mbuf)];
782
783                         // First check whether MAC address is not already in kernel MAC table.
784                         // If present in our hash with a non-null MAC, then present in kernel. A null MAC
785                         // might just mean that we sent a request.
786                         // If MAC present in kernel, do not send a packet towards the kernel to try to generate
787                         // an ARP request, as the kernel would not generate it.
788                         int ret = rte_hash_lookup(task->external_ip_hash, (const void *)&ip);
789                         if ((ret >= 0) && (!prox_rte_is_zero_ether_addr(&task->external_ip_table[ret].mac))) {
790                                 memcpy(&hdr_arp->arp.data.sha, &task->external_ip_table[ret].mac, sizeof(prox_rte_ether_addr));
791                                 plogx_dbg("\tMaster ready to send MAC_INFO_FROM_MASTER ip "IPv4_BYTES_FMT" with mac "MAC_BYTES_FMT"\n",
792                                         IP4(ip), MAC_BYTES(hdr_arp->arp.data.sha.addr_bytes));
793                                 tx_ring_ip(tbase, ring, MAC_INFO_FROM_MASTER, mbuf, ip);
794                                 return;
795                         }
796
797                         struct sockaddr_in dst;
798                         dst.sin_family = AF_INET;
799                         dst.sin_addr.s_addr = ip;
800                         dst.sin_port = rte_cpu_to_be_16(PROX_PSEUDO_PKT_PORT);
801                         int n = sendto(prox_port_cfg[vdev_port].fd, (char*)(&ip), 0, 0,  (struct sockaddr *)&dst, sizeof(struct sockaddr_in));
802                         plogx_dbg("\tSent %d bytes to TAP IP "IPv4_BYTES_FMT" using fd %d\n", n, IPv4_BYTES(((uint8_t*)&ip)), prox_port_cfg[vdev_port].fd);
803
804                         record_request(tbase, ip, port, ring);
805                         tx_drop(mbuf);
806                         break;
807                 }
808                 handle_unknown_ip(tbase, mbuf);
809                 break;
810         case IP6_REQ_MAC_TO_MASTER:
811                 handle_unknown_ip6(tbase, mbuf);
812                 break;
813         case NDP_PKT_FROM_NET_TO_MASTER:
814                 hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
815                 prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(hdr + 1);
816                 if (unlikely((hdr->ether_type != ETYPE_IPv6) || (ipv6_hdr->proto != ICMPv6))) {
817                         // Should not happen
818                         if (hdr->ether_type != ETYPE_IPv6)
819                                 plog_err("\tUnexpected message received: NDP_PKT_FROM_NET_TO_MASTER with ether_type %x\n", hdr->ether_type);
820                         else
821                                 plog_err("\tUnexpected message received: NDP_PKT_FROM_NET_TO_MASTER with ether_type %x and proto %x\n", hdr->ether_type, ipv6_hdr->proto);
822                         tx_drop(mbuf);
823                         return;
824                 }
825                 icmpv6 = (struct icmpv6 *)(ipv6_hdr + 1);
826                 switch (icmpv6->type) {
827                 case ICMPv6_DU:
828                         plog_err("IPV6 ICMPV6 Destination Unreachable\n");
829                         tx_drop(mbuf);
830                         break;
831                 case ICMPv6_PTB:
832                         plog_err("IPV6 ICMPV6 packet too big\n");
833                         tx_drop(mbuf);
834                         break;
835                 case ICMPv6_TE:
836                         plog_err("IPV6 ICMPV6 Time Exceeded\n");
837                         tx_drop(mbuf);
838                         break;
839                 case ICMPv6_PaPr:
840                         plog_err("IPV6 ICMPV6 Parameter Problem\n");
841                         tx_drop(mbuf);
842                         break;
843                 case ICMPv6_RS:
844                         handle_rs(tbase, mbuf);
845                         break;
846                 case ICMPv6_RA:
847                         handle_ra(tbase, mbuf);
848                         break;
849                 case ICMPv6_NS:
850                         handle_ns(tbase, mbuf);
851                         break;
852                 case ICMPv6_NA:
853                         handle_na(tbase, mbuf);
854                         break;
855                 case ICMPv6_RE:
856                         plog_err("IPV6 ICMPV6 Redirect not handled\n");
857                         tx_drop(mbuf);
858                         break;
859                 default:
860                         plog_err("Unexpected type %d in IPV6 ICMPV6\n", icmpv6->type);
861                         tx_drop(mbuf);
862                         break;
863                 }
864                 break;
865         default:
866                 plogx_dbg("\tMaster received unexpected message\n");
867                 tx_drop(mbuf);
868                 break;
869         }
870 }
871
872 void init_ctrl_plane(struct task_base *tbase)
873 {
874         struct task_master *task = (struct task_master *)tbase;
875         int socket_id = rte_lcore_to_socket_id(prox_cfg.master);
876         uint32_t n_entries = MAX_ARP_ENTRIES * 4;
877         static char hash_name[30];
878
879         sprintf(hash_name, "A%03d_hash_arp_table", prox_cfg.master);
880         struct rte_hash_parameters hash_params = {
881                 .name = hash_name,
882                 .entries = n_entries,
883                 .hash_func = rte_hash_crc,
884                 .hash_func_init_val = 0,
885         };
886         if (prox_cfg.flags & DSF_L3_ENABLED) {
887                 hash_params.key_len = sizeof(uint32_t);
888                 task->external_ip_hash = rte_hash_create(&hash_params);
889                 PROX_PANIC(task->external_ip_hash == NULL, "Failed to set up external ip hash\n");
890                 plog_info("\texternal ip hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len);
891                 hash_name[0]++;
892
893                 task->external_ip_table = (struct external_ip_table *)prox_zmalloc(n_entries * sizeof(struct external_ip_table), socket_id);
894                 PROX_PANIC(task->external_ip_table == NULL, "Failed to allocate memory for %u entries in external ip table\n", n_entries);
895                 plog_info("\texternal ip table, with %d entries of size %ld\n", n_entries, sizeof(struct external_ip_table));
896
897                 hash_params.key_len = sizeof(struct ip_port);
898                 task->internal_ip_hash = rte_hash_create(&hash_params);
899                 PROX_PANIC(task->internal_ip_hash == NULL, "Failed to set up internal ip hash\n");
900                 plog_info("\tinternal ip hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len);
901                 hash_name[0]++;
902
903                 task->internal_ip_table = (struct ip_table *)prox_zmalloc(n_entries * sizeof(struct ip_table), socket_id);
904                 PROX_PANIC(task->internal_ip_table == NULL, "Failed to allocate memory for %u entries in internal ip table\n", n_entries);
905                 plog_info("\tinternal ip table, with %d entries of size %ld\n", n_entries, sizeof(struct ip_table));
906         }
907
908         if (prox_cfg.flags & DSF_NDP_ENABLED) {
909                 hash_params.key_len = sizeof(struct ipv6_addr);
910                 task->external_ip6_hash = rte_hash_create(&hash_params);
911                 PROX_PANIC(task->external_ip6_hash == NULL, "Failed to set up external ip6 hash\n");
912                 plog_info("\texternal ip6 hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len);
913                 hash_name[0]++;
914
915                 task->external_ip6_table = (struct external_ip_table *)prox_zmalloc(n_entries * sizeof(struct external_ip_table), socket_id);
916                 PROX_PANIC(task->external_ip6_table == NULL, "Failed to allocate memory for %u entries in external ip6 table\n", n_entries);
917                 plog_info("\texternal ip6_table, with %d entries of size %ld\n", n_entries, sizeof(struct external_ip_table));
918
919                 hash_params.key_len = sizeof(struct ip6_port);
920                 task->internal_ip6_hash = rte_hash_create(&hash_params);
921                 PROX_PANIC(task->internal_ip6_hash == NULL, "Failed to set up internal ip6 hash\n");
922                 plog_info("\tinternal ip6 hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len);
923                 hash_name[0]++;
924
925                 task->internal_ip6_table = (struct ip_table *)prox_zmalloc(n_entries * sizeof(struct ip_table), socket_id);
926                 PROX_PANIC(task->internal_ip6_table == NULL, "Failed to allocate memory for %u entries in internal ip6 table\n", n_entries);
927                 plog_info("\tinternal ip6 table, with %d entries of size %ld\n", n_entries, sizeof(struct ip_table));
928         }
929
930         int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
931         PROX_PANIC(fd < 0, "Failed to open netlink socket: %d\n", errno);
932         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
933
934         struct sockaddr_nl sockaddr;
935         memset(&sockaddr, 0, sizeof(struct sockaddr_nl));
936         sockaddr.nl_family = AF_NETLINK;
937         sockaddr.nl_groups = RTMGRP_NEIGH | RTMGRP_NOTIFY;
938         int rc = bind(fd, (struct sockaddr *)&sockaddr, sizeof(struct sockaddr_nl));
939         PROX_PANIC(rc < 0, "Failed to bind to RTMGRP_NEIGH netlink group\n");
940         task->arp_fds.fd = fd;
941         task->arp_fds.events = POLL_IN;
942         plog_info("\tRTMGRP_NEIGH netlink group bound; fd = %d\n", fd);
943
944         fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
945         PROX_PANIC(fd < 0, "Failed to open netlink socket: %d\n", errno);
946         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
947         struct sockaddr_nl sockaddr2;
948         memset(&sockaddr2, 0, sizeof(struct sockaddr_nl));
949         sockaddr2.nl_family = AF_NETLINK;
950         sockaddr2.nl_groups = RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY;
951         rc = bind(fd, (struct sockaddr *)&sockaddr2, sizeof(struct sockaddr_nl));
952         PROX_PANIC(rc < 0, "Failed to bind to RTMGRP_NEIGH netlink group\n");
953         task->route_fds.fd = fd;
954         task->route_fds.events = POLL_IN;
955         plog_info("\tRTMGRP_IPV4_ROUTE netlink group bound; fd = %d\n", fd);
956
957         static char name[] = "master_arp_nd_pool";
958         const int NB_ARP_MBUF = 1024;
959         const int ARP_MBUF_SIZE = 2048;
960         const int NB_CACHE_ARP_MBUF = 256;
961         struct rte_mempool *ret = rte_mempool_create(name, NB_ARP_MBUF, ARP_MBUF_SIZE, NB_CACHE_ARP_MBUF,
962                 sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, 0,
963                 rte_socket_id(), 0);
964         PROX_PANIC(ret == NULL, "Failed to allocate ARP memory pool on socket %u with %u elements\n",
965                 rte_socket_id(), NB_ARP_MBUF);
966         plog_info("\t\tMempool %p (%s) size = %u * %u cache %u, socket %d\n", ret, name, NB_ARP_MBUF,
967                 ARP_MBUF_SIZE, NB_CACHE_ARP_MBUF, rte_socket_id());
968         tbase->l3.arp_nd_pool = ret;
969 }
970
971 static void handle_route_event(struct task_base *tbase)
972 {
973         struct task_master *task = (struct task_master *)tbase;
974         struct rte_mbuf *mbufs[MAX_RING_BURST];
975         int fd = task->route_fds.fd, interface_index, mask = -1;
976         char interface_name[IF_NAMESIZE] = {0};
977         int len = recv(fd, netlink_buf, sizeof(netlink_buf), 0);
978         uint32_t ip = 0, gw_ip = 0;
979         if (len < 0) {
980                 plog_err("Failed to recv from netlink: %d\n", errno);
981                 return;
982         }
983         struct nlmsghdr * nl_hdr = (struct nlmsghdr *)netlink_buf;
984         if (nl_hdr->nlmsg_flags & NLM_F_MULTI) {
985                 plog_err("Unexpected multipart netlink message\n");
986                 return;
987         }
988         if ((nl_hdr->nlmsg_type != RTM_NEWROUTE) && (nl_hdr->nlmsg_type != RTM_DELROUTE))
989                 return;
990
991         struct rtmsg *rtmsg = (struct rtmsg *)NLMSG_DATA(nl_hdr);
992         int rtm_family = rtmsg->rtm_family;
993         if ((rtm_family == AF_INET) && (rtmsg->rtm_table != RT_TABLE_MAIN) &&(rtmsg->rtm_table != RT_TABLE_LOCAL))
994                 return;
995         int dst_len = rtmsg->rtm_dst_len;
996
997         struct rtattr *rta = (struct rtattr *)RTM_RTA(rtmsg);
998         int rtl = RTM_PAYLOAD(nl_hdr);
999         for (; RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
1000                 switch (rta->rta_type) {
1001                 case RTA_DST:
1002                         ip = *((uint32_t *)RTA_DATA(rta));
1003                         break;
1004                 case RTA_OIF:
1005                         interface_index = *((int *)RTA_DATA(rta));
1006                         if (if_indextoname(interface_index, interface_name) == NULL) {
1007                                 plog_info("Unknown Interface Index %d\n", interface_index);
1008                         }
1009                         break;
1010                 case RTA_METRICS:
1011                         mask = *((int *)RTA_DATA(rta));
1012                         break;
1013                 case RTA_GATEWAY:
1014                         gw_ip = *((uint32_t *)RTA_DATA(rta));
1015                         break;
1016                 default:
1017                         break;
1018                 }
1019         }
1020         int dpdk_vdev_port = -1;
1021         for (int i = 0; i< prox_rte_eth_dev_count_avail(); i++) {
1022                 if (strcmp(prox_port_cfg[i].name, interface_name) == 0)
1023                         dpdk_vdev_port = i;
1024         }
1025         if (dpdk_vdev_port != -1) {
1026                 plogx_info("Received netlink message on tap interface %s for IP "IPv4_BYTES_FMT"/%d, Gateway  "IPv4_BYTES_FMT"\n", interface_name, IP4(ip), dst_len, IP4(gw_ip));
1027                 int ret1 = rte_mempool_get(tbase->l3.arp_nd_pool, (void **)mbufs);
1028                 if (unlikely(ret1 != 0)) {
1029                         plog_err("Unable to allocate a mbuf for master to core communication\n");
1030                         return;
1031                 }
1032                 int dpdk_port = prox_port_cfg[dpdk_vdev_port].dpdk_mapping;
1033                 tx_ring_route(tbase, task->internal_port_table[dpdk_port].ring, (nl_hdr->nlmsg_type == RTM_NEWROUTE), mbufs[0], ip, gw_ip, dst_len);
1034         } else
1035                 plog_info("Received netlink message on unknown interface %s for IP "IPv4_BYTES_FMT"/%d, Gateway  "IPv4_BYTES_FMT"\n", interface_name[0] ? interface_name:"", IP4(ip), dst_len, IP4(gw_ip));
1036         return;
1037 }
1038
1039 static void handle_arp_event(struct task_base *tbase)
1040 {
1041         struct task_master *task = (struct task_master *)tbase;
1042         struct rte_mbuf *mbufs[MAX_RING_BURST];
1043         struct nlmsghdr * nl_hdr;
1044         int fd = task->arp_fds.fd;
1045         int len, ret;
1046         uint32_t ip = 0;
1047         prox_rte_ether_addr mac;
1048         memset(&mac, 0, sizeof(mac));
1049         len = recv(fd, netlink_buf, sizeof(netlink_buf), 0);
1050         if (len < 0) {
1051                 plog_err("Failed to recv from netlink: %d\n", errno);
1052                 return;
1053         }
1054         nl_hdr = (struct nlmsghdr *)netlink_buf;
1055         if (nl_hdr->nlmsg_flags & NLM_F_MULTI) {
1056                 plog_err("Unexpected multipart netlink message\n");
1057                 return;
1058         }
1059         if ((nl_hdr->nlmsg_type != RTM_NEWNEIGH) && (nl_hdr->nlmsg_type != RTM_DELNEIGH))
1060                 return;
1061
1062         struct ndmsg *ndmsg = (struct ndmsg *)NLMSG_DATA(nl_hdr);
1063         int ndm_family = ndmsg->ndm_family;
1064         struct rtattr *rta = (struct rtattr *)RTM_RTA(ndmsg);
1065         int rtl = RTM_PAYLOAD(nl_hdr);
1066         for (; RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
1067                 switch (rta->rta_type) {
1068                 case NDA_DST:
1069                         ip = *((uint32_t *)RTA_DATA(rta));
1070                         break;
1071                 case NDA_LLADDR:
1072                         mac = *((prox_rte_ether_addr *)(uint64_t *)RTA_DATA(rta));
1073                         break;
1074                 default:
1075                         break;
1076                 }
1077         }
1078         plogx_info("Received netlink ip "IPv4_BYTES_FMT" with mac "MAC_BYTES_FMT"\n", IP4(ip), MAC_BYTES(mac.addr_bytes));
1079         ret = rte_hash_lookup(task->external_ip_hash, (const void *)&ip);
1080         if (unlikely(ret < 0)) {
1081                 // entry not found for this IP: we did not ask a request.
1082                 // This can happen if the kernel updated the ARP table when receiving an ARP_REQUEST
1083                 // We must record this, as the ARP entry is now in the kernel table
1084                 if (prox_rte_is_zero_ether_addr(&mac)) {
1085                         // Timeout or MAC deleted from kernel MAC table
1086                         int ret = rte_hash_del_key(task->external_ip_hash, (const void *)&ip);
1087                         plogx_dbg("ip "IPv4_BYTES_FMT" removed from external_ip_hash\n", IP4(ip));
1088                         return;
1089                 }
1090                 int ret = rte_hash_add_key(task->external_ip_hash, (const void *)&ip);
1091                 if (unlikely(ret < 0)) {
1092                         plogx_dbg("IP "IPv4_BYTES_FMT" not found in external_ip_hash and unable to add it\n", IP4(ip));
1093                         return;
1094                 }
1095                 memcpy(&task->external_ip_table[ret].mac, &mac, sizeof(prox_rte_ether_addr));
1096                 plogx_dbg("ip "IPv4_BYTES_FMT" added in external_ip_hash with mac "MAC_BYTES_FMT"\n", IP4(ip), MAC_BYTES(mac.addr_bytes));
1097                 return;
1098         }
1099
1100         // entry found for this IP
1101         uint16_t nb_requests = task->external_ip_table[ret].nb_requests;
1102         if (nb_requests == 0) {
1103                 return;
1104         }
1105
1106         memcpy(&task->external_ip_table[ret].mac, &mac, sizeof(prox_rte_ether_addr));
1107
1108         // If we receive a request from multiple task for the same IP, then we update all tasks
1109         int ret1 = rte_mempool_get(tbase->l3.arp_nd_pool, (void **)mbufs);
1110         if (unlikely(ret1 != 0)) {
1111                 plog_err("Unable to allocate a mbuf for master to core communication\n");
1112                 return;
1113         }
1114         rte_mbuf_refcnt_set(mbufs[0], nb_requests);
1115         for (int i = 0; i < nb_requests; i++) {
1116                 struct rte_ring *ring = task->external_ip_table[ret].rings[i];
1117                 struct ether_hdr_arp *hdr = rte_pktmbuf_mtod(mbufs[0], struct ether_hdr_arp *);
1118                 memcpy(&hdr->arp.data.sha, &mac, sizeof(prox_rte_ether_addr));
1119                 tx_ring_ip(tbase, ring, MAC_INFO_FROM_MASTER, mbufs[0], ip);
1120                 plog_dbg("MAC_INFO_FROM_MASTER ip "IPv4_BYTES_FMT" with mac "MAC_BYTES_FMT"\n", IP4(ip), MAC_BYTES(mac.addr_bytes));
1121         }
1122         task->external_ip_table[ret].nb_requests = 0;
1123         return;
1124 }
1125
1126 static int handle_ctrl_plane_f(struct task_base *tbase, __attribute__((unused)) struct rte_mbuf **mbuf, uint16_t n_pkts)
1127 {
1128         int ring_id = 0, j, ret = 0, n = 0;
1129         struct rte_mbuf *mbufs[MAX_RING_BURST];
1130         struct task_master *task = (struct task_master *)tbase;
1131
1132         /*      Handle_master works differently than other handle functions
1133                 It is not handled by a DPDK dataplane core
1134                 It is no thread_generic based, hence do not receive packets the same way
1135         */
1136
1137         ret = ring_deq(task->ctrl_rx_ring, mbufs);
1138         for (j = 0; j < ret; j++) {
1139                 handle_message(tbase, mbufs[j], ring_id);
1140         }
1141         for (int vdev_id = 0; vdev_id < task->max_vdev_id; vdev_id++) {
1142                 struct vdev *vdev = &task->all_vdev[vdev_id];
1143                 n = rte_eth_rx_burst(vdev->port_id, 0, mbufs, MAX_PKT_BURST);
1144                 for (j = 0; j < n; j++) {
1145                         tx_ring(tbase, vdev->ring, PKT_FROM_TAP, mbufs[j]);
1146                 }
1147                 ret +=n;
1148         }
1149         if ((task->max_vdev_id) && (poll(&task->arp_fds, 1, prox_cfg.poll_timeout) == POLL_IN)) {
1150                 handle_arp_event(tbase);
1151         }
1152         if (poll(&task->route_fds, 1, prox_cfg.poll_timeout) == POLL_IN) {
1153                 handle_route_event(tbase);
1154         }
1155         return ret;
1156 }
1157
1158 static void init_task_master(struct task_base *tbase, struct task_args *targs)
1159 {
1160         if (prox_cfg.flags & DSF_CTRL_PLANE_ENABLED) {
1161                 struct task_master *task = (struct task_master *)tbase;
1162
1163                 task->ctrl_rx_ring = targs->lconf->ctrl_rings_p[0];
1164                 task->ctrl_tx_rings = ctrl_rings;
1165                 init_ctrl_plane(tbase);
1166                 handle_ctrl_plane = handle_ctrl_plane_f;
1167         }
1168 }
1169
1170 static struct task_init task_init_master = {
1171         .mode_str = "master",
1172         .init = init_task_master,
1173         .handle = NULL,
1174         .flag_features = TASK_FEATURE_NEVER_DISCARDS,
1175         .size = sizeof(struct task_master)
1176 };
1177
1178 __attribute__((constructor)) static void reg_task_gen(void)
1179 {
1180         reg_task(&task_init_master);
1181 }