summaryrefslogtreecommitdiffstats
path: root/VNFs/DPPD-PROX/handle_master.c
diff options
context:
space:
mode:
authorXavier Simonart <xavier.simonart@intel.com>2020-04-20 23:25:22 +0200
committerXavier Simonart <xavier.simonart@intel.com>2020-05-29 23:28:44 +0200
commitfa869940dd9bb459ac599fe80c26c9d3e720fd31 (patch)
tree67aefe7f36fad283ab690d5d0feae1a547a59487 /VNFs/DPPD-PROX/handle_master.c
parent6f898f1c73d630bf6e5e75ba1b30d261c8301d2a (diff)
Add support for vdev tap devices
This commit adds support for the creation of tap devices. To create a tap device, and associate it with a DPDK port, add within the port section: vdev=<tap_name> local ipv4=<ip_assigned_to_port> <tap_name> will appear as a kernel network device, with an IP <ip_assigned_to_port> ARP packets received from the network on the DPDK interface will be forwarded to the kernel. 1st packet which needs to be generated to a new IP will cause an IP packet to be sent to the kernel (using socket sendto) forcing the kernel to send an ARP_REQUEST. In this commit, there is no notification from the kernel about ARP table changes. This is subject to further commits. Two config files, gen_tap.cfg and swap_tap.cfg have been created. They work one against each other. *** Note however that they do not work if running within the same host (with the port being connected back to back) *** This is due to the fact that the kernel would bypass the ports and use local interface... Change-Id: Iadeec0d99e3c693472ea44bdb9163a3bf97df2fa Signed-off-by: Xavier Simonart <xavier.simonart@intel.com>
Diffstat (limited to 'VNFs/DPPD-PROX/handle_master.c')
-rw-r--r--VNFs/DPPD-PROX/handle_master.c76
1 files changed, 72 insertions, 4 deletions
diff --git a/VNFs/DPPD-PROX/handle_master.c b/VNFs/DPPD-PROX/handle_master.c
index 9a864352..de0c0d51 100644
--- a/VNFs/DPPD-PROX/handle_master.c
+++ b/VNFs/DPPD-PROX/handle_master.c
@@ -1,5 +1,5 @@
/*
-// Copyright (c) 2010-2017 Intel Corporation
+// Copyright (c) 2010-2020 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
// limitations under the License.
*/
+#include <fcntl.h>
+
#include <rte_hash.h>
#include <rte_hash_crc.h>
#include "prox_cfg.h"
@@ -35,10 +37,12 @@
#include "lconf.h"
#include "input.h"
#include "tx_pkt.h"
+#include "defines.h"
#define PROX_MAX_ARP_REQUESTS 32 // Maximum number of tasks requesting the same MAC address
+#define SET_NON_BLOCKING(X) fcntl(X, F_SETFL, fcntl(X, F_GETFL) | O_NONBLOCK);
-const char *actions_string[] = {"UPDATE_FROM_CTRL", "SEND_ARP_REQUEST_FROM_CTRL", "SEND_ARP_REPLY_FROM_CTRL", "HANDLE_ARP_TO_CTRL", "REQ_MAC_TO_CTRL"};
+const char *actions_string[] = {"UPDATE_FROM_CTRL", "SEND_ARP_REQUEST_FROM_CTRL", "SEND_ARP_REPLY_FROM_CTRL", "HANDLE_ARP_TO_CTRL", "REQ_MAC_TO_CTRL", "PKT_FROM_TAP"};
static struct my_arp_t arp_reply = {
.htype = 0x100,
@@ -83,6 +87,8 @@ struct task_master {
struct rte_hash *external_ip_hash;
struct rte_hash *internal_ip_hash;
struct port_table internal_port_table[PROX_MAX_PORTS];
+ struct vdev all_vdev[PROX_MAX_PORTS];
+ int max_vdev_id;
};
struct ip_port {
@@ -111,11 +117,36 @@ static inline uint32_t get_ip(struct rte_mbuf *mbuf)
return (mbuf->udata64 >> 32) & 0xFFFFFFFF;
}
+void master_init_vdev(struct task_base *tbase, uint8_t port_id, uint8_t core_id, uint8_t task_id)
+{
+ struct task_master *task = (struct task_master *)tbase;
+ uint8_t vdev_port = prox_port_cfg[port_id].dpdk_mapping;
+ int rc;
+ if (vdev_port != NO_VDEV_PORT) {
+ task->all_vdev[task->max_vdev_id].port_id = vdev_port;
+ task->all_vdev[task->max_vdev_id].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
+
+ struct sockaddr_in dst, src;
+ src.sin_family = AF_INET;
+ src.sin_addr.s_addr = prox_port_cfg[vdev_port].ip;
+ src.sin_port = 5000;
+
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ PROX_PANIC(fd < 0, "Failed to open socket(AF_INET, SOCK_DGRAM, 0)\n");
+ prox_port_cfg[vdev_port].fd = fd;
+ rc = bind(fd,(struct sockaddr *)&src, sizeof(struct sockaddr_in));
+ PROX_PANIC(rc, "Failed to bind("IPv4_BYTES_FMT":%d): errno = %d\n", IPv4_BYTES(((uint8_t*)&src.sin_addr.s_addr)), src.sin_port, errno);
+ 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);
+ SET_NON_BLOCKING(fd);
+ task->max_vdev_id++;
+ }
+}
+
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)
{
struct task_master *task = (struct task_master *)tbase;
struct ip_port key;
- plogx_dbg("\tregistering IP %d.%d.%d.%d with port %d core %d and task %d\n", IP4(ip), port_id, core_id, task_id);
+ plogx_info("\tregistering IP %d.%d.%d.%d with port %d core %d and task %d\n", IP4(ip), port_id, core_id, task_id);
if (port_id >= PROX_MAX_PORTS) {
plog_err("Unable to register ip %d.%d.%d.%d, port %d\n", IP4(ip), port_id);
@@ -273,13 +304,22 @@ static inline void handle_unknown_ip(struct task_base *tbase, struct rte_mbuf *m
static inline void handle_message(struct task_base *tbase, struct rte_mbuf *mbuf, int ring_id)
{
+ struct task_master *task = (struct task_master *)tbase;
struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
int command = get_command(mbuf);
+ uint8_t port = get_port(mbuf);
uint32_t ip;
+ uint8_t vdev_port = prox_port_cfg[port].dpdk_mapping;
plogx_dbg("\tMaster received %s (%x) from mbuf %p\n", actions_string[command], command, mbuf);
switch(command) {
case ARP_TO_CTRL:
+ if (vdev_port != NO_VDEV_PORT) {
+ // If a virtual (net_tap) device is attached, send the (ARP) packet to this device
+ // The kernel will receive and handle it.
+ int n = rte_eth_tx_burst(prox_port_cfg[port].dpdk_mapping, 0, &mbuf, 1);
+ return;
+ }
if (hdr_arp->ether_hdr.ether_type != ETYPE_ARP) {
tx_drop(mbuf);
plog_err("\tUnexpected message received: ARP_TO_CTRL with ether_type %x\n", hdr_arp->ether_hdr.ether_type);
@@ -300,6 +340,26 @@ static inline void handle_message(struct task_base *tbase, struct rte_mbuf *mbuf
}
break;
case REQ_MAC_TO_CTRL:
+ if (vdev_port != NO_VDEV_PORT) {
+ // We send a packet to the kernel with the proper destnation IP address and our src IP address
+ // This means that if a generator sends packets from many sources all ARP will still
+ // be sent from the same IP src. This might be a limitation.
+ // This prevent to have to open as many sockets as there are sources MAC addresses
+ // We also always use the same UDP ports - as the packet will finally not leave the system anyhow
+ // Content of udp might be garbage - we do not care.
+
+ prox_rte_ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
+ prox_rte_ipv4_hdr *ip_hdr = (prox_rte_ipv4_hdr *)(hdr + 1);
+ prox_rte_udp_hdr *udp = (prox_rte_udp_hdr *)(ip_hdr + 1);
+
+ struct sockaddr_in dst;
+ dst.sin_family = AF_INET;
+ dst.sin_addr.s_addr = ip_hdr->dst_addr;
+ dst.sin_port = 5000;
+ int n = sendto(prox_port_cfg[vdev_port].fd, (char*)(udp + 1), 18, 0, (struct sockaddr *)&dst, sizeof(struct sockaddr_in));
+ plog_dbg("Sent %d bytes to "IPv4_BYTES_FMT" using fd %d\n", n, IPv4_BYTES(((uint8_t*)&ip_hdr->dst_addr)), prox_port_cfg[vdev_port].fd);
+ break;
+ }
handle_unknown_ip(tbase, mbuf);
break;
default:
@@ -343,7 +403,7 @@ void init_ctrl_plane(struct task_base *tbase)
static int handle_ctrl_plane_f(struct task_base *tbase, __attribute__((unused)) struct rte_mbuf **mbuf, uint16_t n_pkts)
{
- int ring_id = 0, j, ret = 0;
+ int ring_id = 0, j, ret = 0, n = 0;
struct rte_mbuf *mbufs[MAX_RING_BURST];
struct task_master *task = (struct task_master *)tbase;
@@ -356,6 +416,14 @@ static int handle_ctrl_plane_f(struct task_base *tbase, __attribute__((unused))
for (j = 0; j < ret; j++) {
handle_message(tbase, mbufs[j], ring_id);
}
+ for (int vdev_id = 0; vdev_id < task->max_vdev_id; vdev_id++) {
+ struct vdev *vdev = &task->all_vdev[vdev_id];
+ n = rte_eth_rx_burst(vdev->port_id, 0, mbufs, MAX_PKT_BURST);
+ for (j = 0; j < n; j++) {
+ tx_ring(tbase, vdev->ring, PKT_FROM_TAP, mbufs[j]);
+ }
+ ret +=n;
+ }
return ret;
}