datapath: More flexible kernel/userspace tunneling attribute.
authorPravin B Shelar <pshelar@nicira.com>
Sat, 19 Jan 2013 02:03:15 +0000 (18:03 -0800)
committerPravin B Shelar <pshelar@nicira.com>
Sat, 19 Jan 2013 02:03:15 +0000 (18:03 -0800)
Following patch breaks down single ipv4_tunnel netlink attribute into
individual member attributes. It will help when we extend tunneling
parameters in future.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Bug #14611

datapath/datapath.c
datapath/flow.c
datapath/flow.h
datapath/tunnel.h
include/linux/openvswitch.h
lib/dpif-netdev.c
lib/odp-util.c
tests/odp.at

index ac6b705..d363cd7 100644 (file)
@@ -527,16 +527,89 @@ static int flush_flows(struct datapath *dp)
        return 0;
 }
 
-static int validate_actions(const struct nlattr *attr,
-                               const struct sw_flow_key *key, int depth);
+static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, int attr_len)
+{
+
+       struct sw_flow_actions *acts;
+       int new_acts_size;
+       int req_size = NLA_ALIGN(attr_len);
+       int next_offset = offsetof(struct sw_flow_actions, actions) +
+                                       (*sfa)->actions_len;
+
+       if (req_size <= (ksize(*sfa) - next_offset))
+               goto out;
+
+       new_acts_size = ksize(*sfa) * 2;
+
+       if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
+               if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size)
+                       return ERR_PTR(-EMSGSIZE);
+               new_acts_size = MAX_ACTIONS_BUFSIZE;
+       }
+
+       acts = ovs_flow_actions_alloc(new_acts_size);
+       if (IS_ERR(acts))
+               return (void *)acts;
 
-static int validate_sample(const struct nlattr *attr,
-                               const struct sw_flow_key *key, int depth)
+       memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len);
+       acts->actions_len = (*sfa)->actions_len;
+       kfree(*sfa);
+       *sfa = acts;
+
+out:
+       (*sfa)->actions_len += req_size;
+       return  (struct nlattr *) ((unsigned char *)(*sfa) + next_offset);
+}
+
+static int add_action(struct sw_flow_actions **sfa, int attrtype, void *data, int len)
+{
+       struct nlattr *a;
+
+       a = reserve_sfa_size(sfa, nla_attr_size(len));
+       if (IS_ERR(a))
+               return PTR_ERR(a);
+
+       a->nla_type = attrtype;
+       a->nla_len = nla_attr_size(len);
+
+       if (data)
+               memcpy(nla_data(a), data, len);
+       memset((unsigned char *) a + a->nla_len, 0, nla_padlen(len));
+
+       return 0;
+}
+
+static inline int add_nested_action_start(struct sw_flow_actions **sfa, int attrtype)
+{
+       int used = (*sfa)->actions_len;
+       int err;
+
+       err = add_action(sfa, attrtype, NULL, 0);
+       if (err)
+               return err;
+
+       return used;
+}
+
+static inline void add_nested_action_end(struct sw_flow_actions *sfa, int st_offset)
+{
+       struct nlattr *a = (struct nlattr *) ((unsigned char *)sfa->actions + st_offset);
+
+       a->nla_len = sfa->actions_len - st_offset;
+}
+
+static int validate_and_copy_actions(const struct nlattr *attr,
+                               const struct sw_flow_key *key, int depth,
+                               struct sw_flow_actions **sfa);
+
+static int validate_and_copy_sample(const struct nlattr *attr,
+                          const struct sw_flow_key *key, int depth,
+                          struct sw_flow_actions **sfa)
 {
        const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1];
        const struct nlattr *probability, *actions;
        const struct nlattr *a;
-       int rem;
+       int rem, start, err, st_acts;
 
        memset(attrs, 0, sizeof(attrs));
        nla_for_each_nested(a, attr, rem) {
@@ -555,7 +628,26 @@ static int validate_sample(const struct nlattr *attr,
        actions = attrs[OVS_SAMPLE_ATTR_ACTIONS];
        if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN))
                return -EINVAL;
-       return validate_actions(actions, key, depth + 1);
+
+       /* validation done, copy sample action. */
+       start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE);
+       if (start < 0)
+               return start;
+       err = add_action(sfa, OVS_SAMPLE_ATTR_PROBABILITY, nla_data(probability), sizeof(u32));
+       if (err)
+               return err;
+       st_acts = add_nested_action_start(sfa, OVS_SAMPLE_ATTR_ACTIONS);
+       if (st_acts < 0)
+               return st_acts;
+
+       err = validate_and_copy_actions(actions, key, depth + 1, sfa);
+       if (err)
+               return err;
+
+       add_nested_action_end(*sfa, st_acts);
+       add_nested_action_end(*sfa, start);
+
+       return 0;
 }
 
 static int validate_tp_port(const struct sw_flow_key *flow_key)
@@ -571,8 +663,30 @@ static int validate_tp_port(const struct sw_flow_key *flow_key)
        return -EINVAL;
 }
 
