2 // Copyright (c) 2010-2020 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <linux/netlink.h>
21 #include <linux/rtnetlink.h>
25 #include <rte_hash_crc.h>
26 #include <rte_ether.h>
30 #include "prox_globals.h"
33 #include "handle_master.h"
35 #include "mbuf_utils.h"
38 #include "prox_malloc.h"
40 #include "task_init.h"
41 #include "prox_port_cfg.h"
47 #include "prox_ipv6.h"
48 #include "packet_utils.h"
50 #define PROX_MAX_ARP_REQUESTS 32 // Maximum number of tasks requesting the same MAC address
51 #define NETLINK_BUF_SIZE 16384
53 static char netlink_buf[NETLINK_BUF_SIZE];
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
76 static struct my_arp_t arp_reply = {
83 static struct my_arp_t arp_request = {
94 } __attribute__((packed));
99 } __attribute__((packed));
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)
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);
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)
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);
115 plogx_dbg("\tregistering node with port %d core %d and task %d\n", port_id, core_id, task_id);
117 if (port_id >= PROX_MAX_PORTS) {
118 plog_err("Unable to register router, port %d\n", port_id);
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;
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;
134 memcpy(&key.ip6, local_ipv6_addr, sizeof(struct ipv6_addr));
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));
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));
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];
151 void master_init_vdev(struct task_base *tbase, uint8_t port_id, uint8_t core_id, uint8_t task_id)
153 struct task_master *task = (struct task_master *)tbase;
154 uint8_t vdev_port = prox_port_cfg[port_id].dpdk_mapping;
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)
161 if (i < task->max_vdev_id) {
162 // Already initialized (e.g. by another core handling the same port).
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];
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);
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)
187 struct task_master *task = (struct task_master *)tbase;
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);
191 if (port_id >= PROX_MAX_PORTS) {
192 plog_err("Unable to register ip "IPv4_BYTES_FMT", port %d\n", IP4(ip), port_id);
196 /* TODO - store multiple rings if multiple cores able to handle IP
197 Remove them when such cores are stopped and de-register IP
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;
203 if (ip == RANDOM_IP) {
204 task->internal_port_table[port_id].flags |= HANDLE_RANDOM_IP_FLAG;
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));
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];
219 static inline void handle_arp_reply(struct task_base *tbase, struct rte_mbuf *mbuf, struct my_arp_t *arp)
221 struct task_master *task = (struct task_master *)tbase;
223 uint32_t key = arp->data.spa;
224 plogx_dbg("\tMaster handling ARP reply for ip "IPv4_BYTES_FMT"\n", IP4(key));
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
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);
240 task->external_ip_table[ret].nb_requests = 0;
247 static inline void handle_arp_request(struct task_base *tbase, struct rte_mbuf *mbuf, struct my_arp_t *arp)
249 struct task_master *task = (struct task_master *)tbase;
250 prox_rte_ether_hdr *ether_hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
252 uint8_t port = get_port(mbuf);
255 key.ip = arp->data.tpa;
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);
268 plogx_dbg("\tMaster handling ARP request for ip "IPv4_BYTES_FMT"\n", IP4(key.ip));
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);
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);
283 static inline int record_request(struct task_base *tbase, uint32_t ip_dst, uint8_t port, struct rte_ring *ring)
285 struct task_master *task = (struct task_master *)tbase;
286 int ret = rte_hash_add_key(task->external_ip_hash, (const void *)&ip_dst);
289 if (unlikely(ret < 0)) {
290 plogx_dbg("Unable to add IP "IPv4_BYTES_FMT" in external_ip_hash\n", IP4(ip_dst));
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));
302 for (i = 0; i < task->external_ip_table[ret].nb_requests; i++) {
303 if (task->external_ip_table[ret].rings[i] == ring)
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++;
314 static inline void handle_unknown_ip(struct task_base *tbase, struct rte_mbuf *mbuf)
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);
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);
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)];
332 plogx_dbg("Port %d not registered", port);
337 if (record_request(tbase, ip_dst, port, ring) < 0) {
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);
347 static inline void build_icmp_reply_message(struct task_base *tbase, struct rte_mbuf *mbuf)
349 struct task_master *task = (struct task_master *)tbase;
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;
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);
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);
376 static inline void handle_icmp(struct task_base *tbase, struct rte_mbuf *mbuf)
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) {
386 prox_rte_ipv4_hdr *ip_hdr = (prox_rte_ipv4_hdr *)(hdr + 1);
387 if (ip_hdr->next_proto_id != IPPROTO_ICMP) {
391 if (ip_hdr->dst_addr != port->ip) {
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) {
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();
405 return build_icmp_reply_message(tbase, mbuf);
406 } else if (type == PROX_RTE_IP_ICMP_ECHO_REPLY) {
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();
418 static inline void handle_unknown_ip6(struct task_base *tbase, struct rte_mbuf *mbuf)
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);
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);
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;
441 plogx_dbg("Unable to find a src ip for dst ip "IPv6_BYTES_FMT"\n", IPv6_BYTES(ip_dst->bytes));
445 struct rte_ring *ring = task->ctrl_tx_rings[get_core(mbuf) * MAX_TASKS_PER_CORE + get_task(mbuf)];
448 plogx_dbg("Port %d not registered", port);
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));
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));
469 for (i = 0; i < task->external_ip6_table[ret2].nb_requests; i++) {
470 if (task->external_ip6_table[ret2].rings[i] == ring)
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));
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);
488 static inline void handle_rs(struct task_base *tbase, struct rte_mbuf *mbuf, prox_rte_ipv6_hdr *ipv6_hdr, uint16_t vlan)
490 struct task_master *task = (struct task_master *)tbase;
492 uint8_t port = get_port(mbuf);
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);
503 static inline void handle_ra(struct task_base *tbase, struct rte_mbuf *mbuf, prox_rte_ipv6_hdr *ipv6_hdr, uint16_t vlan)
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;
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));
517 plog_info("TX side not initialized yet => dropping\n");
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;
528 case ICMPv6_source_link_layer_address:
529 plog_dbg("\tOption %d = Source Link Layer Address\n", type);
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));
537 plog_dbg("\tOption %d = MTU\n", type);
540 plog_dbg("\tOption %d = Unknown Option\n", type);
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);
548 option_len -=option->length * 8;
549 option = (struct icmpv6_option *)(((uint8_t *)option) + option->length * 8);
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);
560 static inline void handle_ns(struct task_base *tbase, struct rte_mbuf *mbuf, prox_rte_ipv6_hdr *ipv6_hdr, uint16_t vlan)
562 struct task_master *task = (struct task_master *)tbase;
563 struct icmpv6_NS *neighbour_sollicitation = (struct icmpv6_NS *)(ipv6_hdr + 1);
565 uint8_t port = get_port(mbuf);
566 struct rte_ring *ring = task->internal_port_table[port].ring;
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));
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;
579 case ICMPv6_source_link_layer_address:
580 plog_dbg("Option %d = Source Link Layer Address\n", type);
583 plog_dbg("Option %d = Unknown Option\n", type);
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);
591 option_len -=option->length * 8;
592 option = (struct icmpv6_option *)(((uint8_t *)option) + option->length * 8);
595 memcpy(&key.ip6, &neighbour_sollicitation->target_address, sizeof(struct ipv6_addr));
598 if (memcmp(&neighbour_sollicitation->target_address, &task->internal_port_table[port].local_ipv6_addr, 8) == 0) {
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);
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);
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);
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);
633 static inline void handle_na(struct task_base *tbase, struct rte_mbuf *mbuf, prox_rte_ipv6_hdr *ipv6_hdr, uint16_t vlan)
635 struct task_master *task = (struct task_master *)tbase;
636 struct icmpv6_NA *neighbour_advertisement = (struct icmpv6_NA *)(ipv6_hdr + 1);
638 uint8_t port = get_port(mbuf);
639 struct rte_ring *ring = task->internal_port_table[port].ring;
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));
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;
653 case ICMPv6_source_link_layer_address:
654 plog_dbg("Option %d = Source Link Layer Address\n", type);
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);
661 target_address = option->data;
662 plog_dbg("Option %d = Target Link Layer Address = "MAC_BYTES_FMT"\n", type, MAC_BYTES(target_address));
665 plog_dbg("Option %d = Unknown Option\n", type);
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);
673 option_len -=option->length * 8;
674 option = (struct icmpv6_option *)(((uint8_t *)option) + option->length * 8);
677 if (target_address == NULL) {
680 struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
681 struct ipv6_addr *key = &neighbour_advertisement->destination_address;
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
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);
698 task->external_ip6_table[ret].nb_requests = 0;
705 static inline void handle_message(struct task_base *tbase, struct rte_mbuf *mbuf, int ring_id)
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);
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;
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);
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);
737 handle_icmp(tbase, mbuf);
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);
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;
754 arp = (struct my_arp_t *)(ether_hdr + 1);
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);
762 if (arp_is_gratuitous(arp)) {
763 plog_info("\tReceived gratuitous packet \n");
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);
772 plog_info("\tReceived unexpected ARP operation %d\n", arp->oper);
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
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)];
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);
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);
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)
814 if (vlan_id >= prox_port_cfg[vdev_port].n_vlans) {
816 plogx_info("\tDid not send to TAP IP "IPv4_BYTES_FMT" as wrong VLAN %d\n", IPv4_BYTES(((uint8_t*)&ip)), vlan);
820 int n = sendto(prox_port_cfg[vdev_port].fds[vlan_id], (char*)(&ip), 0, MSG_DONTROUTE, (struct sockaddr *)&dst, sizeof(struct sockaddr_in));
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));
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]);
826 record_request(tbase, ip, port, ring);
830 handle_unknown_ip(tbase, mbuf);
832 case IP6_REQ_MAC_TO_MASTER:
833 handle_unknown_ip6(tbase, mbuf);
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))) {
841 plog_err("\tUnexpected message received: NDP_PKT_FROM_NET_TO_MASTER with ether_type %x\n", ether_hdr->ether_type);
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);
847 icmpv6 = (struct icmpv6 *)(ipv6_hdr + 1);
848 switch (icmpv6->type) {
850 plog_err("IPV6 ICMPV6 Destination Unreachable\n");
854 plog_err("IPV6 ICMPV6 packet too big\n");
858 plog_err("IPV6 ICMPV6 Time Exceeded\n");
862 plog_err("IPV6 ICMPV6 Parameter Problem\n");
866 handle_rs(tbase, mbuf, ipv6_hdr, vlan);
869 handle_ra(tbase, mbuf, ipv6_hdr, vlan);
872 handle_ns(tbase, mbuf, ipv6_hdr, vlan);
875 handle_na(tbase, mbuf, ipv6_hdr, vlan);
878 plog_err("IPV6 ICMPV6 Redirect not handled\n");
882 plog_err("Unexpected type %d in IPV6 ICMPV6\n", icmpv6->type);
888 plogx_dbg("\tMaster received unexpected message\n");
894 void init_ctrl_plane(struct task_base *tbase)
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];
901 sprintf(hash_name, "A%03d_hash_arp_table", prox_cfg.master);
902 struct rte_hash_parameters hash_params = {
904 .entries = n_entries,
905 .hash_func = rte_hash_crc,
906 .hash_func_init_val = 0,
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);
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));
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);
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));
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);
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));
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);
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));
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);
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);
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_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);
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,
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;
993 static void handle_route_event(struct task_base *tbase)
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;
1002 plog_err("Failed to recv from netlink: %d\n", errno);
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");
1010 if ((nl_hdr->nlmsg_type != RTM_NEWROUTE) && (nl_hdr->nlmsg_type != RTM_DELROUTE))
1013 struct rtmsg *rtmsg = (struct rtmsg *)NLMSG_DATA(nl_hdr);
1014 int rtm_family = rtmsg->rtm_family;
1015 if (rtm_family != AF_INET) {
1016 plog_warn("Unhandled non IPV4 routing message\n");
1019 if ((rtmsg->rtm_table != RT_TABLE_MAIN) && (rtmsg->rtm_table != RT_TABLE_LOCAL))
1021 int dst_len = rtmsg->rtm_dst_len;
1023 struct rtattr *rta = (struct rtattr *)RTM_RTA(rtmsg);
1024 int rtl = RTM_PAYLOAD(nl_hdr);
1025 for (; RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
1026 switch (rta->rta_type) {
1028 ip = *((uint32_t *)RTA_DATA(rta));
1031 interface_index = *((int *)RTA_DATA(rta));
1032 if (if_indextoname(interface_index, interface_name) == NULL) {
1033 plog_info("Unknown Interface Index %d\n", interface_index);
1037 mask = *((int *)RTA_DATA(rta));
1040 gw_ip = *((uint32_t *)RTA_DATA(rta));
1046 int dpdk_vdev_port = -1;
1047 for (int i = 0; i< prox_rte_eth_dev_count_avail(); i++) {
1048 for (int vlan_id = 0; vlan_id < prox_port_cfg[i].n_vlans; vlan_id++) {
1049 if (strcmp(prox_port_cfg[i].names[vlan_id], interface_name) == 0) {
1054 if (dpdk_vdev_port != -1)
1057 if (dpdk_vdev_port != -1) {
1058 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));
1059 int ret1 = rte_mempool_get(tbase->l3.arp_nd_pool, (void **)mbufs);
1060 if (unlikely(ret1 != 0)) {
1061 plog_err("Unable to allocate a mbuf for master to core communication\n");
1064 int dpdk_port = prox_port_cfg[dpdk_vdev_port].dpdk_mapping;
1065 tx_ring_route(tbase, task->internal_port_table[dpdk_port].ring, (nl_hdr->nlmsg_type == RTM_NEWROUTE), mbufs[0], ip, gw_ip, dst_len);
1067 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));
1071 static void handle_arp_event(struct task_base *tbase)
1073 struct task_master *task = (struct task_master *)tbase;
1074 struct rte_mbuf *mbufs[MAX_RING_BURST];
1075 struct nlmsghdr * nl_hdr;
1076 int fd = task->arp_fds.fd;
1079 prox_rte_ether_addr mac;
1080 memset(&mac, 0, sizeof(mac));
1081 len = recv(fd, netlink_buf, sizeof(netlink_buf), 0);
1083 plog_err("Failed to recv from netlink: %d\n", errno);
1086 nl_hdr = (struct nlmsghdr *)netlink_buf;
1087 if (nl_hdr->nlmsg_flags & NLM_F_MULTI) {
1088 plog_err("Unexpected multipart netlink message\n");
1091 if ((nl_hdr->nlmsg_type != RTM_NEWNEIGH) && (nl_hdr->nlmsg_type != RTM_DELNEIGH))
1094 struct ndmsg *ndmsg = (struct ndmsg *)NLMSG_DATA(nl_hdr);
1095 int ndm_family = ndmsg->ndm_family;
1096 struct rtattr *rta = (struct rtattr *)RTM_RTA(ndmsg);
1097 int rtl = RTM_PAYLOAD(nl_hdr);
1098 for (; RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
1099 switch (rta->rta_type) {
1101 ip = *((uint32_t *)RTA_DATA(rta));
1104 mac = *((prox_rte_ether_addr *)(uint64_t *)RTA_DATA(rta));
1110 plogx_info("Received netlink ip "IPv4_BYTES_FMT" with mac "MAC_BYTES_FMT"\n", IP4(ip), MAC_BYTES(mac.addr_bytes));
1111 ret = rte_hash_lookup(task->external_ip_hash, (const void *)&ip);
1112 if (unlikely(ret < 0)) {
1113 // entry not found for this IP: we did not ask a request.
1114 // This can happen if the kernel updated the ARP table when receiving an ARP_REQUEST
1115 // We must record this, as the ARP entry is now in the kernel table
1116 if (prox_rte_is_zero_ether_addr(&mac)) {
1117 // Timeout or MAC deleted from kernel MAC table
1118 int ret = rte_hash_del_key(task->external_ip_hash, (const void *)&ip);
1119 plogx_dbg("ip "IPv4_BYTES_FMT" removed from external_ip_hash\n", IP4(ip));
1122 int ret = rte_hash_add_key(task->external_ip_hash, (const void *)&ip);
1123 if (unlikely(ret < 0)) {
1124 plogx_dbg("IP "IPv4_BYTES_FMT" not found in external_ip_hash and unable to add it\n", IP4(ip));
1127 memcpy(&task->external_ip_table[ret].mac, &mac, sizeof(prox_rte_ether_addr));
1128 plogx_dbg("ip "IPv4_BYTES_FMT" added in external_ip_hash with mac "MAC_BYTES_FMT"\n", IP4(ip), MAC_BYTES(mac.addr_bytes));
1132 // entry found for this IP
1133 uint16_t nb_requests = task->external_ip_table[ret].nb_requests;
1134 if (nb_requests == 0) {
1138 memcpy(&task->external_ip_table[ret].mac, &mac, sizeof(prox_rte_ether_addr));
1140 // If we receive a request from multiple task for the same IP, then we update all tasks
1141 int ret1 = rte_mempool_get(tbase->l3.arp_nd_pool, (void **)mbufs);
1142 if (unlikely(ret1 != 0)) {
1143 plog_err("Unable to allocate a mbuf for master to core communication\n");
1146 rte_mbuf_refcnt_set(mbufs[0], nb_requests);
1147 for (int i = 0; i < nb_requests; i++) {
1148 struct rte_ring *ring = task->external_ip_table[ret].rings[i];
1149 struct ether_hdr_arp *hdr = rte_pktmbuf_mtod(mbufs[0], struct ether_hdr_arp *);
1150 memcpy(&hdr->arp.data.sha, &mac, sizeof(prox_rte_ether_addr));
1151 tx_ring_ip(tbase, ring, MAC_INFO_FROM_MASTER, mbufs[0], ip);
1152 plog_dbg("MAC_INFO_FROM_MASTER ip "IPv4_BYTES_FMT" with mac "MAC_BYTES_FMT"\n", IP4(ip), MAC_BYTES(mac.addr_bytes));
1154 task->external_ip_table[ret].nb_requests = 0;
1158 static int handle_ctrl_plane_f(struct task_base *tbase, __attribute__((unused)) struct rte_mbuf **mbuf, uint16_t n_pkts)
1160 int ring_id = 0, j, ret = 0, n = 0;
1161 struct rte_mbuf *mbufs[MAX_RING_BURST];
1162 struct task_master *task = (struct task_master *)tbase;
1164 /* Handle_master works differently than other handle functions
1165 It is not handled by a DPDK dataplane core
1166 It is no thread_generic based, hence do not receive packets the same way
1169 ret = ring_deq(task->ctrl_rx_ring, mbufs);
1170 for (j = 0; j < ret; j++) {
1171 handle_message(tbase, mbufs[j], ring_id);
1173 for (int vdev_id = 0; vdev_id < task->max_vdev_id; vdev_id++) {
1174 struct vdev *vdev = &task->all_vdev[vdev_id];
1175 n = rte_eth_rx_burst(vdev->port_id, 0, mbufs, MAX_PKT_BURST);
1176 for (j = 0; j < n; j++) {
1177 tx_ring(tbase, vdev->ring, PKT_FROM_TAP, mbufs[j]);
1181 if ((task->max_vdev_id) && (poll(&task->arp_fds, 1, prox_cfg.poll_timeout) == POLL_IN)) {
1182 handle_arp_event(tbase);
1184 if (poll(&task->route_fds, 1, prox_cfg.poll_timeout) == POLL_IN) {
1185 handle_route_event(tbase);
1190 static void init_task_master(struct task_base *tbase, struct task_args *targs)
1192 if (prox_cfg.flags & DSF_CTRL_PLANE_ENABLED) {
1193 struct task_master *task = (struct task_master *)tbase;
1195 task->ctrl_rx_ring = targs->lconf->ctrl_rings_p[0];
1196 task->ctrl_tx_rings = ctrl_rings;
1197 init_ctrl_plane(tbase);
1198 handle_ctrl_plane = handle_ctrl_plane_f;
1202 static struct task_init task_init_master = {
1203 .mode_str = "master",
1204 .init = init_task_master,
1206 .flag_features = TASK_FEATURE_NEVER_DISCARDS,
1207 .size = sizeof(struct task_master)
1210 __attribute__((constructor)) static void reg_task_gen(void)
1212 reg_task(&task_init_master);