devices: add support for l3 af_packet interface
Type: improvement
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
Change-Id: Ia6b9d4ac55be2216887bfdb99be4021f6a96f166
diff --git a/src/vnet/devices/af_packet/af_packet.c b/src/vnet/devices/af_packet/af_packet.c
index 2dc2630..69e3c87 100644
--- a/src/vnet/devices/af_packet/af_packet.c
+++ b/src/vnet/devices/af_packet/af_packet.c
@@ -38,6 +38,11 @@
af_packet_main_t af_packet_main;
+VNET_HW_INTERFACE_CLASS (af_packet_ip_device_hw_interface_class, static) = {
+ .name = "af-packet-ip-device",
+ .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
+};
+
#define AF_PACKET_DEFAULT_TX_FRAMES_PER_BLOCK 1024
#define AF_PACKET_DEFAULT_TX_FRAME_SIZE (2048 * 5)
#define AF_PACKET_TX_BLOCK_NR 1
@@ -367,6 +372,7 @@
apif->per_interface_next_index = ~0;
apif->next_tx_frame = 0;
apif->next_rx_frame = 0;
+ apif->mode = arg->mode;
ret = af_packet_read_mtu (apif);
if (ret != 0)
@@ -375,36 +381,44 @@
if (tm->n_vlib_mains > 1)
clib_spinlock_init (&apif->lockp);
- /*use configured or generate random MAC address */
- if (arg->hw_addr)
- clib_memcpy (hw_addr, arg->hw_addr, 6);
+ if (apif->mode == AF_PACKET_IF_MODE_ETHERNET)
+ {
+ /*use configured or generate random MAC address */
+ if (arg->hw_addr)
+ clib_memcpy (hw_addr, arg->hw_addr, 6);
+ else
+ {
+ f64 now = vlib_time_now (vm);
+ u32 rnd;
+ rnd = (u32) (now * 1e6);
+ rnd = random_u32 (&rnd);
+
+ clib_memcpy (hw_addr + 2, &rnd, sizeof (rnd));
+ hw_addr[0] = 2;
+ hw_addr[1] = 0xfe;
+ }
+
+ error = ethernet_register_interface (
+ vnm, af_packet_device_class.index, if_index, hw_addr,
+ &apif->hw_if_index, af_packet_eth_flag_change);
+
+ if (error)
+ {
+ clib_memset (apif, 0, sizeof (*apif));
+ pool_put (apm->interfaces, apif);
+ vlib_log_err (apm->log_class, "Unable to register interface: %U",
+ format_clib_error, error);
+ clib_error_free (error);
+ ret = VNET_API_ERROR_SYSCALL_ERROR_1;
+ goto error;
+ }
+ }
else
{
- f64 now = vlib_time_now (vm);
- u32 rnd;
- rnd = (u32) (now * 1e6);
- rnd = random_u32 (&rnd);
-
- clib_memcpy (hw_addr + 2, &rnd, sizeof (rnd));
- hw_addr[0] = 2;
- hw_addr[1] = 0xfe;
+ apif->hw_if_index = vnet_register_interface (
+ vnm, af_packet_device_class.index, if_index,
+ af_packet_ip_device_hw_interface_class.index, if_index);
}
-
- error = ethernet_register_interface (vnm, af_packet_device_class.index,
- if_index, hw_addr, &apif->hw_if_index,
- af_packet_eth_flag_change);
-
- if (error)
- {
- clib_memset (apif, 0, sizeof (*apif));
- pool_put (apm->interfaces, apif);
- vlib_log_err (apm->log_class, "Unable to register interface: %U",
- format_clib_error, error);
- clib_error_free (error);
- ret = VNET_API_ERROR_SYSCALL_ERROR_1;
- goto error;
- }
-
sw = vnet_get_hw_sw_interface (vnm, apif->hw_if_index);
hw = vnet_get_hw_interface (vnm, apif->hw_if_index);
apif->sw_if_index = sw->sw_if_index;
@@ -504,7 +518,10 @@
mhash_unset (&apm->if_index_by_host_if_name, host_if_name, &if_index);
- ethernet_delete_interface (vnm, apif->hw_if_index);
+ if (apif->mode == AF_PACKET_IF_MODE_ETHERNET)
+ ethernet_delete_interface (vnm, apif->hw_if_index);
+ else
+ vnet_delete_hw_interface (vnm, apif->hw_if_index);
pool_put (apm->interfaces, apif);
diff --git a/src/vnet/devices/af_packet/af_packet.h b/src/vnet/devices/af_packet/af_packet.h
index 3163aa0..652e173 100644
--- a/src/vnet/devices/af_packet/af_packet.h
+++ b/src/vnet/devices/af_packet/af_packet.h
@@ -18,9 +18,14 @@
*/
#include <vppinfra/lock.h>
-
#include <vlib/log.h>
+typedef enum
+{
+ AF_PACKET_IF_MODE_ETHERNET = 1,
+ AF_PACKET_IF_MODE_IP = 2
+} af_packet_if_mode_t;
+
typedef struct
{
u32 sw_if_index;
@@ -49,6 +54,7 @@
u8 is_admin_up;
u32 queue_index;
u32 host_mtu;
+ af_packet_if_mode_t mode;
} af_packet_if_t;
typedef struct
@@ -77,6 +83,7 @@
u32 tx_frame_size;
u32 rx_frames_per_block;
u32 tx_frames_per_block;
+ af_packet_if_mode_t mode;
/* return */
u32 sw_if_index;
diff --git a/src/vnet/devices/af_packet/cli.c b/src/vnet/devices/af_packet/cli.c
index bae4f61..3dd3c8e 100644
--- a/src/vnet/devices/af_packet/cli.c
+++ b/src/vnet/devices/af_packet/cli.c
@@ -51,6 +51,9 @@
clib_memset (arg, 0, sizeof (*arg));
+ // Default mode
+ arg->mode = AF_PACKET_IF_MODE_ETHERNET;
+
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
@@ -69,6 +72,8 @@
else if (unformat (line_input, "tx-per-block %u",
&arg->tx_frames_per_block))
;
+ else if (unformat (line_input, "mode ip"))
+ arg->mode = AF_PACKET_IF_MODE_IP;
else if (unformat (line_input, "hw-addr %U", unformat_ethernet_address,
hwaddr))
arg->hw_addr = hwaddr;
@@ -140,7 +145,8 @@
?*/
VLIB_CLI_COMMAND (af_packet_create_command, static) = {
.path = "create host-interface",
- .short_help = "create host-interface name <ifname> [hw-addr <mac-addr>]",
+ .short_help =
+ "create host-interface name <ifname> [hw-addr <mac-addr>] [mode ip]",
.function = af_packet_create_command_fn,
};
diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c
index 0542b16..8e4bc2b 100644
--- a/src/vnet/devices/af_packet/device.c
+++ b/src/vnet/devices/af_packet/device.c
@@ -339,6 +339,14 @@
int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0);
struct ifreq ifr;
+ if (apif->mode == AF_PACKET_IF_MODE_IP)
+ {
+ vlib_log_warn (apm->log_class, "af_packet_%s interface is in IP mode",
+ apif->host_if_name);
+ return clib_error_return (0,
+ " MAC update failed, interface is in IP mode");
+ }
+
if (0 > fd)
{
vlib_log_warn (apm->log_class, "af_packet_%s could not open socket",
diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c
index e2f87b1..0fdae5c 100644
--- a/src/vnet/devices/af_packet/node.c
+++ b/src/vnet/devices/af_packet/node.c
@@ -194,7 +194,7 @@
{
af_packet_main_t *apm = &af_packet_main;
struct tpacket2_hdr *tph;
- u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
+ u32 next_index;
u32 block = 0;
u32 rx_frame;
u32 n_free_bufs;
@@ -209,6 +209,21 @@
u32 thread_index = vm->thread_index;
u32 n_buffer_bytes = vlib_buffer_get_default_data_size (vm);
u32 min_bufs = apif->rx_req->tp_frame_size / n_buffer_bytes;
+ vlib_buffer_t bt;
+
+ if (apif->mode == AF_PACKET_IF_MODE_IP)
+ {
+ next_index = VNET_DEVICE_INPUT_NEXT_IP4_INPUT;
+ }
+ else
+ {
+ next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
+ if (PREDICT_FALSE (apif->per_interface_next_index != ~0))
+ next_index = apif->per_interface_next_index;
+
+ /* redirect if feature path enabled */
+ vnet_feature_start_device_input_x1 (apif->sw_if_index, &next_index, &bt);
+ }
n_free_bufs = vec_len (apm->rx_buffers[thread_index]);
if (PREDICT_FALSE (n_free_bufs < VLIB_FRAME_SIZE))
@@ -317,14 +332,30 @@
}
else
{
- next0 = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
-
- if (PREDICT_FALSE (apif->per_interface_next_index != ~0))
- next0 = apif->per_interface_next_index;
-
- /* redirect if feature path enabled */
- vnet_feature_start_device_input_x1 (apif->sw_if_index, &next0,
- first_b0);
+ if (PREDICT_FALSE (apif->mode == AF_PACKET_IF_MODE_IP))
+ {
+ switch (first_b0->data[0] & 0xf0)
+ {
+ case 0x40:
+ next0 = VNET_DEVICE_INPUT_NEXT_IP4_INPUT;
+ break;
+ case 0x60:
+ next0 = VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
+ break;
+ default:
+ next0 = VNET_DEVICE_INPUT_NEXT_DROP;
+ break;
+ }
+ if (PREDICT_FALSE (apif->per_interface_next_index != ~0))
+ next0 = apif->per_interface_next_index;
+ }
+ else
+ {
+ /* copy feature arc data from template */
+ first_b0->current_config_index = bt.current_config_index;
+ vnet_buffer (first_b0)->feature_arc_index =
+ vnet_buffer (&bt)->feature_arc_index;
+ }
}
/* trace */