+static int validate_and_copy_set_tun(const struct nlattr *attr,
+                                    struct sw_flow_actions **sfa)
+{
+       struct ovs_key_ipv4_tunnel tun_key;
+       int err, start;
+
+       err = ipv4_tun_from_nlattr(nla_data(attr), &tun_key);
+       if (err)
+               return err;
+
+       start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET);
+       if (start < 0)
+               return start;
+
+       err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &tun_key, sizeof(tun_key));
+       add_nested_action_end(*sfa, start);
+
+       return err;
+}
+
 static int validate_set(const struct nlattr *a,
-                       const struct sw_flow_key *flow_key)
+                       const struct sw_flow_key *flow_key,
+                       struct sw_flow_actions **sfa,
+                       bool *set_tun)
 {
        const struct nlattr *ovs_key = nla_data(a);
        int key_type = nla_type(ovs_key);
@@ -582,13 +696,14 @@ static int validate_set(const struct nlattr *a,
                return -EINVAL;
 
        if (key_type > OVS_KEY_ATTR_MAX ||
-           nla_len(ovs_key) != ovs_key_lens[key_type])
+           (ovs_key_lens[key_type] != nla_len(ovs_key) &&
+            ovs_key_lens[key_type] != -1))
                return -EINVAL;
 
        switch (key_type) {
        const struct ovs_key_ipv4 *ipv4_key;
-       const struct ovs_key_ipv4_tunnel *tun_key;
        const struct ovs_key_ipv6 *ipv6_key;
+       int err;
 
        case OVS_KEY_ATTR_PRIORITY:
        case OVS_KEY_ATTR_TUN_ID:
@@ -602,10 +717,11 @@ static int validate_set(const struct nlattr *a,
 #endif
                break;
 
-       case OVS_KEY_ATTR_IPV4_TUNNEL:
-               tun_key = nla_data(ovs_key);
-               if (!tun_key->ipv4_dst)
-                       return -EINVAL;
+       case OVS_KEY_ATTR_TUNNEL:
+               *set_tun = true;
+               err = validate_and_copy_set_tun(a, sfa);
+               if (err)
+                       return err;
                break;
 
        case OVS_KEY_ATTR_IPV4:
@@ -683,8 +799,24 @@ static int validate_userspace(const struct nlattr *attr)
        return 0;
 }
 
-static int validate_actions(const struct nlattr *attr,
-                               const struct sw_flow_key *key,  int depth)
+static int copy_action(const struct nlattr *from,
+                     struct sw_flow_actions **sfa)
+{
+       int totlen = NLA_ALIGN(from->nla_len);
+       struct nlattr *to;
+
+       to = reserve_sfa_size(sfa, from->nla_len);
+       if (IS_ERR(to))
+               return PTR_ERR(to);
+
+       memcpy(to, from, totlen);
+       return 0;
+}
+
+static int validate_and_copy_actions(const struct nlattr *attr,
+                               const struct sw_flow_key *key,
+                               int depth,
+                               struct sw_flow_actions **sfa)
 {
        const struct nlattr *a;
        int rem, err;
@@ -704,12 +836,14 @@ static int validate_actions(const struct nlattr *attr,
                };
                const struct ovs_action_push_vlan *vlan;
                int type = nla_type(a);
+               bool skip_copy;
 
                if (type > OVS_ACTION_ATTR_MAX ||
                    (action_lens[type] != nla_len(a) &&
                     action_lens[type] != (u32)-1))
                        return -EINVAL;
 
+               skip_copy = false;
                switch (type) {
                case OVS_ACTION_ATTR_UNSPEC:
                        return -EINVAL;
@@ -738,20 +872,26 @@ static int validate_actions(const struct nlattr *attr,
                        break;
 
                case OVS_ACTION_ATTR_SET:
-                       err = validate_set(a, key);
+                       err = validate_set(a, key, sfa, &skip_copy);
                        if (err)
                                return err;
                        break;
 
                case OVS_ACTION_ATTR_SAMPLE:
-                       err = validate_sample(a, key, depth);
+                       err = validate_and_copy_sample(a, key, depth, sfa);
                        if (err)
                                return err;
+                       skip_copy = true;
                        break;
 
                default:
                        return -EINVAL;
                }
+               if (!skip_copy) {
+                       err = copy_action(a, sfa);
+                       if (err)
+                               return err;
+               }
        }
 
        if (rem > 0)
@@ -820,16 +960,15 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]);
        if (err)
                goto err_flow_free;
-
-       err = validate_actions(a[OVS_PACKET_ATTR_ACTIONS], &flow->key, 0);
-       if (err)
-               goto err_flow_free;
-
-       acts = ovs_flow_actions_alloc(a[OVS_PACKET_ATTR_ACTIONS]);
+       acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS]));
        err = PTR_ERR(acts);
        if (IS_ERR(acts))
                goto err_flow_free;
+
+       err = validate_and_copy_actions(a[OVS_PACKET_ATTR_ACTIONS], &flow->key, 0, &acts);
        rcu_assign_pointer(flow->sf_acts, acts);
+       if (err)
+               goto err_flow_free;
 
        OVS_CB(packet)->flow = flow;
        packet->priority = flow->key.phy.priority;
@@ -918,6 +1057,99 @@ static struct genl_multicast_group ovs_dp_flow_multicast_group = {
        .name = OVS_FLOW_MCGROUP
 };
 
