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