summaryrefslogtreecommitdiffstats
path: root/VNFs
diff options
context:
space:
mode:
authorXavier Simonart <xavier.simonart@intel.com>2019-06-24 17:01:54 +0200
committerXavier Simonart <xavier.simonart@intel.com>2019-10-09 19:09:34 +0200
commit48f8c3d212644a33dd0abaaa1a0c71d4decaafdf (patch)
tree515043d3dc43025bb5ce5e6cb842afd68ae891e9 /VNFs
parent4cc4dabe80eb7d19c20920b7ec20899d6a76a1dd (diff)
Add support for igmp and multicast
Multicast can be enabled through configuration or through command line - Through configuration Add multicast=mcast_address (e.g. multicast=01:00:5e:01:02:03) in the port section - Through command line run enable multicast port_id mcast_address (e.g. enable multicast 1 01:00:5e:01:02:03) IGMP join message is sent unsollicited through command line: join igmp core_id task_id ip (e.g. join igmp 1 0 224.1.1.3) To enable swap answering IGMP Query (w/ IGMP Join) - Through configuration Add igmp ipv4=ip_address within the core/task section - Through command line join igmp core_id task_id ip (e.g. join igmp 1 0 224.1.1.3) (this will 1st initiate an unsollicated join, then answer any subsequent query) UDP/TCP packets received on a multicast address (224.0.0.0 => 239.255.255.255) are discarded To stop sending responses to IGMP query: leave igmp core_id task_id Change-Id: I3808ccabf3b38b5a1e10e1b044db63aa05bcd7b5 Signed-off-by: Xavier Simonart <xavier.simonart@intel.com>
Diffstat (limited to 'VNFs')
-rw-r--r--VNFs/DPPD-PROX/cmd_parser.c84
-rw-r--r--VNFs/DPPD-PROX/commands.c83
-rw-r--r--VNFs/DPPD-PROX/commands.h2
-rw-r--r--VNFs/DPPD-PROX/config/mcast.cfg108
-rw-r--r--VNFs/DPPD-PROX/defaults.c1
-rw-r--r--VNFs/DPPD-PROX/handle_swap.c204
-rw-r--r--VNFs/DPPD-PROX/handle_swap.h22
-rw-r--r--VNFs/DPPD-PROX/igmp.h59
-rw-r--r--VNFs/DPPD-PROX/prox_args.c17
-rw-r--r--VNFs/DPPD-PROX/prox_cksum.c11
-rw-r--r--VNFs/DPPD-PROX/prox_cksum.h2
-rw-r--r--VNFs/DPPD-PROX/prox_port_cfg.c15
-rw-r--r--VNFs/DPPD-PROX/prox_port_cfg.h3
-rw-r--r--VNFs/DPPD-PROX/task_base.h1
-rw-r--r--VNFs/DPPD-PROX/task_init.h1
15 files changed, 543 insertions, 70 deletions
diff --git a/VNFs/DPPD-PROX/cmd_parser.c b/VNFs/DPPD-PROX/cmd_parser.c
index 79c939b9..d4bfed01 100644
--- a/VNFs/DPPD-PROX/cmd_parser.c
+++ b/VNFs/DPPD-PROX/cmd_parser.c
@@ -53,6 +53,7 @@
#include "handle_impair.h"
#include "rx_pkt.h"
#include "prox_compat.h"
+#include "igmp.h"
static int core_task_is_valid(int lcore_id, int task_id)
{
@@ -1254,6 +1255,31 @@ static int parse_cmd_tot_imissed_tot(const char *str, struct input *input)
return 0;
}
+static int parse_cmd_enable_multicast(const char *str, struct input *input)
+{
+ uint8_t port_id;
+ struct ether_addr mac;
+
+ if (sscanf(str, "%hhu %hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &port_id, mac.addr_bytes, mac.addr_bytes + 1, mac.addr_bytes + 2, mac.addr_bytes + 3, mac.addr_bytes + 4, mac.addr_bytes + 5 ) != 7) {
+ return -1;
+ }
+ cmd_multicast(port_id, 1, &mac);
+ return 0;
+}
+
+static int parse_cmd_disable_multicast(const char *str, struct input *input)
+{
+ uint8_t port_id;
+ struct ether_addr mac;
+
+ if (sscanf(str, "%hhu %hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &port_id, mac.addr_bytes, mac.addr_bytes + 1, mac.addr_bytes + 2, mac.addr_bytes + 3, mac.addr_bytes + 4, mac.addr_bytes + 5 ) != 7) {
+ return -1;
+ }
+
+ cmd_multicast(port_id, 0, &mac);
+ return 0;
+}
+
static int parse_cmd_reset_port(const char *str, struct input *input)
{
uint32_t port_id;
@@ -1987,6 +2013,58 @@ static int parse_cmd_accuracy(const char *str, struct input *input)
return 0;
}
+static int parse_cmd_leave_igmp(const char *str, struct input *input)
+{
+ unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
+
+ if (parse_cores_task(str, lcores, &task_id, &nb_cores))
+ return -1;
+
+ if (cores_task_are_valid(lcores, task_id, nb_cores)) {
+ for (unsigned int i = 0; i < nb_cores; i++) {
+ lcore_id = lcores[i];
+
+ if (!task_is_mode(lcore_id, task_id, "swap")) {
+ plog_err("Core %u task %u is not running swap\n", lcore_id, task_id);
+ }
+ else {
+ struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
+ igmp_leave_group(tbase);
+ }
+ }
+ }
+ return 0;
+}
+
+static int parse_cmd_join_igmp(const char *str, struct input *input)
+{
+ unsigned lcores[RTE_MAX_LCORE], lcore_id, task_id, nb_cores;
+ uint32_t igmp_ip;
+ uint8_t *igmp_bytes = (uint8_t *)&igmp_ip;
+
+ if (parse_cores_task(str, lcores, &task_id, &nb_cores))
+ return -1;
+ if (!(str = strchr_skip_twice(str, ' ')))
+ return -1;
+ if (sscanf(str, "%hhu.%hhu.%hhu.%hhu", igmp_bytes, igmp_bytes + 1, igmp_bytes + 2, igmp_bytes + 3) != 4) {
+ return -1;
+ }
+ if (cores_task_are_valid(lcores, task_id, nb_cores)) {
+ for (unsigned int i = 0; i < nb_cores; i++) {
+ lcore_id = lcores[i];
+
+ if (!task_is_mode(lcore_id, task_id, "swap")) {
+ plog_err("Core %u task %u is not running swap\n", lcore_id, task_id);
+ }
+ else {
+ struct task_base *tbase = lcore_cfg[lcore_id].tasks_all[task_id];
+ igmp_join_group(tbase, igmp_ip);
+ }
+ }
+ }
+ return 0;
+}
+
static int parse_cmd_rx_tx_info(const char *str, struct input *input)
{
if (strcmp(str, "") != 0) {
@@ -2100,7 +2178,9 @@ static struct cmd_str cmd_strings[] = {
{"set cache class", "<core id> <class>", "Set cache class", parse_cmd_set_cache_class},
{"get cache class", "<core id>", "Get cache class", parse_cmd_get_cache_class},
{"get cache mask", "<core id>", "Get cache mask", parse_cmd_get_cache_mask},
- {"reset port", "", "Reset port", parse_cmd_reset_port},
+ {"reset port", "<port id>", "Reset port", parse_cmd_reset_port},
+ {"enable multicast", "<port id> <MAC>", "Enable multicast", parse_cmd_enable_multicast},
+ {"disable multicast", "<port id> <MAC>", "Disable multicast", parse_cmd_disable_multicast},
{"ring info all", "", "Get information about ring, such as ring size and number of elements in the ring", parse_cmd_ring_info_all},
{"ring info", "<core id> <task id>", "Get information about ring on core <core id> in task <task id>, such as ring size and number of elements in the ring", parse_cmd_ring_info},
{"port info", "<port id> [brief?]", "Get port related information, such as MAC address, socket, number of descriptors..., . Adding \"brief\" after command prints short version of output.", parse_cmd_port_info},
@@ -2115,6 +2195,8 @@ static struct cmd_str cmd_strings[] = {
{"random delay_us", "<core_id> <task_id> <random delay_us>", "Set the delay in usec for the impair mode to <random delay_us>", parse_cmd_random_delay_us},
{"probability", "<core_id> <task_id> <probability>", "Set the percent of forwarded packets for the impair mode", parse_cmd_set_probability},
{"version", "", "Show version", parse_cmd_version},
+ {"join igmp", "<core_id> <task_id> <ip>", "Send igmp membership report for group <ip>", parse_cmd_join_igmp},
+ {"leave igmp", "<core_id> <task_id>", "Send igmp leave group", parse_cmd_leave_igmp},
{0,0,0,0},
};
diff --git a/VNFs/DPPD-PROX/commands.c b/VNFs/DPPD-PROX/commands.c
index 969dec39..a66f4888 100644
--- a/VNFs/DPPD-PROX/commands.c
+++ b/VNFs/DPPD-PROX/commands.c
@@ -246,6 +246,61 @@ static struct size_unit to_size_unit(uint64_t bytes)
return ret;
}
+static int add_multicast_addr(uint8_t port_id, struct ether_addr *addr)
+{
+ unsigned int i;
+ int rc = 0;
+
+ struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
+
+ if (port_cfg->nb_mc_addr >= NB_MCAST_ADDR) {
+ plog_err("Already reached maximum number (%d) of mcast addr on port %u\n", NB_MCAST_ADDR, port_id);
+ return -1;
+ }
+ for (i = 0; i < port_cfg->nb_mc_addr; i++) {
+ if (is_same_ether_addr(addr, &port_cfg->mc_addr[i])) {
+ plog_info("multicast address already added to port\n");
+ return -1;
+ }
+ }
+
+ ether_addr_copy(addr, &port_cfg->mc_addr[port_cfg->nb_mc_addr]);
+ if ((rc = rte_eth_dev_set_mc_addr_list(port_id, port_cfg->mc_addr, port_cfg->nb_mc_addr + 1)) != 0) {
+ plog_err("rte_eth_dev_set_mc_addr_list returns %d on port %u\n", rc, port_id);
+ return rc;
+ }
+
+ port_cfg->nb_mc_addr++;
+ plog_info("rte_eth_dev_set_mc_addr_list(%d addr) on port %u\n", port_cfg->nb_mc_addr, port_id);
+ return rc;
+}
+
+static int del_multicast_addr(uint8_t port_id, struct ether_addr *addr)
+{
+ unsigned int i;
+ int rc = 0;
+
+ struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
+
+ for (i = 0; i < port_cfg->nb_mc_addr; i++) {
+ if (is_same_ether_addr(addr, &port_cfg->mc_addr[i])) {
+ // Copy last address to the slot to be deleted
+ ether_addr_copy(&port_cfg->mc_addr[port_cfg->nb_mc_addr-1], &port_cfg->mc_addr[i]);
+
+ if ((rc = rte_eth_dev_set_mc_addr_list(port_id, port_cfg->mc_addr, port_cfg->nb_mc_addr - 1)) != 0) {
+ plog_err("rte_eth_dev_set_mc_addr_list returns %d on port %u\n", rc, port_id);
+ // When set failed, let restore the situation we were before calling the function...
+ ether_addr_copy(addr, &port_cfg->mc_addr[i]);
+ return rc;
+ }
+ port_cfg->nb_mc_addr--;
+ plog_info("rte_eth_dev_set_mc_addr_list(%d addr) on port %u\n", port_cfg->nb_mc_addr, port_id);
+ return 0;
+ }
+ }
+ plog_err("multicast address not found on port %u\n", port_id);
+ return -1;
+}
void cmd_mem_stats(void)
{
struct rte_malloc_socket_stats sock_stats;
@@ -858,6 +913,9 @@ void cmd_portinfo(int port_id, char *dst, size_t max_len)
dst += snprintf(dst, end - dst, "\tSocket: %u\n", port_cfg->socket);
dst += snprintf(dst, end - dst, "\tPCI address: %s\n", port_cfg->pci_addr);
dst += snprintf(dst, end - dst, "\tPromiscuous: %s\n", port_cfg->promiscuous? "yes" : "no");
+ for (unsigned int i = 0; i < port_cfg->nb_mc_addr; i++) {
+ dst += snprintf(dst, end - dst, "\tmcast address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->mc_addr[i].addr_bytes));
+ }
dst += snprintf(dst, end - dst, "\tNumber of RX/TX descriptors: %u/%u\n", port_cfg->n_rxd, port_cfg->n_txd);
dst += snprintf(dst, end - dst, "\tNumber of RX/TX queues: %u/%u (max: %u/%u)\n", port_cfg->n_rxq, port_cfg->n_txq, port_cfg->max_rxq, port_cfg->max_txq);
dst += snprintf(dst, end - dst, "\tMemory pools:\n");
@@ -899,6 +957,31 @@ void cmd_reset_port(uint8_t portid)
}
}
+void cmd_multicast(uint8_t port_id, unsigned int val, struct ether_addr *mac)
+{
+ if (!port_is_active(port_id)) {
+ return;
+ }
+ struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
+ if (val == 1) {
+ if (port_cfg->nb_mc_addr == 0) {
+ rte_eth_allmulticast_enable(port_id);
+ }
+ if (add_multicast_addr(port_id, mac) != 0) {
+ if (port_cfg->nb_mc_addr == 0)
+ rte_eth_allmulticast_disable(port_id);
+ }
+ } else if (val == 0) {
+ if (del_multicast_addr(port_id, mac) == 0) {
+ if (port_cfg->nb_mc_addr == 0) {
+ rte_eth_allmulticast_disable(port_id);
+ }
+ }
+ } else {
+ plog_err("Unexpected value in cmd_multicast on port %d\n", port_id);
+ }
+}
+
void cmd_write_reg(uint8_t port_id, unsigned int id, unsigned int val)
{
if (!port_is_active(port_id)) {
diff --git a/VNFs/DPPD-PROX/commands.h b/VNFs/DPPD-PROX/commands.h
index 6c4a29a3..291930ff 100644
--- a/VNFs/DPPD-PROX/commands.h
+++ b/VNFs/DPPD-PROX/commands.h
@@ -18,6 +18,7 @@
#define _COMMANDS_H_
#include <inttypes.h>
+#include <rte_ether.h>
struct input;
@@ -64,6 +65,7 @@ void cmd_set_cache_class(uint32_t lcore_id, uint32_t set);
void cmd_cache_reset(void);
void cmd_reset_port(uint8_t port_id);
+void cmd_multicast(uint8_t port_id, unsigned int val, struct ether_addr *mac);
int reconnect_task(uint32_t lcore_id, uint32_t task_id);
int bypass_task(uint32_t lcore_id, uint32_t task_id);
diff --git a/VNFs/DPPD-PROX/config/mcast.cfg b/VNFs/DPPD-PROX/config/mcast.cfg
new file mode 100644
index 00000000..3e673e57
--- /dev/null
+++ b/VNFs/DPPD-PROX/config/mcast.cfg
@@ -0,0 +1,108 @@
+;;
+;; Copyright (c) 2019 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.
+;;
+
+[eal options]
+-n=6 ; force number of memory channels
+no-output=no ; disable DPDK debug output
+
+;; This example uses 2 physical ports, connected back to back or through a
+;; switch.
+;; The 1st physical port (DPDK port 0) generates (through tasks 2 and 3 on
+;; core 1) 2x IGMP membership query per second: one towards 224.0.0.3 and
+;; one towards 224.0.0.4.
+;; mcast packets can be generated using "speed 1 0 1" (to generate packets
+;; on core 1, task 0 at 100Mbps) and "speed 1 1 1" (to generate packets
+;; on core 1, task 1 at 100Mbps). They will resp. generate mcast packets
+;; towards 224.0.0.3 and 224.0.0.4;
+
+;; 2x VF are configured on the second physical port.
+;; They receive packets from the generator, each on their own mcast address.
+
+[port 0]
+name=gen_port
+
+[port 1]
+name=vf0
+multicast=01:00:5e:00:00:03
+
+[port 2]
+name=vf1
+multicast=01:00:5e:00:00:04
+
+[variables]
+$mbs=8
+
+[defaults]
+mempool size=4K
+
+[global]
+start time=5
+name=Basic multicast
+
+[core 0s0]
+mode=master
+
+[core 1s0]
+name=gen
+task=0
+mode=gen
+tx port=gen_port
+bps=0
+pkt inline=01 00 5e 00 00 03 00 00 00 00 00 01 08 00 45 00 05 dc 00 00 00 00 ff 11 00 00 c0 a8 01 01 e0 00 00 03 0b b8 0b b8 05 c8 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7
+min bulk size=$mbs
+
+task=1
+mode=gen
+tx port=gen_port
+bps=0
+pkt inline=01 00 5e 00 00 04 00 00 00 00 00 01 08 00 45 00 05 dc 00 00 00 00 ff 11 00 00 c0 a8 01 01 e0 00 00 04 0b b8 0b b8 05 c8 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7
+min bulk size=$mbs
+
+task=2
+mode=gen
+tx port=gen_port
+bps=125
+pkt inline=01 00 5e 00 00 03 00 00 01 00 00 01 08 00 45 00 00 1c 00 00 00 00 01 02 b0 dd c0 a8 01 02 e0 00 00 03 11 0a 0c f0 e0 00 00 03
+
+task=3
+mode=gen
+tx port=gen_port
+bps=125
+pkt inline=01 00 5e 00 00 04 00 00 01 00 00 01 08 00 45 00 00 1c 00 00 00 00 01 02 b0 dd c0 a8 01 02 e0 00 00 04 11 0a 0c f0 e0 00 00 04
+
+[core 2s0]
+name=RX gen
+task=0
+mode=nop
+rx port=gen_port
+
+[core 3s1]
+name=swap 0
+task=0
+mode=swap
+rx port=vf0
+tx port=vf0
+local ipv4=20.21.22.23
+igmp ipv4=224.0.0.3
+
+[core 4s1]
+name=swap 1
+task=0
+mode=swap
+rx port=vf1
+tx port=vf1
+local ipv4=20.21.22.24
+igmp ipv4=224.0.0.4
diff --git a/VNFs/DPPD-PROX/defaults.c b/VNFs/DPPD-PROX/defaults.c
index 700b63ef..fce5c5c1 100644
--- a/VNFs/DPPD-PROX/defaults.c
+++ b/VNFs/DPPD-PROX/defaults.c
@@ -169,6 +169,7 @@ void set_port_defaults(void)
{
for (uint8_t i = 0; i < PROX_MAX_PORTS; ++i ) {
prox_port_cfg[i].promiscuous = 1;
+ prox_port_cfg[i].nb_mc_addr = 0;
prox_port_cfg[i].n_rxd = NB_RX_RING_DESC;
prox_port_cfg[i].n_txd = NB_TX_RING_DESC;
prox_port_cfg[i].port_conf = default_port_conf;
diff --git a/VNFs/DPPD-PROX/handle_swap.c b/VNFs/DPPD-PROX/handle_swap.c
index 63c4dbde..39131013 100644
--- a/VNFs/DPPD-PROX/handle_swap.c
+++ b/VNFs/DPPD-PROX/handle_swap.c
@@ -21,20 +21,28 @@
#include "task_base.h"
#include "lconf.h"
#include "log.h"
-#include "arp.h"
-#include "handle_swap.h"
#include "prox_port_cfg.h"
#include "mpls.h"
#include "qinq.h"
#include "gre.h"
#include "prefetch.h"
+#include "igmp.h"
+#include "prox_cksum.h"
struct task_swap {
struct task_base base;
- uint8_t src_dst_mac[12];
+ struct rte_mempool *igmp_pool;
uint32_t runtime_flags;
+ uint32_t igmp_address;
+ uint8_t src_dst_mac[12];
+ uint32_t local_ipv4;
+ int offload_crc;
};
+#define NB_IGMP_MBUF 1024
+#define IGMP_MBUF_SIZE 2048
+#define NB_CACHE_IGMP_MBUF 256
+
static void write_src_and_dst_mac(struct task_swap *task, struct rte_mbuf *mbuf)
{
struct ether_hdr *hdr;
@@ -63,29 +71,46 @@ static void write_src_and_dst_mac(struct task_swap *task, struct rte_mbuf *mbuf)
}
}
}
-static inline int handle_arp_request(struct task_swap *task, struct ether_hdr_arp *hdr_arp, struct ether_addr *s_addr, uint32_t ip)
+
+static inline void build_mcast_mac(uint32_t ip, struct ether_addr *dst_mac)
{
- if ((hdr_arp->arp.data.tpa == ip) || (ip == 0)) {
- build_arp_reply(hdr_arp, s_addr);
- return 0;
- } else if (task->runtime_flags & TASK_MULTIPLE_MAC) {
- struct ether_addr tmp_s_addr;
- create_mac(hdr_arp, &tmp_s_addr);
- build_arp_reply(hdr_arp, &tmp_s_addr);
- return 0;
- } else {
- plogx_dbg("Received ARP on unexpected IP %x, expecting %x\n", rte_be_to_cpu_32(hdr_arp->arp.data.tpa), rte_be_to_cpu_32(ip));
- return OUT_DISCARD;
- }
+ // MAC address is 01:00:5e followed by 23 LSB of IP address
+ uint64_t mac = 0x0000005e0001L | ((ip & 0xFFFF7F00L) << 16);
+ memcpy(dst_mac, &mac, sizeof(struct ether_addr));
}
-/*
- * swap mode does not send arp requests, so does not expect arp replies
- * Need to understand later whether we must send arp requests
- */
-static inline int handle_arp_replies(struct task_swap *task, struct ether_hdr_arp *hdr_arp)
+static inline void build_igmp_message(struct task_base *tbase, struct rte_mbuf *mbuf, uint32_t ip, uint8_t igmp_message)
{
- return OUT_DISCARD;
+ struct task_swap *task = (struct task_swap *)tbase;
+ struct ether_hdr *hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *);
+ struct ether_addr dst_mac;
+ build_mcast_mac(ip, &dst_mac);
+
+ rte_pktmbuf_pkt_len(mbuf) = 46;
+ rte_pktmbuf_data_len(mbuf) = 46;
+ init_mbuf_seg(mbuf);
+
+ ether_addr_copy(&dst_mac, &hdr->d_addr);
+ ether_addr_copy((struct ether_addr *)&task->src_dst_mac[6], &hdr->s_addr);
+ hdr->ether_type = ETYPE_IPv4;
+
+ struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)(hdr + 1);
+ ip_hdr->version_ihl = 0x45; /**< version and header length */
+ ip_hdr->type_of_service = 0; /**< type of service */
+ ip_hdr->total_length = rte_cpu_to_be_16(32); /**< length of packet */
+ ip_hdr->packet_id = 0; /**< packet ID */
+ ip_hdr->fragment_offset = 0; /**< fragmentation offset */
+ ip_hdr->time_to_live = 1; /**< time to live */
+ ip_hdr->next_proto_id = IPPROTO_IGMP; /**< protocol ID */
+ ip_hdr->hdr_checksum = 0; /**< header checksum */
+ ip_hdr->src_addr = task->local_ipv4; /**< source address */
+ ip_hdr->dst_addr = ip; /**< destination address */
+ struct igmpv2_hdr *pigmp = (struct igmpv2_hdr *)(ip_hdr + 1);
+ pigmp->type = igmp_message;
+ pigmp->max_resp_time = 0;
+ pigmp->checksum = 0;
+ pigmp->group_address = ip;
+ prox_ip_udp_cksum(mbuf, ip_hdr, sizeof(struct ether_hdr), sizeof(struct ipv4_hdr), task->offload_crc);
}
static int handle_swap_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
@@ -95,6 +120,8 @@ static int handle_swap_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, ui
struct ether_addr mac;
struct ipv4_hdr *ip_hdr;
struct udp_hdr *udp_hdr;
+ struct gre_hdr *pgre;
+ struct ipv4_hdr *inner_ip_hdr;
uint32_t ip;
uint16_t port;
uint8_t out[64] = {0};
@@ -102,8 +129,9 @@ static int handle_swap_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, ui
uint32_t mpls_len = 0;
struct qinq_hdr *qinq;
struct vlan_hdr *vlan;
- struct ether_hdr_arp *hdr_arp;
uint16_t j;
+ struct igmpv2_hdr *pigmp;
+ uint8_t type;
for (j = 0; j < n_pkts; ++j) {
PREFETCH0(mbufs[j]);
@@ -112,12 +140,14 @@ static int handle_swap_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, ui
PREFETCH0(rte_pktmbuf_mtod(mbufs[j], void *));
}
+ // TODO 1: check packet is long enough for Ethernet + IP + UDP = 42 bytes
for (uint16_t j = 0; j < n_pkts; ++j) {
hdr = rte_pktmbuf_mtod(mbufs[j], struct ether_hdr *);
switch (hdr->ether_type) {
case ETYPE_MPLSU:
mpls = (struct mpls_hdr *)(hdr + 1);
while (!(mpls->bytes & 0x00010000)) {
+ // TODO: verify pcket length
mpls++;
mpls_len += sizeof(struct mpls_hdr);
}
@@ -173,30 +203,111 @@ static int handle_swap_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, ui
out[j] = OUT_DISCARD;
continue;
}
- udp_hdr = (struct udp_hdr *)(ip_hdr + 1);
+ // TODO 2 : check packet is long enough for Ethernet + IP + UDP + extra header (VLAN, MPLS, ...)
ip = ip_hdr->dst_addr;
- ip_hdr->dst_addr = ip_hdr->src_addr;
- ip_hdr->src_addr = ip;
- if (ip_hdr->next_proto_id == IPPROTO_GRE) {
- struct gre_hdr *pgre = (struct gre_hdr *)(ip_hdr + 1);
- struct ipv4_hdr *inner_ip_hdr = ((struct ipv4_hdr *)(pgre + 1));
+
+ switch (ip_hdr->next_proto_id) {
+ case IPPROTO_GRE:
+ ip_hdr->dst_addr = ip_hdr->src_addr;
+ ip_hdr->src_addr = ip;
+
+ pgre = (struct gre_hdr *)(ip_hdr + 1);
+ inner_ip_hdr = ((struct ipv4_hdr *)(pgre + 1));
ip = inner_ip_hdr->dst_addr;
inner_ip_hdr->dst_addr = inner_ip_hdr->src_addr;
inner_ip_hdr->src_addr = ip;
+
udp_hdr = (struct udp_hdr *)(inner_ip_hdr + 1);
+ // TODO 3.1 : verify proto is UPD or TCP
port = udp_hdr->dst_port;
udp_hdr->dst_port = udp_hdr->src_port;
udp_hdr->src_port = port;
- } else {
+ write_src_and_dst_mac(task, mbufs[j]);
+ break;
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ if (task->igmp_address && IS_IPV4_MCAST(rte_be_to_cpu_32(ip))) {
+ out[j] = OUT_DISCARD;
+ continue;
+ }
+ udp_hdr = (struct udp_hdr *)(ip_hdr + 1);
+ ip_hdr->dst_addr = ip_hdr->src_addr;
+ ip_hdr->src_addr = ip;
+
port = udp_hdr->dst_port;
udp_hdr->dst_port = udp_hdr->src_port;
udp_hdr->src_port = port;
+ write_src_and_dst_mac(task, mbufs[j]);
+ break;
+ case IPPROTO_IGMP:
+ pigmp = (struct igmpv2_hdr *)(ip_hdr + 1);
+ // TODO: check packet len
+ type = pigmp->type;
+ if (type == IGMP_MEMBERSHIP_QUERY) {
+ if (task->igmp_address) {
+ // We have an address registered
+ if ((task->igmp_address == pigmp->group_address) || (pigmp->group_address == 0)) {
+ // We get a request for the registered address, or to 0.0.0.0
+ build_igmp_message(tbase, mbufs[j], task->igmp_address, IGMP_MEMBERSHIP_REPORT); // replace Membership query packet with a response
+ } else {
+ // Discard as either we are not registered or this is a query for a different group
+ out[j] = OUT_DISCARD;
+ continue;
+ }
+ } else {
+ // Discard as either we are not registered
+ out[j] = OUT_DISCARD;
+ continue;
+ }
+ } else {
+ // Do not forward other IGMP packets back
+ out[j] = OUT_DISCARD;
+ continue;
+ }
+ break;
+ default:
+ plog_warn("Unsupported IP protocol 0x%x\n", ip_hdr->next_proto_id);
+ out[j] = OUT_DISCARD;
+ continue;
}
- write_src_and_dst_mac(task, mbufs[j]);
}
return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
}
+void igmp_join_group(struct task_base *tbase, uint32_t igmp_address)
+{
+ struct task_swap *task = (struct task_swap *)tbase;
+ struct rte_mbuf *igmp_mbuf;
+ uint8_t out[64] = {0};
+ int ret;
+
+ task->igmp_address = igmp_address;
+ ret = rte_mempool_get(task->igmp_pool, (void **)&igmp_mbuf);
+ if (ret != 0) {
+ plog_err("Unable to allocate igmp mbuf\n");
+ return;
+ }
+ build_igmp_message(tbase, igmp_mbuf, task->igmp_address, IGMP_MEMBERSHIP_REPORT);
+ task->base.tx_pkt(&task->base, &igmp_mbuf, 1, out);
+}
+
+void igmp_leave_group(struct task_base *tbase)
+{
+ struct task_swap *task = (struct task_swap *)tbase;
+ struct rte_mbuf *igmp_mbuf;
+ uint8_t out[64] = {0};
+ int ret;
+
+ task->igmp_address = 0;
+ ret = rte_mempool_get(task->igmp_pool, (void **)&igmp_mbuf);
+ if (ret != 0) {
+ plog_err("Unable to allocate igmp mbuf\n");
+ return;
+ }
+ build_igmp_message(tbase, igmp_mbuf, task->igmp_address, IGMP_LEAVE_GROUP);
+ task->base.tx_pkt(&task->base, &igmp_mbuf, 1, out);
+}
+
static void init_task_swap(struct task_base *tbase, struct task_args *targ)
{
struct task_swap *task = (struct task_swap *)tbase;
@@ -240,27 +351,36 @@ static void init_task_swap(struct task_base *tbase, struct task_args *targ)
}
}
task->runtime_flags = targ->flags;
+ task->igmp_address = rte_cpu_to_be_32(targ->igmp_address);
+ if (task->igmp_pool == NULL) {
+ static char name[] = "igmp0_pool";
+ name[4]++;
+ struct rte_mempool *ret = rte_mempool_create(name, NB_IGMP_MBUF, IGMP_MBUF_SIZE, NB_CACHE_IGMP_MBUF,
+ sizeof(struct rte_pktmbuf_pool_private), rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, 0,
+ rte_socket_id(), 0);
+ PROX_PANIC(ret == NULL, "Failed to allocate IGMP memory pool on socket %u with %u elements\n",
+ rte_socket_id(), NB_IGMP_MBUF);
+ plog_info("\t\tMempool %p (%s) size = %u * %u cache %u, socket %d\n", ret, name, NB_IGMP_MBUF,
+ IGMP_MBUF_SIZE, NB_CACHE_IGMP_MBUF, rte_socket_id());
+ task->igmp_pool = ret;
+ }
+ task->local_ipv4 = rte_cpu_to_be_32(targ->local_ipv4);
+
+ struct prox_port_cfg *port = find_reachable_port(targ);
+ if (port) {
+ task->offload_crc = port->requested_tx_offload & (DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM);
+ }
}
static struct task_init task_init_swap = {
.mode_str = "swap",
.init = init_task_swap,
.handle = handle_swap_bulk,
- .flag_features = TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS,
- .size = sizeof(struct task_swap),
-};
-
-static struct task_init task_init_swap_arp = {
- .mode_str = "swap",
- .sub_mode_str = "l3",
- .init = init_task_swap,
- .handle = handle_swap_bulk,
- .flag_features = TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS,
+ .flag_features = 0,
.size = sizeof(struct task_swap),
};
__attribute__((constructor)) static void reg_task_swap(void)
{
reg_task(&task_init_swap);
- reg_task(&task_init_swap_arp);
}
diff --git a/VNFs/DPPD-PROX/handle_swap.h b/VNFs/DPPD-PROX/handle_swap.h
deleted file mode 100644
index b589051d..00000000
--- a/VNFs/DPPD-PROX/handle_swap.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
-// 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.
-*/
-
-#ifndef _HANDLE_SWAP_H_
-#define _HANDLE_SWAP_H_
-
-struct task_base;
-
-#endif /* _HANDLE_SWAP_H_ */
diff --git a/VNFs/DPPD-PROX/igmp.h b/VNFs/DPPD-PROX/igmp.h
new file mode 100644
index 00000000..7b868aae
--- /dev/null
+++ b/VNFs/DPPD-PROX/igmp.h
@@ -0,0 +1,59 @@
+/*
+// Copyright (c) 2019 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.
+*/
+
+#ifndef _IGMP_H_
+#define _IGMP_H_
+
+#define IGMP_MEMBERSHIP_QUERY 0x11
+#define IGMP_MEMBERSHIP_REPORT_V1 0x12
+#define IGMP_MEMBERSHIP_REPORT 0x16
+#define IGMP_LEAVE_GROUP 0x17
+
+struct igmpv1_hdr {
+ uint8_t type: 4; /* type */
+ uint8_t version: 4; /* version */
+ uint8_t unused; /* unused */
+ uint16_t checksum; /* checksum */
+ uint32_t group_address; /* group address */
+} __attribute__((__packed__));
+
+struct igmpv2_hdr {
+ uint8_t type; /* type */
+ uint8_t max_resp_time; /* maximum response time */
+ uint16_t checksum; /* checksum */
+ uint32_t group_address; /* group address */
+} __attribute__((__packed__));
+
+struct igmpv3_hdr {
+ uint8_t type; /* type */
+ uint8_t max_resp_time; /* maximum response time */
+ uint16_t checksum; /* checksum */
+ uint32_t group_address; /* group address */
+ uint8_t bits: 4; /* S(suppress router-side processing)QRV(Querier.s Robustness Variable) bits */
+ uint8_t reserved: 4; /* reserved */
+ uint8_t QQIC; /* Querier.s Query Interval Code */
+ uint16_t n_src; /* Number of source addresses */
+} __attribute__((__packed__));
+
+struct task_base;
+
+// igmp_join and leave functions are so far implemented within handle_swap.
+// Only swap task can use them right now, as they use igmp_pool
+// only defined in swap task.
+void igmp_join_group(struct task_base *tbase, uint32_t igmp_address);
+void igmp_leave_group(struct task_base *tbase);
+
+#endif /* _IGMP_H_ */
diff --git a/VNFs/DPPD-PROX/prox_args.c b/VNFs/DPPD-PROX/prox_args.c
index b99796b7..df69f979 100644
--- a/VNFs/DPPD-PROX/prox_args.c
+++ b/VNFs/DPPD-PROX/prox_args.c
@@ -534,6 +534,17 @@ static int get_port_cfg(unsigned sindex, char *str, void *data)
}
cfg->promiscuous = val;
}
+ else if (STR_EQ(str, "multicast")) {
+ uint32_t val;
+ if (cfg->nb_mc_addr >= NB_MCAST_ADDR) {
+ plog_err("too many multicast addresses\n");
+ return -1;
+ }
+ if (parse_mac(&cfg->mc_addr[cfg->nb_mc_addr], pkey)) {
+ return -1;
+ }
+ cfg->nb_mc_addr++ ;
+ }
else if (STR_EQ(str, "lsc")) {
cfg->lsc_set_explicitely = 1;
uint32_t val;
@@ -856,9 +867,6 @@ static int get_core_cfg(unsigned sindex, char *str, void *data)
if (STR_EQ(str, "fast path handle arp")) {
return parse_flag(&targ->runtime_flags, TASK_FP_HANDLE_ARP, pkey);
}
- if (STR_EQ(str, "multiple arp")) {
- return parse_flag(&targ->flags, TASK_MULTIPLE_MAC, pkey);
- }
/* Using tx port name, only a _single_ port can be assigned to a task. */
if (STR_EQ(str, "tx port")) {
@@ -1356,6 +1364,9 @@ static int get_core_cfg(unsigned sindex, char *str, void *data)
targ->flags |= TASK_ARG_SRC_MAC_SET;
return 0;
}
+ if (STR_EQ(str, "igmp ipv4")) { /* IGMP Group */
+ return parse_ip(&targ->igmp_address, pkey);
+ }
if (STR_EQ(str, "gateway ipv4")) { /* Gateway IP address used when generating */
if ((targ->flags & TASK_ARG_L3) == 0)
plog_warn("gateway ipv4 configured but L3 sub mode not enabled\n");
diff --git a/VNFs/DPPD-PROX/prox_cksum.c b/VNFs/DPPD-PROX/prox_cksum.c
index add52f2b..58e05a6b 100644
--- a/VNFs/DPPD-PROX/prox_cksum.c
+++ b/VNFs/DPPD-PROX/prox_cksum.c
@@ -112,6 +112,10 @@ inline void prox_ip_udp_cksum(struct rte_mbuf *mbuf, struct ipv4_hdr *pip, uint1
} else
#endif
prox_tcp_cksum_sw(tcp, l4_len, pip->src_addr, pip->dst_addr);
+ } else if (pip->next_proto_id == IPPROTO_IGMP) {
+ struct igmpv2_hdr *igmp = (struct igmpv2_hdr *)(((uint8_t*)pip) + l3_len);
+ // Not sure NIC can offload IGMP checkum => do it in software
+ prox_igmp_cksum_sw(igmp, l4_len);
}
}
@@ -153,3 +157,10 @@ inline void prox_tcp_cksum_sw(struct tcp_hdr *tcp, uint16_t len, uint32_t src_ip
uint16_t csum = checksum_byte_seq((uint16_t *)tcp, len);
tcp->cksum = csum;
}
+
+inline void prox_igmp_cksum_sw(struct igmpv2_hdr *igmp, uint16_t len)
+{
+ igmp->checksum = 0;
+ uint16_t csum = checksum_byte_seq((uint16_t *)igmp, len);
+ igmp->checksum = csum;
+}
diff --git a/VNFs/DPPD-PROX/prox_cksum.h b/VNFs/DPPD-PROX/prox_cksum.h
index c11b17a5..57489900 100644
--- a/VNFs/DPPD-PROX/prox_cksum.h
+++ b/VNFs/DPPD-PROX/prox_cksum.h
@@ -25,6 +25,7 @@
#include <rte_udp.h>
#include <rte_tcp.h>
#include <rte_mbuf.h>
+#include "igmp.h"
#if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0)
#define CALC_TX_OL(l2_len, l3_len) ((uint64_t)(l2_len) | (uint64_t)(l3_len) << 7)
@@ -64,5 +65,6 @@ void prox_ip_udp_cksum(struct rte_mbuf *mbuf, struct ipv4_hdr *buf, uint16_t l2_
/* src_ip_addr/dst_ip_addr are in network byte order */
void prox_udp_cksum_sw(struct udp_hdr *udp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr);
void prox_tcp_cksum_sw(struct tcp_hdr *tcp, uint16_t len, uint32_t src_ip_addr, uint32_t dst_ip_addr);
+void prox_igmp_cksum_sw(struct igmpv2_hdr *igmp, uint16_t len);
#endif /* _PROX_CKSUM_H_ */
diff --git a/VNFs/DPPD-PROX/prox_port_cfg.c b/VNFs/DPPD-PROX/prox_port_cfg.c
index c335ee10..ac0ba0f3 100644
--- a/VNFs/DPPD-PROX/prox_port_cfg.c
+++ b/VNFs/DPPD-PROX/prox_port_cfg.c
@@ -41,6 +41,7 @@
#include "prox_cksum.h"
#include "stats_irq.h"
#include "prox_compat.h"
+#include "rte_ethdev.h"
struct prox_port_cfg prox_port_cfg[PROX_MAX_PORTS];
rte_atomic32_t lsc;
@@ -518,7 +519,7 @@ static void init_port(struct prox_port_cfg *port_cfg)
#if RTE_VERSION >= RTE_VERSION_NUM(2,0,0,0)
port_cfg->port_conf.rx_adv_conf.rss_conf.rss_hf &= port_cfg->dev_info.flow_type_rss_offloads;
#endif
- plog_info("\t\t Enabling RSS rss_hf = 0x%lx (requested 0x%llx)\n", port_cfg->port_conf.rx_adv_conf.rss_conf.rss_hf, ETH_RSS_IP|ETH_RSS_UDP);
+ plog_info("\t\t Enabling RSS rss_hf = 0x%lx (requested 0x%llx, supported 0x%lx)\n", port_cfg->port_conf.rx_adv_conf.rss_conf.rss_hf, ETH_RSS_IP|ETH_RSS_UDP, port_cfg->dev_info.flow_type_rss_offloads);
// rxmode such as hw src strip
#if RTE_VERSION >= RTE_VERSION_NUM(18,8,0,1)
@@ -689,6 +690,18 @@ static void init_port(struct prox_port_cfg *port_cfg)
}
}
}
+ if (port_cfg->nb_mc_addr) {
+ rte_eth_allmulticast_enable(port_id);
+ if ((ret = rte_eth_dev_set_mc_addr_list(port_id, port_cfg->mc_addr, port_cfg->nb_mc_addr)) != 0) {
+ plog_err("\t\trte_eth_dev_set_mc_addr_list returns %d on port %u\n", ret, port_id);
+ port_cfg->nb_mc_addr = 0;
+ rte_eth_allmulticast_disable(port_id);
+ plog_info("\t\tport %u NOT in multicast mode as failed to add mcast address\n", port_id);
+ } else {
+ plog_info("\t\trte_eth_dev_set_mc_addr_list(%d addr) on port %u\n", port_cfg->nb_mc_addr, port_id);
+ plog_info("\t\tport %u in multicast mode\n", port_id);
+ }
+ }
}
void init_port_all(void)
diff --git a/VNFs/DPPD-PROX/prox_port_cfg.h b/VNFs/DPPD-PROX/prox_port_cfg.h
index ccf83d6c..c025c03d 100644
--- a/VNFs/DPPD-PROX/prox_port_cfg.h
+++ b/VNFs/DPPD-PROX/prox_port_cfg.h
@@ -32,6 +32,7 @@ enum addr_type {PROX_PORT_MAC_HW, PROX_PORT_MAC_SET, PROX_PORT_MAC_RAND};
#define IPV4_CKSUM 1
#define UDP_CKSUM 2
+#define NB_MCAST_ADDR 16
struct prox_port_cfg {
struct rte_mempool *pool[32]; /* Rx/Tx mempool */
@@ -71,6 +72,8 @@ struct prox_port_cfg {
} capabilities;
uint32_t max_rx_pkt_len;
uint32_t min_rx_bufsize;
+ uint32_t nb_mc_addr;
+ struct ether_addr mc_addr[NB_MCAST_ADDR];
};
extern rte_atomic32_t lsc;
diff --git a/VNFs/DPPD-PROX/task_base.h b/VNFs/DPPD-PROX/task_base.h
index 64d17436..ce70aca2 100644
--- a/VNFs/DPPD-PROX/task_base.h
+++ b/VNFs/DPPD-PROX/task_base.h
@@ -53,7 +53,6 @@
#define TASK_FEATURE_LUT_QINQ_RSS 0x2000
#define TASK_FEATURE_LUT_QINQ_HASH 0x4000
#define TASK_FEATURE_RX_ALL 0x8000
-#define TASK_MULTIPLE_MAC 0x10000
#define TASK_FEATURE_TXQ_FLAGS_MULTIPLE_MEMPOOL 0x20000
#define FLAG_TX_FLUSH 0x01
diff --git a/VNFs/DPPD-PROX/task_init.h b/VNFs/DPPD-PROX/task_init.h
index f513d34f..9fa9f92b 100644
--- a/VNFs/DPPD-PROX/task_init.h
+++ b/VNFs/DPPD-PROX/task_init.h
@@ -233,6 +233,7 @@ struct task_args {
uint irq_debug;
struct task_base *tmaster;
char sub_mode_str[PROX_MODE_LEN];
+ uint32_t igmp_address;
};
/* Return the first port that is reachable through the task. If the