+static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *skb);
+static int sample_action_to_attr(const struct nlattr *attr, struct sk_buff *skb)
+{
+       const struct nlattr *a;
+       struct nlattr *start;
+       int err = 0, rem;
+
+       start = nla_nest_start(skb, OVS_ACTION_ATTR_SAMPLE);
+       if (!start)
+               return -EMSGSIZE;
+
+       nla_for_each_nested(a, attr, rem) {
+               int type = nla_type(a);
+               struct nlattr *st_sample;
+
+               switch (type) {
+               case OVS_SAMPLE_ATTR_PROBABILITY:
+                       if (nla_put(skb, OVS_SAMPLE_ATTR_PROBABILITY, sizeof(u32), nla_data(a)))
+                               return -EMSGSIZE;
+                       break;
+               case OVS_SAMPLE_ATTR_ACTIONS:
+                       st_sample = nla_nest_start(skb, OVS_SAMPLE_ATTR_ACTIONS);
+                       if (!st_sample)
+                               return -EMSGSIZE;
+                       err = actions_to_attr(nla_data(a), nla_len(a), skb);
+                       if (err)
+                               return err;
+                       nla_nest_end(skb, st_sample);
+                       break;
+               }
+       }
+
+       nla_nest_end(skb, start);
+       return err;
+}
+
+static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
+{
+       const struct nlattr *ovs_key = nla_data(a);
+       int key_type = nla_type(ovs_key);
+       struct nlattr *start;
+       int err;
+
+       switch (key_type) {
+       case OVS_KEY_ATTR_IPV4_TUNNEL:
+               start = nla_nest_start(skb, OVS_ACTION_ATTR_SET);
+               if (!start)
+                       return -EMSGSIZE;
+
+               err = ipv4_tun_to_nlattr(skb, nla_data(ovs_key));
+               if (err)
+                       return err;
+               nla_nest_end(skb, start);
+               break;
+       default:
+               if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key))
+                       return -EMSGSIZE;
+               break;
+       }
+
+       return 0;
+}
+
+static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *skb)
+{
+       const struct nlattr *a;
+       int rem, err;
+
+       nla_for_each_attr(a, attr, len, rem) {
+               int type = nla_type(a);
+
+               switch (type) {
+               case OVS_ACTION_ATTR_SET:
+                       err = set_action_to_attr(a, skb);
+                       if (err)
+                               return err;
+                       break;
+
+               case OVS_ACTION_ATTR_SAMPLE:
+                       err = sample_action_to_attr(a, skb);
+                       if (err)
+                               return err;
+                       break;
+               default:
+                       if (nla_put(skb, type, nla_len(a), nla_data(a)))
+                               return -EMSGSIZE;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 /* Called with genl_lock. */
 static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
                                  struct sk_buff *skb, u32 portid,
@@ -925,6 +1157,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
 {
        const int skb_orig_len = skb->len;
        const struct sw_flow_actions *sf_acts;
+       struct nlattr *start;
        struct ovs_flow_stats stats;
        struct ovs_header *ovs_header;
        struct nlattr *nla;
@@ -979,10 +1212,11 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
         * This can only fail for dump operations because the skb is always
         * properly sized for single flows.
         */
-       err = nla_put(skb, OVS_FLOW_ATTR_ACTIONS, sf_acts->actions_len,
-                     sf_acts->actions);
+       start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS);
+       err = actions_to_attr(sf_acts->actions, sf_acts->actions_len, skb);
        if (err < 0 && skb_orig_len)
                goto error;
+       nla_nest_end(skb, start);
 
        return genlmsg_end(skb, ovs_header);
 
@@ -1042,6 +1276,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        struct sk_buff *reply;
        struct datapath *dp;
        struct flow_table *table;
+       struct sw_flow_actions *acts = NULL;
        int error;
        int key_len;
 
@@ -1055,9 +1290,14 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 
        /* Validate actions. */
        if (a[OVS_FLOW_ATTR_ACTIONS]) {
-               error = validate_actions(a[OVS_FLOW_ATTR_ACTIONS], &key,  0);
-               if (error)
+               acts = ovs_flow_actions_alloc(nla_len(a[OVS_FLOW_ATTR_ACTIONS]));
+               error = PTR_ERR(acts);
+               if (IS_ERR(acts))
                        goto error;
+
+               error = validate_and_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &key,  0, &acts);
+               if (error)
+                       goto err_kfree;
        } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) {
                error = -EINVAL;
                goto error;
@@ -1066,17 +1306,15 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
        error = -ENODEV;
        if (!dp)
-               goto error;
+               goto err_kfree;
 
        table = genl_dereference(dp->table);
        flow = ovs_flow_tbl_lookup(table, &key, key_len);
        if (!flow) {
-               struct sw_flow_actions *acts;
-
                /* Bail out if we're not allowed to create a new flow. */
                error = -ENOENT;
                if (info->genlhdr->cmd == OVS_FLOW_CMD_SET)
-                       goto error;
+                       goto err_kfree;
 
                /* Expand table, if necessary, to make room. */
                if (ovs_flow_tbl_need_to_expand(table)) {
@@ -1094,15 +1332,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                flow = ovs_flow_alloc();
                if (IS_ERR(flow)) {
                        error = PTR_ERR(flow);
-                       goto error;
+                       goto err_kfree;
                }
                clear_stats(flow);
 
-               /* Obtain actions. */
-               acts = ovs_flow_actions_alloc(a[OVS_FLOW_ATTR_ACTIONS]);
-               error = PTR_ERR(acts);
-               if (IS_ERR(acts))
-                       goto error_free_flow;
                rcu_assign_pointer(flow->sf_acts, acts);
 
                /* Put flow in bucket. */
@@ -1114,7 +1347,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        } else {
                /* We found a matching flow. */
                struct sw_flow_actions *old_acts;
-               struct nlattr *acts_attrs;
 
                /* Bail out if we're not allowed to modify an existing flow.
                 * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
@@ -1125,26 +1357,13 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                error = -EEXIST;
                if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW &&
                    info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL))
-                       goto error;
+                       goto err_kfree;
 
                /* Update actions. */
                old_acts = rcu_dereference_protected(flow->sf_acts,
                                                     lockdep_genl_is_held());
-               acts_attrs = a[OVS_FLOW_ATTR_ACTIONS];
-               if (acts_attrs &&
-                  (old_acts->actions_len != nla_len(acts_attrs) ||
-                  memcmp(old_acts->actions, nla_data(acts_attrs),
-                         old_acts->actions_len))) {
-                       struct sw_flow_actions *new_acts;
-
-                       new_acts = ovs_flow_actions_alloc(acts_attrs);
-                       error = PTR_ERR(new_acts);
-                       if (IS_ERR(new_acts))
-                               goto error;
-
-                       rcu_assign_pointer(flow->sf_acts, new_acts);
-                       ovs_flow_deferred_free_acts(old_acts);
-               }
+               rcu_assign_pointer(flow->sf_acts, acts);
+               ovs_flow_deferred_free_acts(old_acts);
 
                reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
                                               info->snd_seq, OVS_FLOW_CMD_NEW);
@@ -1166,8 +1385,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                                ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
        return 0;
 
-error_free_flow:
-       ovs_flow_free(flow);
+err_kfree:
+       kfree(acts);
 error:
        return error;
 }
index 4cded77..d05d0f1 100644 (file)
@@ -200,20 +200,18 @@ void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb)
        spin_unlock(&flow->lock);
 }
 
