On Tue, Jun 7, 2016 at 10:53 PM, William Tu <[email protected]> wrote:
> The patch adds a new action to support packet truncation. The new action
> is formatted as 'output(port=n,max_len=m)', as output to port n, with
> packet size being MIN(original_size, m).
>
> One use case is to enable port mirroring to send smaller packets to the
> destination port so that only useful packet information is mirrored/copied,
> saving some performance overhead of copying entire packet payload. Example
> use case is below as well as shown in the testcases:
>
> - Output to port 1 with max_len 100 bytes.
> - The output packet size on port 1 will be MIN(original_packet_size, 100).
> # ovs-ofctl add-flow br0 'actions=output(port=1,max_len=100)'
>
> - The scope of max_len is limited to output action itself. The following
> packet size of output:1 and output:2 will be intact.
> # ovs-ofctl add-flow br0 \
> 'actions=output(port=1,max_len=100),output:1,output:2'
> - The Datapath actions shows:
> # Datapath actions: trunc(100),1,1,2
>
> Signed-off-by: William Tu <[email protected]>
> ---
Can you send next version against net-next tree? All feature patches
needs to be pushed upstream OVS first.
...
> diff --git a/datapath/actions.c b/datapath/actions.c
> index dcf8591..92ee3f9 100644
> --- a/datapath/actions.c
> +++ b/datapath/actions.c
> @@ -778,6 +778,7 @@ static int output_userspace(struct datapath *dp, struct
> sk_buff *skb,
> memset(&upcall, 0, sizeof(upcall));
> upcall.cmd = OVS_PACKET_CMD_ACTION;
> upcall.mru = OVS_CB(skb)->mru;
> + upcall.cutlen = OVS_CB(skb)->cutlen;
>
> for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
> a = nla_next(a, &rem)) {
> @@ -854,10 +855,17 @@ static int sample(struct datapath *dp, struct sk_buff
> *skb,
> return 0;
>
> /* The only known usage of sample action is having a single user-space
> + * action, or having a truncate action followed by a single user-space
> * action. Treat this usage as a special case.
> * The output_userspace() should clone the skb to be sent to the
> - * user space. This skb will be consumed by its caller.
> - */
> + * user space. This skb will be consumed by its caller. */
> + if (unlikely(nla_type(a) == OVS_ACTION_ATTR_TRUNC)) {
> + struct ovs_action_trunc *trunc = nla_data(a);
> + OVS_CB(skb)->cutlen = skb->len > trunc->max_len ?
> + skb->len - trunc->max_len : 0;
> + a = nla_next(a, &rem);
> + }
> +
> if (likely(nla_type(a) == OVS_ACTION_ATTR_USERSPACE &&
> nla_is_last(a, rem)))
> return output_userspace(dp, skb, key, a, actions,
> actions_len);
> @@ -1040,10 +1048,15 @@ static int do_execute_actions(struct datapath *dp,
> struct sk_buff *skb,
> for (a = attr, rem = len; rem > 0;
> a = nla_next(a, &rem)) {
> int err = 0;
> + int cutlen = OVS_CB(skb)->cutlen;
>
> if (unlikely(prev_port != -1)) {
> struct sk_buff *out_skb = skb_clone(skb, GFP_ATOMIC);
>
> + if (cutlen > 0) {
> + pskb_trim(out_skb, out_skb->len - cutlen);
> + OVS_CB(skb)->cutlen = 0;
> + }
> if (out_skb)
> do_output(dp, out_skb, prev_port, key);
>
Lets move the pskb_trim() call inside do_output(). So that NULL skb
is not passed to the function.
> @@ -1055,6 +1068,16 @@ static int do_execute_actions(struct datapath *dp,
> struct sk_buff *skb,
> prev_port = nla_get_u32(a);
> break;
>
> + case OVS_ACTION_ATTR_TRUNC: {
> + struct ovs_action_trunc *trunc = nla_data(a);
> +
> + if (trunc->max_len < ETH_MIN_FRAME_LEN)
> + return -EINVAL;
Does max_len still needs to be check after checking the at flow install.
> + OVS_CB(skb)->cutlen = skb->len > trunc->max_len ?
> + skb->len - trunc->max_len : 0;
> + break;
> + }
> +
> case OVS_ACTION_ATTR_USERSPACE:
> output_userspace(dp, skb, key, a, attr, len);
> break;
> @@ -1125,8 +1148,15 @@ static int do_execute_actions(struct datapath *dp,
> struct sk_buff *skb,
> }
> }
>
> - if (prev_port != -1)
> + if (prev_port != -1) {
> + uint32_t cutlen = OVS_CB(skb)->cutlen;
> +
> + if (cutlen > 0) {
> + pskb_trim(skb, skb->len - cutlen);
> + OVS_CB(skb)->cutlen = 0;
> + }
> do_output(dp, skb, prev_port, key);
> + }
By moving pskb_trim() to do_output() we can avoid the duplicate code.
> else
> consume_skb(skb);
>
> diff --git a/datapath/datapath.c b/datapath/datapath.c
> index 5bec072..958dfb8 100644
> --- a/datapath/datapath.c
> +++ b/datapath/datapath.c
> @@ -280,6 +280,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct
> sw_flow_key *key)
> upcall.cmd = OVS_PACKET_CMD_MISS;
> upcall.portid = ovs_vport_find_upcall_portid(p, skb);
> upcall.mru = OVS_CB(skb)->mru;
> + upcall.cutlen = OVS_CB(skb)->cutlen;
> error = ovs_dp_upcall(dp, skb, key, &upcall);
> if (unlikely(error))
> kfree_skb(skb);
> @@ -409,6 +410,10 @@ static size_t upcall_msg_size(const struct
> dp_upcall_info *upcall_info,
> if (upcall_info->mru)
> size += nla_total_size(sizeof(upcall_info->mru));
>
> + /* OVS_PACKET_ATTR_CUTLEN */
> + if (upcall_info->cutlen)
> + size += nla_total_size(sizeof(upcall_info->cutlen));
> +
I think this should be part of separate patch. This is not required
for truncate support.
> return size;
> }
>
> @@ -439,6 +444,7 @@ static int queue_userspace_packet(struct datapath *dp,
> struct sk_buff *skb,
> size_t len;
> unsigned int hlen;
> int err, dp_ifindex;
> + int cutlen = OVS_CB(skb)->cutlen;
>
> dp_ifindex = get_dpifindex(dp);
> if (!dp_ifindex)
> @@ -475,6 +481,9 @@ static int queue_userspace_packet(struct datapath *dp,
> struct sk_buff *skb,
> else
> hlen = skb->len;
>
> + if (cutlen > 0)
> + hlen -= cutlen;
> +
> len = upcall_msg_size(upcall_info, hlen);
> user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
> if (!user_skb) {
> @@ -525,6 +534,16 @@ static int queue_userspace_packet(struct datapath *dp,
> struct sk_buff *skb,
> pad_packet(dp, user_skb);
> }
>
> + /* Add OVS_PACKET_ATTR_CUTLEN */
> + if (upcall_info->cutlen) {
> + if (nla_put_u16(user_skb, OVS_PACKET_ATTR_CUTLEN,
> + upcall_info->cutlen)) {
> + err = -ENOBUFS;
> + goto out;
> + }
> + pad_packet(dp, user_skb);
> + }
> +
> /* Only reserve room for attribute header, packet data is added
> * in skb_zerocopy()
> */
> @@ -532,9 +551,10 @@ static int queue_userspace_packet(struct datapath *dp,
> struct sk_buff *skb,
> err = -ENOBUFS;
> goto out;
> }
> - nla->nla_len = nla_attr_size(skb->len);
> + nla->nla_len = nla_attr_size(skb->len - cutlen);
>
> - err = skb_zerocopy(user_skb, skb, skb->len, hlen);
> + err = skb_zerocopy(user_skb, skb,
> + (cutlen > 0) ? hlen : skb->len, hlen);
I do not think we need to compare cut-len with zero, we can just
subtract it from skb->len.
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev