The title should have been:

openvswitch: Only set mark and labels with a commit flag.

This reflects the fact that modifying the mark and/or labels of an existing 
connection is allowed. The commit flag is still required to do that, though.

  Jarno

> On Jun 20, 2016, at 5:19 PM, Jarno Rajahalme <ja...@ovn.org> wrote:
> 
> Only allow setting conntrack mark or labels when the commit flag is
> specified.  This makes sure we can not set them before the connection
> has been persisted, as in that case the mark and labels would be lost
> in an event of an userspace upcall.
> 
> OVS userspace already requires the commit flag to accept setting
> ct_mark and/or ct_labels.  Validate for this on the kernel API.
> 
> Finally, set conntrack mark and labels right before committing so that
> the initial conntrack NEW event has the mark and labels.
> 
> Signed-off-by: Jarno Rajahalme <ja...@ovn.org>
> ---
> net/openvswitch/conntrack.c | 72 ++++++++++++++++++++++++++++++---------------
> 1 file changed, 48 insertions(+), 24 deletions(-)
> 
> diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
> index 3d5feed..f1612f5 100644
> --- a/net/openvswitch/conntrack.c
> +++ b/net/openvswitch/conntrack.c
> @@ -824,6 +824,17 @@ static int ovs_ct_lookup(struct net *net, struct 
> sw_flow_key *key,
>       return 0;
> }
> 
> +static bool labels_nonzero(const struct ovs_key_ct_labels *labels)
> +{
> +     size_t i;
> +
> +     for (i = 0; i < sizeof(*labels); i++)
> +             if (labels->ct_labels[i])
> +                     return true;
> +
> +     return false;
> +}
> +
> /* Lookup connection and confirm if unconfirmed. */
> static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
>                        const struct ovs_conntrack_info *info,
> @@ -834,24 +845,35 @@ static int ovs_ct_commit(struct net *net, struct 
> sw_flow_key *key,
>       err = __ovs_ct_lookup(net, key, info, skb);
>       if (err)
>               return err;
> -     /* This is a no-op if the connection has already been confirmed. */
> +
> +     /* As any changes to an unconfirmed connection may be lost due
> +      * to an upcall, we require the presence of the 'commit' flag
> +      * for setting mask and/or labels.  Perform the changes before
> +      * confirming the connection so that the initial mark and label
> +      * values are present in the initial CT NEW netlink event.
> +      */
> +     if (info->mark.mask) {
> +             err = ovs_ct_set_mark(skb, key, info->mark.value,
> +                                   info->mark.mask);
> +             if (err)
> +                     return err;
> +     }
> +     if (labels_nonzero(&info->labels.mask)) {
> +             err = ovs_ct_set_labels(skb, key, &info->labels.value,
> +                                     &info->labels.mask);
> +             if (err)
> +                     return err;
> +     }
> +
> +     /* Will take care of sending queued events even if the connection is
> +      * already confirmed.
> +      */
>       if (nf_conntrack_confirm(skb) != NF_ACCEPT)
>               return -EINVAL;
> 
>       return 0;
> }
> 
> -static bool labels_nonzero(const struct ovs_key_ct_labels *labels)
> -{
> -     size_t i;
> -
> -     for (i = 0; i < sizeof(*labels); i++)
> -             if (labels->ct_labels[i])
> -                     return true;
> -
> -     return false;
> -}
> -
> /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
>  * value if 'skb' is freed.
>  */
> @@ -876,19 +898,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
>               err = ovs_ct_commit(net, key, info, skb);
>       else
>               err = ovs_ct_lookup(net, key, info, skb);
> -     if (err)
> -             goto err;
> 
> -     if (info->mark.mask) {
> -             err = ovs_ct_set_mark(skb, key, info->mark.value,
> -                                   info->mark.mask);
> -             if (err)
> -                     goto err;
> -     }
> -     if (labels_nonzero(&info->labels.mask))
> -             err = ovs_ct_set_labels(skb, key, &info->labels.value,
> -                                     &info->labels.mask);
> -err:
>       skb_push(skb, nh_ofs);
>       if (err)
>               kfree_skb(skb);
> @@ -1145,6 +1155,20 @@ static int parse_ct(const struct nlattr *attr, struct 
> ovs_conntrack_info *info,
>               }
>       }
> 
> +#ifdef CONFIG_NF_CONNTRACK_MARK
> +     if (!info->commit && info->mark.mask) {
> +             OVS_NLERR(log,
> +                       "Setting conntrack mark requires 'commit' flag.");
> +             return -EINVAL;
> +     }
> +#endif
> +#ifdef CONFIG_NF_CONNTRACK_LABELS
> +     if (!info->commit && labels_nonzero(&info->labels.mask)) {
> +             OVS_NLERR(log,
> +                       "Setting conntrack labels requires 'commit' flag.");
> +             return -EINVAL;
> +     }
> +#endif
>       if (rem > 0) {
>               OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem);
>               return -EINVAL;
> -- 
> 2.1.4
> 

Reply via email to