-struct sw_flow_actions *ovs_flow_actions_alloc(const struct nlattr *actions)
+struct sw_flow_actions *ovs_flow_actions_alloc(int size)
 {
-       int actions_len = nla_len(actions);
        struct sw_flow_actions *sfa;
 
-       if (actions_len > MAX_ACTIONS_BUFSIZE)
+       if (size > MAX_ACTIONS_BUFSIZE)
                return ERR_PTR(-EINVAL);
 
-       sfa = kmalloc(sizeof(*sfa) + actions_len, GFP_KERNEL);
+       sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
        if (!sfa)
                return ERR_PTR(-ENOMEM);
 
-       sfa->actions_len = actions_len;
-       memcpy(sfa->actions, nla_data(actions), actions_len);
+       sfa->actions_len = 0;
        return sfa;
 }
 
@@ -848,7 +846,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
        [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6),
        [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp),
        [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd),
-       [OVS_KEY_ATTR_IPV4_TUNNEL] = sizeof(struct ovs_key_ipv4_tunnel),
+       [OVS_KEY_ATTR_TUNNEL] = -1,
 
        /* Not upstream. */
        [OVS_KEY_ATTR_TUN_ID] = sizeof(__be64),
@@ -989,6 +987,105 @@ static int parse_flow_nlattrs(const struct nlattr *attr,
        return 0;
 }
 
