[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openvswitch-discuss
Subject:    [ovs-discuss] [ACLv2 11/19] flow: Decouple datapath flow structure from userspace flow.
From:       blp () nicira ! com (Ben Pfaff)
Date:       2009-08-25 23:10:34
Message-ID: 87my5nwkut.fsf () blp ! benpfaff ! org
[Download RAW message or body]

Jesse Gross <jesse at nicira.com> writes:

> Components of certain flows can only be matched in userspace.
> Previously the datapath and userspace shared the same structure
> for describing flows.  This seperates that structure to allow for
> additional components to be added to the userspace version.

"separates" has two "a"s (sorry, pet peeve).

First, thank you for separating the kernel and userspace flow
structures.  I knew that this would need to be done eventually.
That's the main reason that I invented flow_t, in fact: because I
knew that the userspace structure should be different from the
kernel structure, and yet I didn't want to create a new "struct"
and have to deal with copying back and forth yet.

Let's look at the actual flow structure first

> -typedef struct odp_flow_key flow_t;
> +struct userspace_flow {
> +    union {
> +        struct {
> +            uint32_t nw_src;            /* IP source address. */
> +            uint32_t nw_dst;            /* IP destination address. */
> +            uint16_t in_port;           /* Input switch port. */
> +            uint16_t dl_vlan;           /* Input VLAN. */
> +            uint16_t dl_type;           /* Ethernet frame type. */
> +            uint16_t tp_src;            /* TCP/UDP source port. */
> +            uint16_t tp_dst;            /* TCP/UDP destination port. */
> +            uint8_t  dl_src[ETH_ALEN];  /* Ethernet source address. */
> +            uint8_t  dl_dst[ETH_ALEN];  /* Ethernet destination address. */
> +            uint8_t  nw_proto;          /* IP protocol. */
> +            uint8_t  reserved;          /* Pad to 64 bits. */
> +        };
> +        struct odp_flow_key odp;
> +    };
> +};
> +
> +typedef struct userspace_flow flow_t;

Is there a reason for putting an anonymous union inside the
struct?  I think that you could drop the outer struct entirely
and just call this "union userspace_flow".  --Actually, never
mind, I see that you add members to the outer struct in a later
commit.  That makes sense.

But: what's the motivation for the union?  I don't quite follow.
What does a flow_t represent?  If I have a flow_t, then what do I
really have?

How attached are you to the name "userspace_flow"?  I'd prefer
"struct ovs_flow" or just "struct flow" myself.  They are just as
descriptive, I think, and much shorter.

Over time I'd prefer to migrate away from the flow_t typedef to
the actual struct name.  No rush though.

> +    flow_from_odp(key, &userspace_flow);
>      HMAP_FOR_EACH_WITH_HASH (flow, struct dp_netdev_flow, node,
> -                             flow_hash(key, 0), &dp->flow_table) {
> -        if (flow_equal(&flow->key, key)) {
> +                             flow_hash(&userspace_flow, 0), &dp->flow_table) {
> +        if (memcmp(&flow->key, key, sizeof *key)) {

Surely that should be !memcmp(...)?

> @@ -791,6 +793,7 @@ add_flow(struct dpif *dpif, struct odp_flow *odp_flow)
>      struct dp_netdev *dp = get_dp_netdev(dpif);
>      struct dp_netdev_flow *flow;
>      int error;
> +    flow_t userspace_flow;
>  
>      flow = xcalloc(1, sizeof *flow);
>      flow->key = odp_flow->key;
> @@ -802,7 +805,8 @@ add_flow(struct dpif *dpif, struct odp_flow *odp_flow)
>          return error;
>      }
>  
> -    hmap_insert(&dp->flow_table, &flow->node, flow_hash(&flow->key, 0));
> +    flow_from_odp(&flow->key, &userspace_flow);
> +    hmap_insert(&dp->flow_table, &flow->node, flow_hash(&userspace_flow, 0));
>      return 0;
>  }
>  

Why is dpif_netdev using flow_t at all?  Logically it fits into
the switch the same as the kernel datapath module, so shouldn't
it just use struct odp_flow_key?  I think that there was a logic
error here originally using flow_t instead of struct
odp_flow_key that we should fix.

> diff --git a/lib/flow.c b/lib/flow.c
> index eaf7036..6952392 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -289,6 +289,13 @@ flow_from_match(flow_t *flow, uint32_t *wildcards,
>      flow->reserved = 0;
>  }
>  
> +void
> +flow_from_odp(const struct odp_flow_key *odp, flow_t *flow)
> +{
> +    memset(flow, 0, sizeof *flow);
> +    flow->odp = *odp;

Did you check whether GCC optimizes this decently?  (It's pretty
bad at optimizing memset() and memcpy().)  If not, most of 'flow'
will end up being initialized twice.

I don't know whether this is a frequent enough operation to
matter.

> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index 672bfe5..578b892 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -1562,10 +1562,16 @@ static struct rule *
>  rule_create_subrule(struct ofproto *ofproto, struct rule *rule,
>                      const flow_t *flow)
>  {
> -    struct rule *subrule = rule_create(rule, NULL, 0,
> -                                       rule->idle_timeout, rule->hard_timeout);
> +    flow_t kernel_flow;
> +    struct rule *subrule;
> +
> +    /* Reduce the flow to only those components that the kernel can match. */
> +    flow_from_odp(&flow->odp, &kernel_flow);

That's confusing: we have a struct userspace_flow (flow_t) named
kernel_flow.  How odd, is everything factored out correctly?


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic