[ovs-dev] [PATCH] datapath: Refactor actions in terms of match fields.

Pravin Shelar pshelar at nicira.com
Wed Oct 19 00:50:58 UTC 2011


On Tue, Oct 18, 2011 at 3:47 PM, Jesse Gross <jesse at nicira.com> wrote:
> On Thu, Oct 13, 2011 at 3:23 PM, Pravin B Shelar <pshelar at nicira.com> wrote:
>> Almost all current actions can be expressed in the form of
>> push/pop/set <field>, where field is one of the match fields. We can
>> create three base actions and take a field. This has both a nice
>> symmetry and avoids inconsistencies where we can match on the vlan
>> TPID but not set it.
>> Following patch converts all actions to this new format.
>>
>> Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
>> Bug #7115
>
> Overall, this looks pretty good to me.  I have a few miscellaneous
> comments but in general I like the structure of it.  Ben, can you take
> a look at it as well (although you might as well wait until Pravin has
> had a chance to address my comments here)?
>
>> diff --git a/datapath/actions.c b/datapath/actions.c
>> index a28e986..c348daa 100644
>> --- a/datapath/actions.c
>> +++ b/datapath/actions.c
>> @@ -99,6 +99,8 @@ static int pop_vlan(struct sk_buff *skb)
>>
>>  static int push_vlan(struct sk_buff *skb, __be16 new_tci)
>>  {
>> +       new_tci &= ~htons(VLAN_CFI_MASK);
>
> It's better to use VLAN_TAG_PRESENT instead of VLAN_CFI_MASK.  They
> have the same value but the former better indicates why you're doing
> it.
>
> However, looking at the flow setup code more closely, I now see that I
> misled you here - we actually don't set VLAN_TAG_PRESENT in the
> communication between userspace and kernel - it's instead implied by
> the presence of the Netlink attribute.  Both sides use this convention
> internally but it is masked out when serializing the data.
>
> Given that, I would mask it out in userspace and then add a check to
> the validation code for it.
>
ok,
>> diff --git a/datapath/datapath.c b/datapath/datapath.c
>> index b3e2442..f520502 100644
>> --- a/datapath/datapath.c
>> +++ b/datapath/datapath.c
>> +static int validate_set_actions(const struct nlattr *ovs_key,
>> +               const struct sw_flow_key *flow_key)
>> +{
> [...]
>> +       default:
>> +               return -EOPNOTSUPP;
>
> I think it's better to just return -EINVAL here (and in the main
> validation_actions() function as well).  Otherwise you end up with
> different error codes when trying to set an IPv4 protocol type vs. an
> IPv6 type.
>
ok

>> diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
>> index c077f62..2bc7a00 100644
>> --- a/include/linux/openvswitch.h
>> +++ b/include/linux/openvswitch.h
>> +/**
>> + * OVS datapath actions are expressed using enum ovs_action_type and enum
>> + * ovs_key_type.  enum ovs_action_type is like base action and ovs_key_type
>> + * specifies which field to act on.  i.e. push/pop/set <field>.
>> + * E.g. @OVS_ACTION_ATTR_SET could have nested netlink attribute of type
>> + * %OVS_KEY_ATTR_TUN_ID, %OVS_KEY_ATTR_ETHERNET, %OVS_KEY_ATTR_IPV4,
>> + * %OVS_KEY_ATTR_TCP or %OVS_KEY_ATTR_UDP.
>> + */
>
> I found this comment somewhat confusing to read.  Maybe you could just
> give a single example of what an action would look like instead of
> talking about the two pieces separately?
>
ok
>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>> index 9967322..05f72e3 100644
>> --- a/lib/dpif-netdev.c
>> +++ b/lib/dpif-netdev.c
>> +dp_netdev_set_udp_port(struct ofpbuf *packet, const struct flow *flow,
>> +                       const struct ovs_key_udp *udp_key)
>> +{
>> +    /* Check for trasport header. */
>> +    if (packet->l7 && flow->nw_proto == IPPROTO_UDP) {
>
> I don't think any of the tests of this form (with the exception of the
> pseudoheader changing when the IP address changes) are necessary
> because the main userspace should be able to tell whether the packet
> headers are valid or not.  If it doesn't then when used with the
> kernel module the flows will be rejected.
>
ok

>> +static void
>>  dp_netdev_execute_actions(struct dp_netdev *dp,
>>                           struct ofpbuf *packet, struct flow *key,
>>                           const struct nlattr *actions,
> [...]
>> -        case OVS_ACTION_ATTR_SET_TUNNEL:
>
> You need to still include this in execute_set_action() as a no-op
> because it's still possible for the set_tunnel OpenFlow command to be
> used in this case.  When used without a tunnel (as is always the case
> here), there's no effect but after this patch it will cause an
> assertion failure.

right, i missed it.
>

>> diff --git a/lib/netlink.c b/lib/netlink.c
>> index b4de3ed..f90a0de 100644
>> --- a/lib/netlink.c
>> +++ b/lib/netlink.c
>> @@ -333,6 +333,18 @@ nl_msg_put_nested(struct ofpbuf *msg,
>>     nl_msg_end_nested(msg, offset);
>>  }
>>
>> +void
>> +nl_msg_put_nested_attr(struct ofpbuf *odp_actions, uint16_t type,
>> +                       uint16_t n_type, const void *n_data, size_t n_size)
>
> Where does the n_ prefix come from?  It's somewhat confusing because
> it's usually used for number of X.  I think this function doesn't
> really belong in netlink.c since it's not generic code but is actually
> specific to inserting actions.
>
ok, I will move it to ofproo-dpif.

>> +    void *attr;
>> +
>> +    attr = nl_msg_put_unspec_uninit(odp_actions, n_type, n_size);
>> +    memcpy(attr, n_data, n_size);
>
> I think you can use nl_msg_put_unspec() in place of these three lines.
>
ok

>> diff --git a/lib/odp-util.c b/lib/odp-util.c
>> index a471099..042a1d5 100644
>> --- a/lib/odp-util.c
>> +++ b/lib/odp-util.c
>> +static void
>>  format_odp_action(struct ds *ds, const struct nlattr *a)
>>  {
> [...]
>> +    case OVS_ACTION_ATTR_POP:
>> +        if (nl_attr_get_u16(a) == OVS_KEY_ATTR_8021Q)
>> +            ds_put_cstr(ds, "pop_vlan");
>
> For consistency can we use "pop(vlan)"?
>
ok
>> +        else
>> +            ds_put_format(ds, "pop(%"PRIu16")", nl_attr_get_u16(a));
>
> When we format unknown actions in other places we use the prefix "key"
> as in "pop(key%"PRIu16")".
>
>> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
>> index 8e5a863..0ada375 100644
>> --- a/ofproto/ofproto-dpif.c
>> +++ b/ofproto/ofproto-dpif.c
>> +static void
>> +commit_set_nw_action(const struct flow *flow, struct flow *base,
>> +                     struct ofpbuf *odp_actions)
>> +{
>> +    struct ovs_key_ipv4 ipv4_key;
>>
>> -    if (base->nw_dst != flow->nw_dst) {
>> -        nl_msg_put_be32(odp_actions, OVS_ACTION_ATTR_SET_NW_DST, flow->nw_dst);
>> -        base->nw_dst = flow->nw_dst;
>> +    if (flow->dl_type != htons(ETH_TYPE_IP) ||
>> +        !flow->nw_src || !flow->nw_src ) {
>
> I think that second comparison should be nw_dst.  There's also an
> extra space before the last parenthesis.
>
>> +static void
>> +commit_set_port_action(const struct flow *flow, struct flow *base,
>> +                       struct ofpbuf *odp_actions)
>> +{
>> +    if (!flow->tp_src || !flow->tp_src) {
>
> Another src || src.
>
>> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
>> index b5ca08c..13c1435 100644
>> --- a/tests/ofproto-dpif.at
>> +++ b/tests/ofproto-dpif.at
>> @@ -75,7 +75,7 @@ in_port=5 actions=set_tunnel:5
>>  AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
>>  AT_CHECK([ovs-appctl -t test-openflowd ofproto/trace br0 'tun_id(0x1),in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0),icmp(type=8,code=0)'], [0], [stdout])
>>  AT_CHECK([tail -1 stdout], [0],
>> -  [Datapath actions: set_tunnel(0x1),1,2,set_tunnel(0x3),3,4
>> +  [Datapath actions: set(tun_id(0x1)),1,2,set(tun_id(0x3)),3,4
>
> You also need to update test 387: ofproto-dpif.at:83 ofproto-dpif -
> VLAN handling to account for the changed output.
>
right, vlan test was skipped in my make check.



More information about the dev mailing list