+int ipv4_tun_from_nlattr(const struct nlattr *attr,
+                        struct ovs_key_ipv4_tunnel *tun_key)
+{
+       struct nlattr *a;
+       int rem;
+       bool ttl = false;
+
+       memset(tun_key, 0, sizeof(*tun_key));
+
+       nla_for_each_nested(a, attr, rem) {
+               int type = nla_type(a);
+               static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
+                       [OVS_TUNNEL_KEY_ATTR_ID] = sizeof(u64),
+                       [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = sizeof(u32),
+                       [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = sizeof(u32),
+                       [OVS_TUNNEL_KEY_ATTR_TOS] = 1,
+                       [OVS_TUNNEL_KEY_ATTR_TTL] = 1,
+                       [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,
+                       [OVS_TUNNEL_KEY_ATTR_CSUM] = 0,
+               };
+
+               if (type > OVS_TUNNEL_KEY_ATTR_MAX ||
+                       ovs_tunnel_key_lens[type] != nla_len(a))
+                       return -EINVAL;
+
+               switch (type) {
+               case OVS_TUNNEL_KEY_ATTR_ID:
+                       tun_key->tun_id = nla_get_be64(a);
+                       tun_key->tun_flags |= OVS_TNL_F_KEY;
+                       break;
+               case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
+                       tun_key->ipv4_src = nla_get_be32(a);
+                       break;
+               case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
+                       tun_key->ipv4_dst = nla_get_be32(a);
+                       break;
+               case OVS_TUNNEL_KEY_ATTR_TOS:
+                       tun_key->ipv4_tos = nla_get_u8(a);
+                       break;
+               case OVS_TUNNEL_KEY_ATTR_TTL:
+                       tun_key->ipv4_ttl = nla_get_u8(a);
+                       ttl = true;
+                       break;
+               case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
+                       tun_key->tun_flags |= OVS_TNL_F_DONT_FRAGMENT;
+                       break;
+               case OVS_TUNNEL_KEY_ATTR_CSUM:
+                       tun_key->tun_flags |= OVS_TNL_F_CSUM;
+                       break;
+               default:
+                       return -EINVAL;
+
+               }
+       }
+       if (rem > 0)
+               return -EINVAL;
+
+       if (!tun_key->ipv4_dst)
+               return -EINVAL;
+
+       if (!ttl)
+               return -EINVAL;
+
+       return 0;
+}
+
+int ipv4_tun_to_nlattr(struct sk_buff *skb,
+                       const struct ovs_key_ipv4_tunnel *tun_key)
+{
+       struct nlattr *nla;
+
+       nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL);
+       if (!nla)
+               return -EMSGSIZE;
+
+       if (tun_key->tun_flags & OVS_TNL_F_KEY &&
+           nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, tun_key->tun_id))
+               return -EMSGSIZE;
+       if (tun_key->ipv4_src &&
+           nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, tun_key->ipv4_src))
+               return -EMSGSIZE;
+       if (nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tun_key->ipv4_dst))
+               return -EMSGSIZE;
+       if (tun_key->ipv4_tos &&
+           nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, tun_key->ipv4_tos))
+               return -EMSGSIZE;
+       if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, tun_key->ipv4_ttl))
+               return -EMSGSIZE;
+       if ((tun_key->tun_flags & OVS_TNL_F_DONT_FRAGMENT) &&
+               nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT))
+               return -EMSGSIZE;
+       if ((tun_key->tun_flags & OVS_TNL_F_CSUM) &&
+               nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
+               return -EMSGSIZE;
+
+       nla_nest_end(skb, nla);
+       return 0;
+}
+
 /**
  * ovs_flow_from_nlattrs - parses Netlink attributes into a flow key.
  * @swkey: receives the extracted flow key.
@@ -1037,41 +1134,29 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
        }
 
        if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) &&
-           attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
-               struct ovs_key_ipv4_tunnel *tun_key;
+           attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
                __be64 tun_id;
 
-               tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
+               err = ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->phy.tun.tun_key);
+               if (err)
+                       return err;
 
-               if (!tun_key->ipv4_dst)
-                       return -EINVAL;
-               if (!(tun_key->tun_flags & OVS_TNL_F_KEY))
+               if (!(swkey->phy.tun.tun_key.tun_flags & OVS_TNL_F_KEY))
                        return -EINVAL;
 
                tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
-               if (tun_id != tun_key->tun_id)
+               if (tun_id != swkey->phy.tun.tun_key.tun_id)
                        return -EINVAL;
 
-               memcpy(&swkey->phy.tun.tun_key, tun_key,
-                       sizeof(swkey->phy.tun.tun_key));
-               memset(swkey->phy.tun.tun_key.pad, 0,
-                       sizeof(swkey->phy.tun.tun_key.pad));
-
                attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
-       } else if (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
-               struct ovs_key_ipv4_tunnel *tun_key;
-               tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
-
-               if (!tun_key->ipv4_dst)
-                       return -EINVAL;
+               attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL);
+       } else if (attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
 
-               memcpy(&swkey->phy.tun.tun_key, tun_key,
-                       sizeof(swkey->phy.tun.tun_key));
-               memset(swkey->phy.tun.tun_key.pad, 0,
-                       sizeof(swkey->phy.tun.tun_key.pad));
+               err = ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->phy.tun.tun_key);
+               if (err)
+                       return err;
 
-               attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
+               attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL);
        }
 
        /* Data attributes. */
@@ -1227,6 +1312,8 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
                int type = nla_type(nla);
 
                if (type <= OVS_KEY_ATTR_MAX && ovs_key_lens[type] > 0) {
+                       int err;
+
                        if (nla_len(nla) != ovs_key_lens[type])
                                return -EINVAL;
 
@@ -1250,21 +1337,23 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
 
                                break;
 
-                       case OVS_KEY_ATTR_IPV4_TUNNEL:
+                       case OVS_KEY_ATTR_TUNNEL:
                                if (tun_key->tun_flags & OVS_TNL_F_KEY) {
                                        tun_id = tun_key->tun_id;
+                                       err = ipv4_tun_from_nlattr(nla, tun_key);
+                                       if (err)
+                                               return err;
 
-                                       memcpy(tun_key, nla_data(nla), sizeof(*tun_key));
                                        if (!(tun_key->tun_flags & OVS_TNL_F_KEY))
                                                return -EINVAL;
 
                                        if (tun_key->tun_id != tun_id)
                                                return -EINVAL;
-                               } else
-                                       memcpy(tun_key, nla_data(nla), sizeof(*tun_key));
-
-                               if (!tun_key->ipv4_dst)
-                                       return -EINVAL;
+                               } else {
+                                       err = ipv4_tun_from_nlattr(nla, tun_key);
+                                       if (err)
+                                               return err;
+                               }
                                break;
 
                        case OVS_KEY_ATTR_IN_PORT:
@@ -1301,14 +1390,10 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
            nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority))
                goto nla_put_failure;
 
