summaryrefslogtreecommitdiffstats
path: root/VNFs/DPPD-PROX/handle_master.c
diff options
context:
space:
mode:
authorPatrice Buriez <patrice.buriez@intel.com>2017-10-25 20:30:34 +0200
committerPatrice Buriez <patrice.buriez@intel.com>2017-10-25 20:30:34 +0200
commitf6abc2e6a02557e82ad0d1e5440653bb8884ecc8 (patch)
treeae36de03e9553cd55300771271576369c7484f9e /VNFs/DPPD-PROX/handle_master.c
parent504e70cbb19a3e65b1704ee085cd079d26cf16f8 (diff)
Merge changes from PROX-v041
Change-Id: Ie6d4e7ce22c27967117a446626f5923643397812 Signed-off-by: Patrice Buriez <patrice.buriez@intel.com>
Diffstat (limited to 'VNFs/DPPD-PROX/handle_master.c')
-rw-r--r--VNFs/DPPD-PROX/handle_master.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/VNFs/DPPD-PROX/handle_master.c b/VNFs/DPPD-PROX/handle_master.c
new file mode 100644
index 00000000..6bd4ea2c
--- /dev/null
+++ b/VNFs/DPPD-PROX/handle_master.c
@@ -0,0 +1,348 @@
+/*
+// Copyright (c) 2010-2017 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <rte_hash.h>
+#include <rte_hash_crc.h>
+#include "prox_cfg.h"
+
+#include "prox_globals.h"
+#include "rx_pkt.h"
+#include "arp.h"
+#include "handle_master.h"
+#include "log.h"
+#include "mbuf_utils.h"
+#include "etypes.h"
+#include "defaults.h"
+#include "prox_cfg.h"
+#include "prox_malloc.h"
+#include "quit.h"
+#include "task_init.h"
+#include "prox_port_cfg.h"
+#include "main.h"
+#include "lconf.h"
+#include "input.h"
+#include "tx_pkt.h"
+
+#define IP4(x) x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, x >> 24
+
+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"};
+
+static struct my_arp_t arp_reply = {
+ .htype = 0x100,
+ .ptype = 8,
+ .hlen = 6,
+ .plen = 4,
+ .oper = 0x200
+};
+static struct my_arp_t arp_request = {
+ .htype = 0x100,
+ .ptype = 8,
+ .hlen = 6,
+ .plen = 4,
+ .oper = 0x100
+};
+
+struct ip_table {
+ struct ether_addr mac;
+ struct rte_ring *ring;
+};
+
+struct port_table {
+ struct ether_addr mac;
+ struct rte_ring *ring;
+ uint32_t ip;
+ uint8_t port;
+ uint8_t flags;
+};
+
+struct task_master {
+ struct task_base base;
+ struct rte_ring *ctrl_rx_ring;
+ struct rte_ring **ctrl_tx_rings;
+ struct ip_table *internal_ip_table;
+ struct ip_table *external_ip_table;
+ struct rte_hash *external_ip_hash;
+ struct rte_hash *internal_ip_hash;
+ struct port_table internal_port_table[PROX_MAX_PORTS];
+};
+
+struct ip_port {
+ uint32_t ip;
+ uint8_t port;
+} __attribute__((packed));
+
+static inline uint8_t get_command(struct rte_mbuf *mbuf)
+{
+ return mbuf->udata64 & 0xFF;
+}
+static inline uint8_t get_task(struct rte_mbuf *mbuf)
+{
+ return (mbuf->udata64 >> 8) & 0xFF;
+}
+static inline uint8_t get_core(struct rte_mbuf *mbuf)
+{
+ return (mbuf->udata64 >> 16) & 0xFF;
+}
+static inline uint8_t get_port(struct rte_mbuf *mbuf)
+{
+ return mbuf->port;
+}
+static inline uint32_t get_ip(struct rte_mbuf *mbuf)
+{
+ return (mbuf->udata64 >> 32) & 0xFFFFFFFF;
+}
+
+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 %x.%x.%x.%x 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 %x, port %d\n", ip, port_id);
+ return;
+ }
+
+ /* TODO - stoe multiple rings if multiple cores able to handle IP
+ Remove them when such cores are stopped and de-register IP
+ */
+ task->internal_port_table[port_id].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
+ memcpy(&task->internal_port_table[port_id].mac, &prox_port_cfg[port_id].eth_addr, 6);
+ task->internal_port_table[port_id].ip = ip;
+
+ if (ip == RANDOM_IP) {
+ task->internal_port_table[port_id].flags |= HANDLE_RANDOM_IP_FLAG;
+ return;
+ }
+
+ key.ip = ip;
+ key.port = port_id;
+ int ret = rte_hash_add_key(task->internal_ip_hash, (const void *)&key);
+ if (unlikely(ret < 0)) {
+ plog_err("Unable to register ip %x\n", ip);
+ return;
+ }
+ memcpy(&task->internal_ip_table[ret].mac, &prox_port_cfg[port_id].eth_addr, 6);
+ task->internal_ip_table[ret].ring = task->ctrl_tx_rings[core_id * MAX_TASKS_PER_CORE + task_id];
+
+}
+
+static inline void handle_arp_reply(struct task_base *tbase, struct rte_mbuf *mbuf)
+{
+ struct task_master *task = (struct task_master *)tbase;
+ struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
+ int i, ret;
+ uint32_t key = hdr_arp->arp.data.spa;
+ plogx_dbg("\tMaster handling ARP reply for ip %x\n", key);
+
+ ret = rte_hash_lookup(task->external_ip_hash, (const void *)&key);
+ if (unlikely(ret < 0)) {
+ // entry not found for this IP: we did not ask a request, delete the reply
+ tx_drop(mbuf);
+ } else {
+ // entry found for this IP
+ struct rte_ring *ring = task->external_ip_table[ret].ring;
+ memcpy(&hdr_arp->ether_hdr.d_addr.addr_bytes, &task->external_ip_table[ret].mac, 6);
+ tx_ring_ip(tbase, ring, UPDATE_FROM_CTRL, mbuf, key);
+ }
+}
+
+static inline void handle_arp_request(struct task_base *tbase, struct rte_mbuf *mbuf)
+{
+ struct task_master *task = (struct task_master *)tbase;
+ struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
+ int i, ret;
+ uint8_t port = get_port(mbuf);
+
+ struct ip_port key;
+ key.ip = hdr_arp->arp.data.tpa;
+ key.port = port;
+ if (task->internal_port_table[port].flags & HANDLE_RANDOM_IP_FLAG) {
+ struct ether_addr mac;
+ plogx_dbg("\tMaster handling ARP request for ip %x on port %d which supports random ip\n", key.ip, key.port);
+ struct rte_ring *ring = task->internal_port_table[port].ring;
+ create_mac(hdr_arp, &mac);
+ mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);
+ build_arp_reply(hdr_arp, &mac);
+ tx_ring(tbase, ring, ARP_REPLY_FROM_CTRL, mbuf);
+ return;
+ }
+
+ plogx_dbg("\tMaster handling ARP request for ip %x\n", key.ip);
+
+ ret = rte_hash_lookup(task->internal_ip_hash, (const void *)&key);
+ if (unlikely(ret < 0)) {
+ // entry not found for this IP.
+ plogx_dbg("Master ignoring ARP REQUEST received on un-registered IP %d.%d.%d.%d on port %d\n", IP4(hdr_arp->arp.data.tpa), port);
+ tx_drop(mbuf);
+ } else {
+ struct rte_ring *ring = task->internal_ip_table[ret].ring;
+ mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);
+ build_arp_reply(hdr_arp, &task->internal_ip_table[ret].mac);
+ tx_ring(tbase, ring, ARP_REPLY_FROM_CTRL, mbuf);
+ }
+}
+
+static inline void handle_unknown_ip(struct task_base *tbase, struct rte_mbuf *mbuf)
+{
+ struct task_master *task = (struct task_master *)tbase;
+ struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
+ uint8_t port = get_port(mbuf);
+ uint32_t ip_dst = get_ip(mbuf);
+ int ret1, ret2;
+
+ plogx_dbg("\tMaster handling unknown ip %x for port %d\n", ip_dst, port);
+ if (unlikely(port >= PROX_MAX_PORTS)) {
+ plogx_dbg("Port %d not found", port);
+ tx_drop(mbuf);
+ return;
+ }
+ uint32_t ip_src = task->internal_port_table[port].ip;
+ struct rte_ring *ring = task->ctrl_tx_rings[get_core(mbuf) * MAX_TASKS_PER_CORE + get_task(mbuf)];
+
+ if (ring == NULL) {
+ plogx_dbg("Port %d not registered", port);
+ tx_drop(mbuf);
+ return;
+ }
+
+ ret2 = rte_hash_add_key(task->external_ip_hash, (const void *)&ip_dst);
+ if (unlikely(ret2 < 0)) {
+ // entry not found for this IP: delete the reply
+ plogx_dbg("Unable to add IP %x in external_ip_hash\n", rte_be_to_cpu_32(hdr_arp->arp.data.tpa));
+ tx_drop(mbuf);
+ return;
+ }
+ task->external_ip_table[ret2].ring = ring;
+ memcpy(&task->external_ip_table[ret2].mac, &task->internal_port_table[port].mac, 6);
+
+ mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);
+ build_arp_request(mbuf, &task->internal_port_table[port].mac, ip_dst, ip_src);
+ tx_ring(tbase, ring, ARP_REQ_FROM_CTRL, mbuf);
+}
+
+static inline void handle_message(struct task_base *tbase, struct rte_mbuf *mbuf, int ring_id)
+{
+ struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
+ int command = get_command(mbuf);
+ uint32_t ip;
+ plogx_dbg("\tMaster received %s (%x) from mbuf %p\n", actions_string[command], command, mbuf);
+
+ switch(command) {
+ case ARP_TO_CTRL:
+ 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);
+ return;
+ } else if (arp_is_gratuitous(hdr_arp)) {
+ plog_info("\tReceived gratuitous packet \n");
+ tx_drop(mbuf);
+ return;
+ } else if (memcmp(&hdr_arp->arp, &arp_reply, 8) == 0) {
+ uint32_t ip = hdr_arp->arp.data.spa;
+ handle_arp_reply(tbase, mbuf);
+ } else if (memcmp(&hdr_arp->arp, &arp_request, 8) == 0) {
+ handle_arp_request(tbase, mbuf);
+ } else {
+ plog_info("\tReceived unexpected ARP operation %d\n", hdr_arp->arp.oper);
+ tx_drop(mbuf);
+ return;
+ }
+ break;
+ case REQ_MAC_TO_CTRL:
+ handle_unknown_ip(tbase, mbuf);
+ break;
+ default:
+ plogx_dbg("\tMaster received unexpected message\n");
+ tx_drop(mbuf);
+ break;
+ }
+}
+
+void init_ctrl_plane(struct task_base *tbase)
+{
+ prox_cfg.flags |= DSF_CTRL_PLANE_ENABLED;
+ struct task_master *task = (struct task_master *)tbase;
+ int socket = rte_lcore_to_socket_id(prox_cfg.master);
+ uint32_t n_entries = MAX_ARP_ENTRIES * 4;
+ static char hash_name[30];
+ sprintf(hash_name, "A%03d_hash_arp_table", prox_cfg.master);
+ struct rte_hash_parameters hash_params = {
+ .name = hash_name,
+ .entries = n_entries,
+ .key_len = sizeof(uint32_t),
+ .hash_func = rte_hash_crc,
+ .hash_func_init_val = 0,
+ };
+ task->external_ip_hash = rte_hash_create(&hash_params);
+ PROX_PANIC(task->external_ip_hash == NULL, "Failed to set up external ip hash\n");
+ plog_info("\texternal ip hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len);
+ task->external_ip_table = (struct ip_table *)prox_zmalloc(n_entries * sizeof(struct ip_table), socket);
+ PROX_PANIC(task->external_ip_table == NULL, "Failed to allocate memory for %u entries in external ip table\n", n_entries);
+ plog_info("\texternal ip table, with %d entries of size %ld\n", n_entries, sizeof(struct ip_table));
+
+ hash_name[0]++;
+ hash_params.key_len = sizeof(struct ip_port);
+ task->internal_ip_hash = rte_hash_create(&hash_params);
+ PROX_PANIC(task->internal_ip_hash == NULL, "Failed to set up internal ip hash\n");
+ plog_info("\tinternal ip hash table allocated, with %d entries of size %d\n", hash_params.entries, hash_params.key_len);
+ task->internal_ip_table = (struct ip_table *)prox_zmalloc(n_entries * sizeof(struct ip_table), socket);
+ PROX_PANIC(task->internal_ip_table == NULL, "Failed to allocate memory for %u entries in internal ip table\n", n_entries);
+ plog_info("\tinternal ip table, with %d entries of size %ld\n", n_entries, sizeof(struct ip_table));
+}
+
+static int handle_ctrl_plane_f(struct task_base *tbase, __attribute__((unused)) struct rte_mbuf **mbuf, uint16_t n_pkts)
+{
+ int ring_id, j, ret = 0;
+ struct rte_mbuf *mbufs[MAX_RING_BURST];
+ struct task_master *task = (struct task_master *)tbase;
+
+ /* Handle_master works differently than other handle functions
+ It is not handled by a DPDK dataplane core
+ It is no thread_generic based, hence do not receive packets the same way
+ */
+
+ ret = ring_deq(task->ctrl_rx_ring, mbufs);
+ for (j = 0; j < ret; j++) {
+ handle_message(tbase, mbufs[j], ring_id);
+ }
+ return ret;
+}
+
+static void init_task_master(struct task_base *tbase, struct task_args *targs)
+{
+ if (prox_cfg.flags & DSF_CTRL_PLANE_ENABLED) {
+ struct task_master *task = (struct task_master *)tbase;
+
+ task->ctrl_rx_ring = targs->lconf->ctrl_rings_p[0];
+ task->ctrl_tx_rings = ctrl_rings;
+ init_ctrl_plane(tbase);
+ handle_ctrl_plane = handle_ctrl_plane_f;
+ }
+}
+
+static struct task_init task_init_master = {
+ .mode_str = "master",
+ .init = init_task_master,
+ .handle = NULL,
+ .flag_features = TASK_FEATURE_NEVER_DISCARDS,
+ .size = sizeof(struct task_master)
+};
+
+__attribute__((constructor)) static void reg_task_gen(void)
+{
+ reg_task(&task_init_master);
+}