@@ -143,6 +143,9 @@ struct ovs_vport_stats {
/* Allow datapath to associate multiple Netlink PIDs to each vport */
#define OVS_DP_F_VPORT_PIDS (1 << 1)
+/* Allow tc offload recirc sharing */
+#define OVS_DP_F_TC_RECIRC_SHARING (1 << 2)
+
/* Fixed logical ports. */
#define OVSP_LOCAL ((__u32)0)
@@ -7627,6 +7627,7 @@ const struct dpif_class dpif_netdev_class = {
dpif_netdev_run,
dpif_netdev_wait,
dpif_netdev_get_stats,
+ NULL, /* set_features */
dpif_netdev_port_add,
dpif_netdev_port_del,
dpif_netdev_port_set_config,
@@ -193,6 +193,7 @@ struct dpif_handler {
struct dpif_netlink {
struct dpif dpif;
int dp_ifindex;
+ uint32_t user_features;
/* Upcall messages. */
struct fat_rwlock upcall_lock;
@@ -334,15 +335,26 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name,
/* Create or look up datapath. */
dpif_netlink_dp_init(&dp_request);
+ upcall_pid = 0;
+ dp_request.upcall_pid = &upcall_pid;
+ dp_request.name = name;
+
if (create) {
dp_request.cmd = OVS_DP_CMD_NEW;
- upcall_pid = 0;
- dp_request.upcall_pid = &upcall_pid;
} else {
+ dp_request.cmd = OVS_DP_CMD_GET;
+
+ error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
+ if (error) {
+ return error;
+ }
+ dp_request.user_features = dp.user_features;
+ ofpbuf_delete(buf);
+
/* Use OVS_DP_CMD_SET to report user features */
dp_request.cmd = OVS_DP_CMD_SET;
}
- dp_request.name = name;
+
dp_request.user_features |= OVS_DP_F_UNALIGNED;
dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
@@ -368,6 +380,7 @@ open_dpif(const struct dpif_netlink_dp *dp, struct dpif **dpifp)
dp->dp_ifindex, dp->dp_ifindex);
dpif->dp_ifindex = dp->dp_ifindex;
+ dpif->user_features = dp->user_features;
*dpifp = &dpif->dpif;
return 0;
@@ -664,6 +677,31 @@ dpif_netlink_get_stats(const struct dpif *dpif_, struct dpif_dp_stats *stats)
return error;
}
+static int
+dpif_netlink_set_features(struct dpif *dpif_, uint32_t new_features)
+{
+ struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
+ struct dpif_netlink_dp request, reply;
+ struct ofpbuf *bufp;
+ int error;
+
+ dpif_netlink_dp_init(&request);
+ request.cmd = OVS_DP_CMD_SET;
+ request.dp_ifindex = dpif->dp_ifindex;
+ request.user_features = dpif->user_features | new_features;
+
+ error = dpif_netlink_dp_transact(&request, &reply, &bufp);
+ if (!error) {
+ dpif->user_features = reply.user_features;
+ ofpbuf_delete(bufp);
+ if (!(dpif->user_features & new_features)) {
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return error;
+}
+
static const char *
get_vport_type(const struct dpif_netlink_vport *vport)
{
@@ -3885,6 +3923,7 @@ const struct dpif_class dpif_netlink_class = {
dpif_netlink_run,
NULL, /* wait */
dpif_netlink_get_stats,
+ dpif_netlink_set_features,
dpif_netlink_port_add,
dpif_netlink_port_del,
NULL, /* port_set_config */
@@ -4202,6 +4241,9 @@ dpif_netlink_dp_from_ofpbuf(struct dpif_netlink_dp *dp, const struct ofpbuf *buf
[OVS_DP_ATTR_MEGAFLOW_STATS] = {
NL_POLICY_FOR(struct ovs_dp_megaflow_stats),
.optional = true },
+ [OVS_DP_ATTR_USER_FEATURES] = {
+ .type = NL_A_U32,
+ .optional = true },
};
dpif_netlink_dp_init(dp);
@@ -4230,6 +4272,10 @@ dpif_netlink_dp_from_ofpbuf(struct dpif_netlink_dp *dp, const struct ofpbuf *buf
dp->megaflow_stats = nl_attr_get(a[OVS_DP_ATTR_MEGAFLOW_STATS]);
}
+ if (a[OVS_DP_ATTR_USER_FEATURES]) {
+ dp->user_features = nl_attr_get_u32(a[OVS_DP_ATTR_USER_FEATURES]);
+ }
+
return 0;
}
@@ -188,6 +188,8 @@ struct dpif_class {
/* Retrieves statistics for 'dpif' into 'stats'. */
int (*get_stats)(const struct dpif *dpif, struct dpif_dp_stats *stats);
+ int (*set_features)(struct dpif *dpif, uint32_t user_features);
+
/* Adds 'netdev' as a new port in 'dpif'. If '*port_no' is not
* ODPP_NONE, attempts to use that as the port's port number.
*
@@ -543,6 +543,15 @@ dpif_get_dp_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
return error;
}
+int
+dpif_set_features(struct dpif *dpif, uint32_t new_features)
+{
+ int error = dpif->dpif_class->set_features(dpif, new_features);
+
+ log_operation(dpif, "set_features", error);
+ return error;
+}
+
const char *
dpif_port_open_type(const char *datapath_type, const char *port_type)
{
@@ -435,6 +435,8 @@ struct dpif_dp_stats {
};
int dpif_get_dp_stats(const struct dpif *, struct dpif_dp_stats *);
+int dpif_set_features(struct dpif *, uint32_t new_features);
+
/* Port operations. */