#include "ofpbuf.h"
#include "packets.h"
#include "poll-loop.h"
+#include "random.h"
#include "shash.h"
#include "timeval.h"
#include "util.h"
}
static int
-dpif_netdev_get_stats(const struct dpif *dpif, struct ovs_dp_stats *stats)
+dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
- memset(stats, 0, sizeof *stats);
stats->n_flows = hmap_count(&dp->flow_table);
stats->n_frags = dp->n_frags;
stats->n_hit = dp->n_hit;
return 0;
}
-static int
-dpif_netdev_validate_actions(const struct nlattr *actions,
- size_t actions_len, bool *mutates)
-{
- const struct nlattr *a;
- unsigned int left;
-
- *mutates = false;
- NL_ATTR_FOR_EACH (a, left, actions, actions_len) {
- uint16_t type = nl_attr_type(a);
- int len = odp_action_len(type);
-
- if (len != nl_attr_get_size(a)) {
- return EINVAL;
- }
-
- switch (type) {
- case OVS_ACTION_ATTR_OUTPUT:
- if (nl_attr_get_u32(a) >= MAX_PORTS) {
- return EINVAL;
- }
- break;
-
- case OVS_ACTION_ATTR_USERSPACE:
- break;
-
- case OVS_ACTION_ATTR_PUSH_VLAN:
- *mutates = true;
- if (nl_attr_get_be16(a) & htons(VLAN_CFI)) {
- return EINVAL;
- }
- break;
-
- case OVS_ACTION_ATTR_SET_NW_TOS:
- *mutates = true;
- if (nl_attr_get_u8(a) & IP_ECN_MASK) {
- return EINVAL;
- }
- break;
-
- case OVS_ACTION_ATTR_POP_VLAN:
- case OVS_ACTION_ATTR_SET_DL_SRC:
- case OVS_ACTION_ATTR_SET_DL_DST:
- case OVS_ACTION_ATTR_SET_NW_SRC:
- case OVS_ACTION_ATTR_SET_NW_DST:
- case OVS_ACTION_ATTR_SET_TP_SRC:
- case OVS_ACTION_ATTR_SET_TP_DST:
- *mutates = true;
- break;
-
- case OVS_ACTION_ATTR_SET_TUNNEL:
- case OVS_ACTION_ATTR_SET_PRIORITY:
- case OVS_ACTION_ATTR_POP_PRIORITY:
- default:
- return EOPNOTSUPP;
- }
- }
- return 0;
-}
-
static int
set_flow_actions(struct dp_netdev_flow *flow,
const struct nlattr *actions, size_t actions_len)
{
- bool mutates;
- int error;
-
- error = dpif_netdev_validate_actions(actions, actions_len, &mutates);
- if (error) {
- return error;
- }
-
flow->actions = xrealloc(flow->actions, actions_len);
flow->actions_len = actions_len;
memcpy(flow->actions, actions, actions_len);
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct ofpbuf copy;
- bool mutates;
struct flow key;
int error;
return EINVAL;
}
- error = dpif_netdev_validate_actions(actions, actions_len, &mutates);
- if (error) {
- return error;
- }
-
- if (mutates) {
- /* We need a deep copy of 'packet' since we're going to modify its
- * data. */
- ofpbuf_init(©, DP_NETDEV_HEADROOM + packet->size);
- ofpbuf_reserve(©, DP_NETDEV_HEADROOM);
- ofpbuf_put(©, packet->data, packet->size);
- } else {
- /* We still need a shallow copy of 'packet', even though we won't
- * modify its data, because flow_extract() modifies packet->l2, etc.
- * We could probably get away with modifying those but it's more polite
- * if we don't. */
- copy = *packet;
- }
+ /* Make a deep copy of 'packet', because we might modify its data. */
+ ofpbuf_init(©, DP_NETDEV_HEADROOM + packet->size);
+ ofpbuf_reserve(©, DP_NETDEV_HEADROOM);
+ ofpbuf_put(©, packet->data, packet->size);
flow_extract(©, 0, -1, &key);
error = dpif_netdev_flow_from_nlattrs(key_attrs, key_len, &key);
error = dp_netdev_execute_actions(dp, ©, &key,
actions, actions_len);
}
- if (mutates) {
- ofpbuf_uninit(©);
- }
+
+ ofpbuf_uninit(©);
return error;
}
return 0;
}
+static void
+dp_netdev_sample(struct dp_netdev *dp,
+ struct ofpbuf *packet, struct flow *key,
+ const struct nlattr *action)
+{
+ const struct nlattr *subactions = NULL;
+ const struct nlattr *a;
+ size_t left;
+
+ NL_NESTED_FOR_EACH_UNSAFE (a, left, action) {
+ int type = nl_attr_type(a);
+
+ switch ((enum ovs_sample_attr) type) {
+ case OVS_SAMPLE_ATTR_PROBABILITY:
+ if (random_uint32() >= nl_attr_get_u32(a)) {
+ return;
+ }
+ break;
+
+ case OVS_SAMPLE_ATTR_ACTIONS:
+ subactions = a;
+ break;
+
+ case OVS_SAMPLE_ATTR_UNSPEC:
+ case __OVS_SAMPLE_ATTR_MAX:
+ default:
+ NOT_REACHED();
+ }
+ }
+
+ dp_netdev_execute_actions(dp, packet, key, nl_attr_get(subactions),
+ nl_attr_get_size(subactions));
+}
+
+static void
+dp_netdev_action_userspace(struct dp_netdev *dp,
+ struct ofpbuf *packet, struct flow *key,
+ const struct nlattr *a)
+{
+ const struct nlattr *userdata_attr;
+ uint64_t userdata;
+
+ userdata_attr = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
+ userdata = userdata_attr ? nl_attr_get_u64(userdata_attr) : 0;
+ dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata);
+}
+
static int
dp_netdev_execute_actions(struct dp_netdev *dp,
struct ofpbuf *packet, struct flow *key,
unsigned int left;
NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
- switch (nl_attr_type(a)) {
+ int type = nl_attr_type(a);
+
+ switch ((enum ovs_action_attr) type) {
case OVS_ACTION_ATTR_OUTPUT:
dp_netdev_output_port(dp, packet, nl_attr_get_u32(a));
break;
case OVS_ACTION_ATTR_USERSPACE:
- dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION,
- key, nl_attr_get_u64(a));
+ dp_netdev_action_userspace(dp, packet, key, a);
break;
case OVS_ACTION_ATTR_PUSH_VLAN:
case OVS_ACTION_ATTR_SET_TP_DST:
dp_netdev_set_tp_port(packet, key, a);
break;
+
+ case OVS_ACTION_ATTR_SAMPLE:
+ dp_netdev_sample(dp, packet, key, a);
+ break;
+
+ case OVS_ACTION_ATTR_SET_TUNNEL:
+ case OVS_ACTION_ATTR_SET_PRIORITY:
+ case OVS_ACTION_ATTR_POP_PRIORITY:
+ /* not implemented */
+ break;
+
+ case OVS_ACTION_ATTR_UNSPEC:
+ case __OVS_ACTION_ATTR_MAX:
+ NOT_REACHED();
}
}
return 0;
dpif_netdev_port_query_by_number,
dpif_netdev_port_query_by_name,
dpif_netdev_get_max_ports,
+ NULL, /* port_get_pid */
dpif_netdev_port_dump_start,
dpif_netdev_port_dump_next,
dpif_netdev_port_dump_done,