-       if (swkey->phy.tun.tun_key.ipv4_dst) {
-               struct ovs_key_ipv4_tunnel *tun_key;
-               nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4_TUNNEL, sizeof(*tun_key));
-               if (!nla)
-                       goto nla_put_failure;
-               tun_key = nla_data(nla);
-               memcpy(tun_key, &swkey->phy.tun.tun_key, sizeof(*tun_key));
-       }
+       if (swkey->phy.tun.tun_key.ipv4_dst &&
+           ipv4_tun_to_nlattr(skb, &swkey->phy.tun.tun_key))
+               goto nla_put_failure;
+
        if ((swkey->phy.tun.tun_key.tun_flags & OVS_TNL_F_KEY) &&
            nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->phy.tun.tun_key.tun_id))
                goto nla_put_failure;
index f97ec08..657d01e 100644 (file)
@@ -40,6 +40,20 @@ struct sw_flow_actions {
        struct nlattr actions[];
 };
 
+/* Tunnel flow flags. */
+#define OVS_TNL_F_DONT_FRAGMENT                (1 << 0)
+#define OVS_TNL_F_CSUM                 (1 << 1)
+#define OVS_TNL_F_KEY                  (1 << 2)
+
+struct ovs_key_ipv4_tunnel {
+       __be64 tun_id;
+       __be32 ipv4_src;
+       __be32 ipv4_dst;
+       u16  tun_flags;
+       u8   ipv4_tos;
+       u8   ipv4_ttl;
+};
+
 struct sw_flow_key {
        struct {
                union {
@@ -133,7 +147,7 @@ struct sw_flow *ovs_flow_alloc(void);
 void ovs_flow_deferred_free(struct sw_flow *);
 void ovs_flow_free(struct sw_flow *);
 
-struct sw_flow_actions *ovs_flow_actions_alloc(const struct nlattr *);
+struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len);
 void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
 
 int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
@@ -205,5 +219,9 @@ void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
 
 struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx);
 extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1];
+int ipv4_tun_from_nlattr(const struct nlattr *attr,
+                        struct ovs_key_ipv4_tunnel *tun_key);
+int ipv4_tun_to_nlattr(struct sk_buff *skb,
+                       const struct ovs_key_ipv4_tunnel *tun_key);
 
 #endif /* flow.h */
index cd252f4..c268057 100644 (file)
@@ -199,7 +199,6 @@ static inline void tnl_tun_key_init(struct ovs_key_ipv4_tunnel *tun_key,
        tun_key->ipv4_tos = iph->tos;
        tun_key->ipv4_ttl = iph->ttl;
        tun_key->tun_flags = tun_flags;
-       memset(tun_key->pad, 0, sizeof(tun_key->pad));
 }
 
 static inline void tnl_get_param(const struct tnl_mutable_config *mutable,
index e7d4b49..adc7fa3 100644 (file)
@@ -281,13 +281,30 @@ enum ovs_key_attr {
        OVS_KEY_ATTR_ARP,       /* struct ovs_key_arp */
        OVS_KEY_ATTR_ND,        /* struct ovs_key_nd */
        OVS_KEY_ATTR_SKB_MARK,  /* u32 skb mark */
+       OVS_KEY_ATTR_TUNNEL,    /* Nested set of ovs_tunnel attributes */
+
+#ifdef __KERNEL__
        OVS_KEY_ATTR_IPV4_TUNNEL,  /* struct ovs_key_ipv4_tunnel */
+#endif
        OVS_KEY_ATTR_TUN_ID = 63,  /* be64 tunnel ID */
        __OVS_KEY_ATTR_MAX
 };
 
 #define OVS_KEY_ATTR_MAX (__OVS_KEY_ATTR_MAX - 1)
 
+enum ovs_tunnel_key_attr {
+       OVS_TUNNEL_KEY_ATTR_ID,                 /* be64 Tunnel ID */
+       OVS_TUNNEL_KEY_ATTR_IPV4_SRC,           /* be32 src IP address. */
+       OVS_TUNNEL_KEY_ATTR_IPV4_DST,           /* be32 dst IP address. */
+       OVS_TUNNEL_KEY_ATTR_TOS,                /* u8 Tunnel IP ToS. */
+       OVS_TUNNEL_KEY_ATTR_TTL,                /* u8 Tunnel IP TTL. */
+       OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT,      /* No argument, set DF. */
+       OVS_TUNNEL_KEY_ATTR_CSUM,               /* No argument. CSUM packet. */
+       __OVS_TUNNEL_KEY_ATTR_MAX
+};
+
+#define OVS_TUNNEL_KEY_ATTR_MAX (__OVS_TUNNEL_KEY_ATTR_MAX - 1)
+
 /**
  * enum ovs_frag_type - IPv4 and IPv6 fragment type
  * @OVS_FRAG_TYPE_NONE: Packet is not a fragment.
@@ -364,21 +381,6 @@ struct ovs_key_nd {
        __u8  nd_tll[6];
 };
 
-/* Values for ovs_key_ipv4_tunnel->tun_flags */
-#define OVS_TNL_F_DONT_FRAGMENT (1 << 0)
-#define OVS_TNL_F_CSUM (1 << 1)
-#define OVS_TNL_F_KEY (1 << 2)
-
-struct ovs_key_ipv4_tunnel {
-       __be64 tun_id;
-       __u32  tun_flags;
-       __be32 ipv4_src;
-       __be32 ipv4_dst;
-       __u8   ipv4_tos;
-       __u8   ipv4_ttl;
-       __u8   pad[2];
-};
-
 /**
  * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
  * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
index ff5e187..5b93580 100644 (file)
@@ -1180,7 +1180,7 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
     case OVS_KEY_ATTR_TUN_ID:
     case OVS_KEY_ATTR_PRIORITY:
     case OVS_KEY_ATTR_SKB_MARK:
-    case OVS_KEY_ATTR_IPV4_TUNNEL:
+    case OVS_KEY_ATTR_TUNNEL:
         /* not implemented */
         break;
 
index 2a23f1f..c4f2be8 100644 (file)
@@ -95,7 +95,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr)
     case OVS_KEY_ATTR_PRIORITY: return "skb_priority";
     case OVS_KEY_ATTR_SKB_MARK: return "skb_mark";
     case OVS_KEY_ATTR_TUN_ID: return "tun_id";
