2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-30 22:05:19 +00:00

dpif-netdev: Add clone action

Add support for userspace datapath clone action.  The clone action
provides an action envelope to enclose an action list.
For example, with actions A, B, C and D,  and an action list:
      A, clone(B, C), D

The clone action will ensure that:

- D will see the same packet, and any meta states, such as flow, as
  action B.

- D will be executed regardless whether B, or C drops a packet. They
  can only drop a clone.

- When B drops a packet, clone will skip all remaining actions
  within the clone envelope. This feature is useful when we add
  meter action later:  The meter action can be implemented as a
  simple action without its own envolop (unlike the sample action).
  When necessary, the flow translation layer can enclose a meter action
  in clone.

The clone action is very similar with the OpenFlow clone action.
This is by design to simplify vswitchd flow translation logic.

Without datapath clone, vswitchd simulate the effect by inserting
datapath actions to "undo" clone actions. The above flow will be
translated into   A, B, C, -C, -B, D.

However, there are two issues:
- The resulting datapath action list may be longer without using
  clone.

- Some actions, such as NAT may not be possible to reverse.

This patch implements clone() simply with packet copy. The performance
can be improved with later patches, for example, to delay or avoid
packet copy if possible.  It seems datapath should have enough context
to carry out such optimization without the userspace context.

Signed-off-by: Andy Zhou <azhou@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
This commit is contained in:
Andy Zhou
2017-01-10 18:13:47 -08:00
parent bf6b1d052e
commit 535e3acfa7
8 changed files with 114 additions and 2 deletions

View File

@@ -528,6 +528,26 @@ odp_execute_sample(void *dp, struct dp_packet *packet, bool steal,
nl_attr_get_size(subactions), dp_execute_action);
}
static void
odp_execute_clone(void *dp, struct dp_packet *packet, bool steal,
const struct nlattr *actions,
odp_execute_cb dp_execute_action)
{
struct dp_packet_batch pb;
if (!steal) {
/* The 'actions' may modify the packet, but the modification
* should not propagate beyond this clone action. Make a copy
* the packet in case we don't own the packet, so that the
* 'actions' are only applied to the clone. 'odp_execute_actions'
* will free the clone. */
packet = dp_packet_clone(packet);
}
packet_batch_init_packet(&pb, packet);
odp_execute_actions(dp, &pb, true, nl_attr_get(actions),
nl_attr_get_size(actions), dp_execute_action);
}
static bool
requires_datapath_assistance(const struct nlattr *a)
{
@@ -552,6 +572,7 @@ requires_datapath_assistance(const struct nlattr *a)
case OVS_ACTION_ATTR_PUSH_MPLS:
case OVS_ACTION_ATTR_POP_MPLS:
case OVS_ACTION_ATTR_TRUNC:
case OVS_ACTION_ATTR_CLONE:
return false;
case OVS_ACTION_ATTR_UNSPEC:
@@ -685,6 +706,19 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
break;
}
case OVS_ACTION_ATTR_CLONE:
for (i = 0; i < cnt; i++) {
odp_execute_clone(dp, packets[i], steal && last_action, a,
dp_execute_action);
}
if (last_action) {
/* We do not need to free the packets. odp_execute_clone() has
* stolen them. */
return;
}
break;
case OVS_ACTION_ATTR_OUTPUT:
case OVS_ACTION_ATTR_TUNNEL_PUSH:
case OVS_ACTION_ATTR_TUNNEL_POP: