@@ -51,6 +51,7 @@
#include "latch.h"
#include "netdev.h"
#include "netdev-provider.h"
+#include "netdev-rte-offloads.h"
#include "netdev-vport.h"
#include "netlink.h"
#include "odp-execute.h"
@@ -1865,6 +1866,9 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
if (!error) {
*port_nop = port_no;
error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
+#ifdef DPDK_NETDEV
+ netdev_rte_offloads_port_add(netdev);
+#endif
}
ovs_mutex_unlock(&dp->port_mutex);
@@ -22,6 +22,7 @@
#include "cmap.h"
#include "dpif-netdev.h"
#include "netdev-provider.h"
+#include "netdev-vport.h"
#include "openvswitch/match.h"
#include "openvswitch/vlog.h"
#include "packets.h"
@@ -731,3 +732,49 @@ netdev_rte_offloads_flow_del(struct netdev *netdev, const ovs_u128 *ufid,
return netdev_rte_offloads_destroy_flow(netdev, ufid, rte_flow);
}
+
+/*
+ * Vport netdev flow pointers are initialized by default to kernel calls.
+ * They should be nullified or be set to a valid netdev (userspace) calls.
+ */
+#define NULLIFY(f) (ndc->f = NULL)
+static void
+netdev_rte_offloads_vxlan_init(struct netdev *netdev)
+{
+ /*
+ * Clone default function pointers some
+ * of which may be kernel flow pointers.
+ */
+ struct netdev_class *ndc = netdev_vport_dup_class_once(netdev);
+ if (!ndc) {
+ VLOG_DBG("Vport netdev_class offload api cannot be updated.");
+ return;
+ }
+
+ /* Override kernel flow pointers. */
+ NULLIFY(flow_put);
+ NULLIFY(flow_flush);
+ NULLIFY(flow_dump_create);
+ NULLIFY(flow_dump_destroy);
+ NULLIFY(flow_dump_next);
+ NULLIFY(flow_put);
+ NULLIFY(flow_get);
+ NULLIFY(flow_del);
+ NULLIFY(init_flow_api);
+
+ netdev_vport_update_class(netdev, ndc);
+}
+
+/*
+ * This function is called as part of adding a new dpif netdev port.
+ * In case of vport class of "vxlan" type we update it to match netdev
+ * datapath apis.
+ */
+void
+netdev_rte_offloads_port_add(struct netdev *netdev)
+{
+ const char *type = netdev_get_type(netdev);
+ if (!strcmp("vxlan", type)) {
+ netdev_rte_offloads_vxlan_init(netdev);
+ }
+}
@@ -50,6 +50,11 @@ int netdev_rte_offloads_flow_put(struct netdev *netdev, struct match *match,
int netdev_rte_offloads_flow_del(struct netdev *netdev, const ovs_u128 *ufid,
struct dpif_flow_stats *stats);
+/*
+ * Called by dpif netdev when a port is added
+ */
+void netdev_rte_offloads_port_add(struct netdev *netdev);
+
#define DPDK_FLOW_OFFLOAD_API \
.flow_put = netdev_rte_offloads_flow_put, \
.flow_del = netdev_rte_offloads_flow_del
@@ -1143,90 +1143,95 @@ netdev_vport_get_ifindex(const struct netdev *netdev_)
.get_tunnel_config = get_netdev_tunnel_config, \
.get_status = tunnel_get_status
+/* The name of the dpif_port should be short enough to accomodate adding
+ * a port number to the end if one is necessary. */
+static struct vport_class vport_classes[] = {
+ { "genev_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "geneve",
+ .build_header = netdev_geneve_build_header,
+ .push_header = netdev_tnl_push_udp_header,
+ .pop_header = netdev_geneve_pop_header,
+ .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+ { "gre_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "gre",
+ .build_header = netdev_gre_build_header,
+ .push_header = netdev_gre_push_header,
+ .pop_header = netdev_gre_pop_header,
+ .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+ { "vxlan_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "vxlan",
+ .build_header = netdev_vxlan_build_header,
+ .push_header = netdev_tnl_push_udp_header,
+ .pop_header = netdev_vxlan_pop_header,
+ .get_ifindex = NETDEV_VPORT_GET_IFINDEX
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+ { "lisp_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "lisp"
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+ { "stt_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "stt"
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+ { "erspan_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "erspan",
+ .build_header = netdev_erspan_build_header,
+ .push_header = netdev_erspan_push_header,
+ .pop_header = netdev_erspan_pop_header
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+ { "ip6erspan_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "ip6erspan",
+ .build_header = netdev_erspan_build_header,
+ .push_header = netdev_erspan_push_header,
+ .pop_header = netdev_erspan_pop_header
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+ { "ip6gre_sys",
+ {
+ TUNNEL_FUNCTIONS_COMMON,
+ .type = "ip6gre",
+ .build_header = netdev_gre_build_header,
+ .push_header = netdev_gre_push_header,
+ .pop_header = netdev_gre_pop_header
+ },
+ {{NULL, NULL, 0, 0}}
+ },
+};
+
+#define NUM_VPORT_CLASSES (sizeof vport_classes / sizeof vport_classes[0])
+
+static struct vport_class dup_vport_classes[NUM_VPORT_CLASSES];
+
void
netdev_vport_tunnel_register(void)
{
- /* The name of the dpif_port should be short enough to accomodate adding
- * a port number to the end if one is necessary. */
- static struct vport_class vport_classes[] = {
- { "genev_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "geneve",
- .build_header = netdev_geneve_build_header,
- .push_header = netdev_tnl_push_udp_header,
- .pop_header = netdev_geneve_pop_header,
- .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
- },
- {{NULL, NULL, 0, 0}}
- },
- { "gre_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "gre",
- .build_header = netdev_gre_build_header,
- .push_header = netdev_gre_push_header,
- .pop_header = netdev_gre_pop_header,
- .get_ifindex = NETDEV_VPORT_GET_IFINDEX,
- },
- {{NULL, NULL, 0, 0}}
- },
- { "vxlan_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "vxlan",
- .build_header = netdev_vxlan_build_header,
- .push_header = netdev_tnl_push_udp_header,
- .pop_header = netdev_vxlan_pop_header,
- .get_ifindex = NETDEV_VPORT_GET_IFINDEX
- },
- {{NULL, NULL, 0, 0}}
- },
- { "lisp_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "lisp"
- },
- {{NULL, NULL, 0, 0}}
- },
- { "stt_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "stt"
- },
- {{NULL, NULL, 0, 0}}
- },
- { "erspan_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "erspan",
- .build_header = netdev_erspan_build_header,
- .push_header = netdev_erspan_push_header,
- .pop_header = netdev_erspan_pop_header
- },
- {{NULL, NULL, 0, 0}}
- },
- { "ip6erspan_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "ip6erspan",
- .build_header = netdev_erspan_build_header,
- .push_header = netdev_erspan_push_header,
- .pop_header = netdev_erspan_pop_header
- },
- {{NULL, NULL, 0, 0}}
- },
- { "ip6gre_sys",
- {
- TUNNEL_FUNCTIONS_COMMON,
- .type = "ip6gre",
- .build_header = netdev_gre_build_header,
- .push_header = netdev_gre_push_header,
- .pop_header = netdev_gre_pop_header
- },
- {{NULL, NULL, 0, 0}}
- },
- };
static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
if (ovsthread_once_start(&once)) {
@@ -1237,6 +1242,8 @@ netdev_vport_tunnel_register(void)
netdev_register_provider(&vport_classes[i].netdev_class);
}
+ memset(dup_vport_classes, 0, sizeof dup_vport_classes);
+
unixctl_command_register("tnl/egress_port_range", "min max", 0, 2,
netdev_tnl_egress_port_range, NULL);
@@ -1259,3 +1266,45 @@ netdev_vport_patch_register(void)
simap_init(&patch_class.global_cfg_tracker);
netdev_register_provider(&patch_class.netdev_class);
}
+
+/*
+ * This functions receives a netdev pointer which contains default
+ * netdev_class fields (such as kernel flow functions pointers).
+ * It returns a duplicated netdev_class that can be overriden by the caller
+ */
+struct netdev_class *
+netdev_vport_dup_class_once(struct netdev *netdev)
+{
+ unsigned int i;
+ struct vport_class *vpclass;
+ struct netdev_class *ndclass = NULL;
+
+ if (!is_vport_class(netdev->netdev_class)) {
+ goto out;
+ }
+
+ /* Get the vport_class which contains the netdev_class. */
+ vpclass = vport_class_cast(netdev_get_class(netdev));
+ /* Calculate vpclass entry index in the array 'vport_classes' */
+ i = vpclass - &vport_classes[0];
+ if (i >= NUM_VPORT_CLASSES) {
+ goto out;
+ }
+ /* Entry duplication should be done only once */
+ if (!dup_vport_classes[i].dpif_port) {
+ memcpy(&dup_vport_classes[i], vpclass, sizeof *vpclass);
+ }
+ /* Get the duplicated netdev_class pointer */
+ ndclass = &dup_vport_classes[i].netdev_class;
+out:
+ return ndclass;
+}
+
+void
+netdev_vport_update_class(struct netdev *netdev, struct netdev_class *ndclass)
+{
+ if (is_vport_class(netdev->netdev_class)) {
+ netdev->netdev_class = ndclass;
+ }
+}
+
@@ -42,6 +42,10 @@ void netdev_vport_inc_tx(const struct netdev *,
bool netdev_vport_is_vport_class(const struct netdev_class *);
const char *netdev_vport_class_get_dpif_port(const struct netdev_class *);
+struct netdev_class *netdev_vport_dup_class_once(struct netdev *netdev);
+void netdev_vport_update_class(struct netdev *netdev,
+ struct netdev_class *ndclass);
+
#ifndef _WIN32
enum { NETDEV_VPORT_NAME_BUFSIZE = 16 };
#else