summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSriharsha Basavapatna via dev <ovs-dev@openvswitch.org>2018-10-18 21:43:12 +0530
committerSimon Horman <horms@verge.net.au>2018-10-19 11:27:45 +0200
commit738c785ff16288cf758470348de4106dd5b4416a (patch)
tree294d2bfce02816a5ad923aca0934b20b4125cd56
parentd7abfe39cfd234227bb6174b7f959a16dc803b83 (diff)
downloadopenvswitch-738c785ff16288cf758470348de4106dd5b4416a.tar.gz
dpif-netlink: Detect Out-Of-Resource condition on a netdev
This is the first patch in the patch-set to support dynamic rebalancing of offloaded flows. The patch detects OOR condition on a netdev port when ENOSPC error is returned by TC-Flower while adding a flow rule. A new structure is added to the netdev called "netdev_hw_info", to store OOR related information required to perform dynamic offload-rebalancing. Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com> Co-authored-by: Venkat Duvvuru <venkatkumar.duvvuru@broadcom.com> Signed-off-by: Venkat Duvvuru <venkatkumar.duvvuru@broadcom.com> Reviewed-by: Sathya Perla <sathya.perla@broadcom.com> Reviewed-by: Ben Pfaff <blp@ovn.org> Signed-off-by: Simon Horman <simon.horman@netronome.com>
-rw-r--r--lib/dpif-netlink.c18
-rw-r--r--lib/flow.c25
-rw-r--r--lib/flow.h1
-rw-r--r--lib/netdev-provider.h11
-rw-r--r--lib/netdev.c34
-rw-r--r--lib/netdev.h3
6 files changed, 91 insertions, 1 deletions
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index d83f3a903..5a2ba2d5b 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -2030,7 +2030,23 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put)
VLOG_DBG("added flow");
} else if (err != EEXIST) {
- VLOG_ERR_RL(&rl, "failed to offload flow: %s", ovs_strerror(err));
+ struct netdev *oor_netdev = NULL;
+ if (err == ENOSPC && netdev_is_offload_rebalance_policy_enabled()) {
+ /*
+ * We need to set OOR on the input netdev (i.e, 'dev') for the
+ * flow. But if the flow has a tunnel attribute (i.e, decap action,
+ * with a virtual device like a VxLAN interface as its in-port),
+ * then lookup and set OOR on the underlying tunnel (real) netdev.
+ */
+ oor_netdev = flow_get_tunnel_netdev(&match.flow.tunnel);
+ if (!oor_netdev) {
+ /* Not a 'tunnel' flow */
+ oor_netdev = dev;
+ }
+ netdev_set_hw_info(oor_netdev, HW_INFO_TYPE_OOR, true);
+ }
+ VLOG_ERR_RL(&rl, "failed to offload flow: %s: %s", ovs_strerror(err),
+ (oor_netdev ? oor_netdev->name : dev->name));
}
out:
diff --git a/lib/flow.c b/lib/flow.c
index 47b01fce8..c60446ff4 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
+#include <net/if.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
#include <netinet/ip6.h>
@@ -41,6 +42,8 @@
#include "unaligned.h"
#include "util.h"
#include "openvswitch/nsh.h"
+#include "ovs-router.h"
+#include "lib/netdev-provider.h"
COVERAGE_DEFINE(flow_extract);
COVERAGE_DEFINE(miniflow_malloc);
@@ -3455,3 +3458,25 @@ flow_limit_vlans(int vlan_limit)
flow_vlan_limit = MIN(vlan_limit, FLOW_MAX_VLAN_HEADERS);
}
}
+
+struct netdev *
+flow_get_tunnel_netdev(struct flow_tnl *tunnel)
+{
+ char iface[IFNAMSIZ];
+ struct in6_addr ip6;
+ struct in6_addr gw;
+
+ if (tunnel->ip_src) {
+ in6_addr_set_mapped_ipv4(&ip6, tunnel->ip_src);
+ } else if (ipv6_addr_is_set(&tunnel->ipv6_src)) {
+ ip6 = tunnel->ipv6_src;
+ } else {
+ return NULL;
+ }
+
+ if (!ovs_router_lookup(0, &ip6, iface, NULL, &gw)) {
+ return NULL;
+ }
+
+ return netdev_from_name(iface);
+}
diff --git a/lib/flow.h b/lib/flow.h
index 902ab1bad..5ebdb1f1d 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -73,6 +73,7 @@ void flow_extract(struct dp_packet *, struct flow *);
void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
void flow_unwildcard_tp_ports(const struct flow *, struct flow_wildcards *);
void flow_get_metadata(const struct flow *, struct match *flow_metadata);
+struct netdev *flow_get_tunnel_netdev(struct flow_tnl *tunnel);
const char *ct_state_to_string(uint32_t state);
uint32_t ct_state_from_string(const char *);
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 5a7947351..e320dad61 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -35,6 +35,15 @@ extern "C" {
struct netdev_tnl_build_header_params;
#define NETDEV_NUMA_UNSPEC OVS_NUMA_UNSPEC
+/* Offload-capable (HW) netdev information */
+struct netdev_hw_info {
+ bool oor; /* Out of Offload Resources ? */
+};
+
+enum hw_info_type {
+ HW_INFO_TYPE_OOR = 1 /* OOR state */
+};
+
/* A network device (e.g. an Ethernet device).
*
* Network device implementations may read these members but should not modify
@@ -80,6 +89,8 @@ struct netdev {
int n_rxq;
struct shash_node *node; /* Pointer to element in global map. */
struct ovs_list saved_flags_list; /* Contains "struct netdev_saved_flags". */
+
+ struct netdev_hw_info hw_info; /* offload-capable netdev info */
};
static inline void
diff --git a/lib/netdev.c b/lib/netdev.c
index 722ea89bf..708a4bbd7 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -415,6 +415,7 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp)
netdev->reconfigure_seq = seq_create();
netdev->last_reconfigure_seq =
seq_read(netdev->reconfigure_seq);
+ netdev->hw_info.oor = false;
netdev->node = shash_add(&netdev_shash, name, netdev);
/* By default enable one tx and rx queue per netdev. */
@@ -2253,6 +2254,31 @@ netdev_get_block_id(struct netdev *netdev)
: 0);
}
+/*
+ * Get the value of the hw info parameter specified by type.
+ * Returns the value on success (>= 0). Returns -1 on failure.
+ */
+int
+netdev_get_hw_info(struct netdev *netdev, int type)
+{
+ if (type == HW_INFO_TYPE_OOR) {
+ return netdev->hw_info.oor;
+ }
+
+ return -1;
+}
+
+/*
+ * Set the value of the hw info parameter specified by type.
+ */
+void
+netdev_set_hw_info(struct netdev *netdev, int type, int val)
+{
+ if (type == HW_INFO_TYPE_OOR) {
+ netdev->hw_info.oor = val;
+ }
+}
+
bool
netdev_is_flow_api_enabled(void)
{
@@ -2489,6 +2515,14 @@ netdev_free_custom_stats_counters(struct netdev_custom_stats *custom_stats)
}
}
+static bool netdev_offload_rebalance_policy = false;
+
+bool
+netdev_is_offload_rebalance_policy_enabled(void)
+{
+ return netdev_offload_rebalance_policy;
+}
+
#ifdef __linux__
static void
netdev_ports_flow_init(void)
diff --git a/lib/netdev.h b/lib/netdev.h
index 5ceba88db..c527bd2e9 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -228,8 +228,11 @@ int netdev_flow_del(struct netdev *, const ovs_u128 *,
struct dpif_flow_stats *);
int netdev_init_flow_api(struct netdev *);
uint32_t netdev_get_block_id(struct netdev *);
+int netdev_get_hw_info(struct netdev *, int);
+void netdev_set_hw_info(struct netdev *, int, int);
bool netdev_is_flow_api_enabled(void);
void netdev_set_flow_api_enabled(const struct smap *ovs_other_config);
+bool netdev_is_offload_rebalance_policy_enabled(void);
struct dpif_port;
int netdev_ports_insert(struct netdev *, const struct dpif_class *,