-    case OVS_KEY_ATTR_IPV4_TUNNEL: return "ipv4_tunnel";
+    case OVS_KEY_ATTR_TUNNEL: return "tunnel";
     case OVS_KEY_ATTR_IN_PORT: return "in_port";
     case OVS_KEY_ATTR_ETHERNET: return "eth";
     case OVS_KEY_ATTR_VLAN: return "vlan";
@@ -617,7 +617,7 @@ odp_flow_key_attr_len(uint16_t type)
     case OVS_KEY_ATTR_PRIORITY: return 4;
     case OVS_KEY_ATTR_SKB_MARK: return 4;
     case OVS_KEY_ATTR_TUN_ID: return 8;
-    case OVS_KEY_ATTR_IPV4_TUNNEL: return sizeof(struct ovs_key_ipv4_tunnel);
+    case OVS_KEY_ATTR_TUNNEL: return -2;
     case OVS_KEY_ATTR_IN_PORT: return 4;
     case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet);
     case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16);
@@ -672,19 +672,109 @@ ovs_frag_type_to_string(enum ovs_frag_type type)
     }
 }
 
-static const char *
-odp_tun_flag_to_string(uint32_t flags)
+static int
+tunnel_key_attr_len(int type)
 {
-    switch (flags) {
-    case OVS_TNL_F_DONT_FRAGMENT:
-        return "df";
-    case OVS_TNL_F_CSUM:
-        return "csum";
-    case OVS_TNL_F_KEY:
-        return "key";
-    default:
-        return NULL;
+    switch (type) {
+    case OVS_TUNNEL_KEY_ATTR_ID: return 8;
+    case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: return 4;
+    case OVS_TUNNEL_KEY_ATTR_IPV4_DST: return 4;
+    case OVS_TUNNEL_KEY_ATTR_TOS: return 1;
+    case OVS_TUNNEL_KEY_ATTR_TTL: return 1;
+    case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: return 0;
+    case OVS_TUNNEL_KEY_ATTR_CSUM: return 0;
+    case __OVS_TUNNEL_KEY_ATTR_MAX:
+        return -1;
     }
+    return -1;
+}
+
+static enum odp_key_fitness
+tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun)
+{
+    unsigned int left;
+    const struct nlattr *a;
+    bool ttl = false;
+    bool unknown = false;
+
+    NL_NESTED_FOR_EACH(a, left, attr) {
+        uint16_t type = nl_attr_type(a);
+        size_t len = nl_attr_get_size(a);
+        int expected_len = tunnel_key_attr_len(type);
+
+        if (len != expected_len && expected_len >= 0) {
+            return ODP_FIT_ERROR;
+        }
+
+        switch (type) {
+        case OVS_TUNNEL_KEY_ATTR_ID:
+            tun->tun_id = nl_attr_get_be64(a);
+            tun->flags |= FLOW_TNL_F_KEY;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
+            tun->ip_src = nl_attr_get_be32(a);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
+            tun->ip_dst = nl_attr_get_be32(a);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TOS:
+            tun->ip_tos = nl_attr_get_u8(a);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TTL:
+            tun->ip_ttl = nl_attr_get_u8(a);
+            ttl = true;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
+            tun->flags |= FLOW_TNL_F_DONT_FRAGMENT;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_CSUM:
+            tun->flags |= FLOW_TNL_F_CSUM;
+            break;
+        default:
+            /* Allow this to show up as unexpected, if there are unknown
+             * tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */
+            unknown = true;
+            break;
+        }
+    }
+
+    if (!ttl) {
+        return ODP_FIT_ERROR;
+    }
+    if (unknown) {
+            return ODP_FIT_TOO_MUCH;
+    }
+    return ODP_FIT_PERFECT;
+}
+
+static void
+tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key)
+{
+    size_t tun_key_ofs;
+
+    tun_key_ofs = nl_msg_start_nested(a, OVS_KEY_ATTR_TUNNEL);
+
+    if (tun_key->flags & FLOW_TNL_F_KEY) {
+        nl_msg_put_be64(a, OVS_TUNNEL_KEY_ATTR_ID, tun_key->tun_id);
+    }
+    if (tun_key->ip_src) {
+        nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, tun_key->ip_src);
+    }
+    if (tun_key->ip_dst) {
+        nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tun_key->ip_dst);
+    }
+    if (tun_key->ip_tos) {
+        nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_TOS, tun_key->ip_tos);
+    }
+    nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_TTL, tun_key->ip_ttl);
+    if (tun_key->flags & FLOW_TNL_F_DONT_FRAGMENT) {
+        nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT);
+    }
+    if (tun_key->flags & FLOW_TNL_F_CSUM) {
+        nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_CSUM);
+    }
+
+    nl_msg_end_nested(a, tun_key_ofs);
 }
 
 static void
@@ -699,7 +789,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
     const struct ovs_key_icmpv6 *icmpv6_key;
     const struct ovs_key_arp *arp_key;
     const struct ovs_key_nd *nd_key;
-    const struct ovs_key_ipv4_tunnel *ipv4_tun_key;
+    struct flow_tnl tun_key;
     enum ovs_key_attr attr = nl_attr_type(a);
     int expected_len;
 
@@ -734,18 +824,23 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
         ds_put_format(ds, "(%#"PRIx64")", ntohll(nl_attr_get_be64(a)));
         break;
 
-    case OVS_KEY_ATTR_IPV4_TUNNEL:
-        ipv4_tun_key = nl_attr_get(a);
-        ds_put_format(ds, "(tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT","
-                      "tos=0x%"PRIx8",ttl=%"PRIu8",flags(",
-                      ntohll(ipv4_tun_key->tun_id),
-                      IP_ARGS(&ipv4_tun_key->ipv4_src),
-                      IP_ARGS(&ipv4_tun_key->ipv4_dst),
-                      ipv4_tun_key->ipv4_tos, ipv4_tun_key->ipv4_ttl);
-
-        format_flags(ds, odp_tun_flag_to_string,
-                     ipv4_tun_key->tun_flags, ',');
-        ds_put_format(ds, "))");
+    case OVS_KEY_ATTR_TUNNEL:
+        memset(&tun_key, 0, sizeof tun_key);
+        if (tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) {
+            ds_put_format(ds, "(error)");
+        } else {
+            ds_put_format(ds, "(tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT","
+                          "tos=0x%"PRIx8",ttl=%"PRIu8",flags(",
+                          ntohll(tun_key.tun_id),
+                          IP_ARGS(&tun_key.ip_src),
+                          IP_ARGS(&tun_key.ip_dst),
+                          tun_key.ip_tos, tun_key.ip_ttl);
+
+            format_flags(ds, flow_tun_flag_to_string,
+                         (uint32_t) tun_key.flags, ',');
+            ds_put_format(ds, "))");
+        }
+
         break;
 
     case OVS_KEY_ATTR_IN_PORT:
@@ -974,23 +1069,24 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
     {
         char tun_id_s[32];
         int tos, ttl;
-        struct ovs_key_ipv4_tunnel tun_key;
+        struct flow_tnl tun_key;
         int n = -1;
 
-        if (sscanf(s, "ipv4_tunnel(tun_id=%31[x0123456789abcdefABCDEF],"
+        if (sscanf(s, "tunnel(tun_id=%31[x0123456789abcdefABCDEF],"
                    "src="IP_SCAN_FMT",dst="IP_SCAN_FMT
                    ",tos=%i,ttl=%i,flags%n", tun_id_s,
-                    IP_SCAN_ARGS(&tun_key.ipv4_src),
-                    IP_SCAN_ARGS(&tun_key.ipv4_dst), &tos, &ttl,
+                    IP_SCAN_ARGS(&tun_key.ip_src),
+                    IP_SCAN_ARGS(&tun_key.ip_dst), &tos, &ttl,
                     &n) > 0 && n > 0) {
             int res;
+            uint32_t flags;
 
             tun_key.tun_id = htonll(strtoull(tun_id_s, NULL, 0));
-            tun_key.ipv4_tos = tos;
-            tun_key.ipv4_ttl = ttl;
+            tun_key.ip_tos = tos;
+            tun_key.ip_ttl = ttl;
+            res = parse_flags(&s[n], flow_tun_flag_to_string, &flags);
+            tun_key.flags = (uint16_t) flags;
 
-            res = parse_flags(&s[n], odp_tun_flag_to_string,
-                              &tun_key.tun_flags);
             if (res < 0) {
                 return res;
             }
@@ -999,10 +1095,7 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
                 return -EINVAL;
             }
             n++;
-
-            memset(&tun_key.pad, 0, sizeof tun_key.pad);
-            nl_msg_put_unspec(key, OVS_KEY_ATTR_IPV4_TUNNEL, &tun_key,
-                              sizeof tun_key);
+            tun_key_to_attr(key, &tun_key);
             return n;
         }
     }
index 43b79d6..863eb84 100644 (file)
@@ -92,9 +92,8 @@ push_vlan(tpid=0x9100,vid=13,pcp=5)
 push_vlan(tpid=0x9100,vid=13,pcp=5,cfi=0)
 pop_vlan
 sample(sample=9.7%,actions(1,2,3,push_vlan(vid=1,pcp=2)))
-set(ipv4_tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags(df,csum,key)))
-set(ipv4_tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags(df,csum,key,0x20)))
-set(ipv4_tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags()))
+set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags(df,csum,key)))
+set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags(key)))
 ])
 AT_CHECK_UNQUOTED([test-odp parse-actions < actions.txt], [0],
   [`cat actions.txt`