Commit 03f0d916 authored by Andy Zhou's avatar Andy Zhou Committed by Jesse Gross

openvswitch: Mega flow implementation

Add wildcarded flow support in kernel datapath.

Wildcarded flow can improve OVS flow set up performance by avoid sending
matching new flows to the user space program. The exact performance boost
will largely dependent on wildcarded flow hit rate.

In case all new flows hits wildcard flows, the flow set up rate is
within 5% of that of linux bridge module.

Pravin has made significant contributions to this patch. Including API
clean ups and bug fixes.
Signed-off-by: default avatarPravin B Shelar <pshelar@nicira.com>
Signed-off-by: default avatarAndy Zhou <azhou@nicira.com>
Signed-off-by: default avatarJesse Gross <jesse@nicira.com>
parent 3fa34de6
...@@ -91,6 +91,46 @@ Often we ellipsize arguments not important to the discussion, e.g.: ...@@ -91,6 +91,46 @@ Often we ellipsize arguments not important to the discussion, e.g.:
in_port(1), eth(...), eth_type(0x0800), ipv4(...), tcp(...) in_port(1), eth(...), eth_type(0x0800), ipv4(...), tcp(...)
Wildcarded flow key format
--------------------------
A wildcarded flow is described with two sequences of Netlink attributes
passed over the Netlink socket. A flow key, exactly as described above, and an
optional corresponding flow mask.
A wildcarded flow can represent a group of exact match flows. Each '1' bit
in the mask specifies a exact match with the corresponding bit in the flow key.
A '0' bit specifies a don't care bit, which will match either a '1' or '0' bit
of a incoming packet. Using wildcarded flow can improve the flow set up rate
by reduce the number of new flows need to be processed by the user space program.
Support for the mask Netlink attribute is optional for both the kernel and user
space program. The kernel can ignore the mask attribute, installing an exact
match flow, or reduce the number of don't care bits in the kernel to less than
what was specified by the user space program. In this case, variations in bits
that the kernel does not implement will simply result in additional flow setups.
The kernel module will also work with user space programs that neither support
nor supply flow mask attributes.
Since the kernel may ignore or modify wildcard bits, it can be difficult for
the userspace program to know exactly what matches are installed. There are
two possible approaches: reactively install flows as they miss the kernel
flow table (and therefore not attempt to determine wildcard changes at all)
or use the kernel's response messages to determine the installed wildcards.
When interacting with userspace, the kernel should maintain the match portion
of the key exactly as originally installed. This will provides a handle to
identify the flow for all future operations. However, when reporting the
mask of an installed flow, the mask should include any restrictions imposed
by the kernel.
The behavior when using overlapping wildcarded flows is undefined. It is the
responsibility of the user space program to ensure that any incoming packet
can match at most one flow, wildcarded or not. The current implementation
performs best-effort detection of overlapping wildcarded flows and may reject
some but not all of them. However, this behavior may change in future versions.
Basic rule for evolving flow keys Basic rule for evolving flow keys
--------------------------------- ---------------------------------
......
/* /*
* Copyright (c) 2007-2011 Nicira Networks. * Copyright (c) 2007-2013 Nicira, Inc.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public * modify it under the terms of version 2 of the GNU General Public
...@@ -379,6 +379,12 @@ struct ovs_key_nd { ...@@ -379,6 +379,12 @@ struct ovs_key_nd {
* @OVS_FLOW_ATTR_CLEAR: If present in a %OVS_FLOW_CMD_SET request, clears the * @OVS_FLOW_ATTR_CLEAR: If present in a %OVS_FLOW_CMD_SET request, clears the
* last-used time, accumulated TCP flags, and statistics for this flow. * last-used time, accumulated TCP flags, and statistics for this flow.
* Otherwise ignored in requests. Never present in notifications. * Otherwise ignored in requests. Never present in notifications.
* @OVS_FLOW_ATTR_MASK: Nested %OVS_KEY_ATTR_* attributes specifying the
* mask bits for wildcarded flow match. Mask bit value '1' specifies exact
* match with corresponding flow key bit, while mask bit value '0' specifies
* a wildcarded match. Omitting attribute is treated as wildcarding all
* corresponding fields. Optional for all requests. If not present,
* all flow key bits are exact match bits.
* *
* These attributes follow the &struct ovs_header within the Generic Netlink * These attributes follow the &struct ovs_header within the Generic Netlink
* payload for %OVS_FLOW_* commands. * payload for %OVS_FLOW_* commands.
...@@ -391,6 +397,7 @@ enum ovs_flow_attr { ...@@ -391,6 +397,7 @@ enum ovs_flow_attr {
OVS_FLOW_ATTR_TCP_FLAGS, /* 8-bit OR'd TCP flags. */ OVS_FLOW_ATTR_TCP_FLAGS, /* 8-bit OR'd TCP flags. */
OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */ OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */
OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */ OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */
OVS_FLOW_ATTR_MASK, /* Sequence of OVS_KEY_ATTR_* attributes. */
__OVS_FLOW_ATTR_MAX __OVS_FLOW_ATTR_MAX
}; };
......
/* /*
* Copyright (c) 2007-2012 Nicira, Inc. * Copyright (c) 2007-2013 Nicira, Inc.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public * modify it under the terms of version 2 of the GNU General Public
...@@ -376,8 +376,10 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, ...@@ -376,8 +376,10 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *a; const struct nlattr *a;
int rem; int rem;
BUG_ON(!OVS_CB(skb)->pkt_key);
upcall.cmd = OVS_PACKET_CMD_ACTION; upcall.cmd = OVS_PACKET_CMD_ACTION;
upcall.key = &OVS_CB(skb)->flow->key; upcall.key = OVS_CB(skb)->pkt_key;
upcall.userdata = NULL; upcall.userdata = NULL;
upcall.portid = 0; upcall.portid = 0;
......
This diff is collapsed.
...@@ -88,11 +88,13 @@ struct datapath { ...@@ -88,11 +88,13 @@ struct datapath {
/** /**
* struct ovs_skb_cb - OVS data in skb CB * struct ovs_skb_cb - OVS data in skb CB
* @flow: The flow associated with this packet. May be %NULL if no flow. * @flow: The flow associated with this packet. May be %NULL if no flow.
* @pkt_key: The flow information extracted from the packet. Must be nonnull.
* @tun_key: Key for the tunnel that encapsulated this packet. NULL if the * @tun_key: Key for the tunnel that encapsulated this packet. NULL if the
* packet is not being tunneled. * packet is not being tunneled.
*/ */
struct ovs_skb_cb { struct ovs_skb_cb {
struct sw_flow *flow; struct sw_flow *flow;
struct sw_flow_key *pkt_key;
struct ovs_key_ipv4_tunnel *tun_key; struct ovs_key_ipv4_tunnel *tun_key;
}; };
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
...@@ -183,4 +185,8 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq, ...@@ -183,4 +185,8 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq,
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb); int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb);
void ovs_dp_notify_wq(struct work_struct *work); void ovs_dp_notify_wq(struct work_struct *work);
#define OVS_NLERR(fmt, ...) \
pr_info_once("netlink: " fmt, ##__VA_ARGS__)
#endif /* datapath.h */ #endif /* datapath.h */
This diff is collapsed.
/* /*
* Copyright (c) 2007-2011 Nicira, Inc. * Copyright (c) 2007-2013 Nicira, Inc.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public * modify it under the terms of version 2 of the GNU General Public
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <net/inet_ecn.h> #include <net/inet_ecn.h>
struct sk_buff; struct sk_buff;
struct sw_flow_mask;
struct flow_table;
struct sw_flow_actions { struct sw_flow_actions {
struct rcu_head rcu; struct rcu_head rcu;
...@@ -131,6 +133,8 @@ struct sw_flow { ...@@ -131,6 +133,8 @@ struct sw_flow {
u32 hash; u32 hash;
struct sw_flow_key key; struct sw_flow_key key;
struct sw_flow_key unmasked_key;
struct sw_flow_mask *mask;
struct sw_flow_actions __rcu *sf_acts; struct sw_flow_actions __rcu *sf_acts;
spinlock_t lock; /* Lock for values below. */ spinlock_t lock; /* Lock for values below. */
...@@ -140,6 +144,25 @@ struct sw_flow { ...@@ -140,6 +144,25 @@ struct sw_flow {
u8 tcp_flags; /* Union of seen TCP flags. */ u8 tcp_flags; /* Union of seen TCP flags. */
}; };
struct sw_flow_key_range {
size_t start;
size_t end;
};
static inline u16 ovs_sw_flow_key_range_actual_size(const struct sw_flow_key_range *range)
{
return range->end - range->start;
}
struct sw_flow_match {
struct sw_flow_key *key;
struct sw_flow_key_range range;
struct sw_flow_mask *mask;
};
void ovs_match_init(struct sw_flow_match *match,
struct sw_flow_key *key, struct sw_flow_mask *mask);
struct arp_eth_header { struct arp_eth_header {
__be16 ar_hrd; /* format of hardware address */ __be16 ar_hrd; /* format of hardware address */
__be16 ar_pro; /* format of protocol address */ __be16 ar_pro; /* format of protocol address */
...@@ -159,21 +182,21 @@ void ovs_flow_exit(void); ...@@ -159,21 +182,21 @@ void ovs_flow_exit(void);
struct sw_flow *ovs_flow_alloc(void); struct sw_flow *ovs_flow_alloc(void);
void ovs_flow_deferred_free(struct sw_flow *); void ovs_flow_deferred_free(struct sw_flow *);
void ovs_flow_free(struct sw_flow *flow); void ovs_flow_free(struct sw_flow *, bool deferred);
struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len); struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len);
void ovs_flow_deferred_free_acts(struct sw_flow_actions *); void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *, int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *);
int *key_lenp);
void ovs_flow_used(struct sw_flow *, struct sk_buff *); void ovs_flow_used(struct sw_flow *, struct sk_buff *);
u64 ovs_flow_used_time(unsigned long flow_jiffies); u64 ovs_flow_used_time(unsigned long flow_jiffies);
int ovs_flow_to_nlattrs(const struct sw_flow_key *,
int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); const struct sw_flow_key *, struct sk_buff *);
int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, int ovs_match_from_nlattrs(struct sw_flow_match *match,
const struct nlattr *,
const struct nlattr *); const struct nlattr *);
int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow,
const struct nlattr *attr); const struct nlattr *attr);
#define MAX_ACTIONS_BUFSIZE (32 * 1024) #define MAX_ACTIONS_BUFSIZE (32 * 1024)
#define TBL_MIN_BUCKETS 1024 #define TBL_MIN_BUCKETS 1024
...@@ -182,6 +205,7 @@ struct flow_table { ...@@ -182,6 +205,7 @@ struct flow_table {
struct flex_array *buckets; struct flex_array *buckets;
unsigned int count, n_buckets; unsigned int count, n_buckets;
struct rcu_head rcu; struct rcu_head rcu;
struct list_head *mask_list;
int node_ver; int node_ver;
u32 hash_seed; u32 hash_seed;
bool keep_flows; bool keep_flows;
...@@ -197,22 +221,56 @@ static inline int ovs_flow_tbl_need_to_expand(struct flow_table *table) ...@@ -197,22 +221,56 @@ static inline int ovs_flow_tbl_need_to_expand(struct flow_table *table)
return (table->count > table->n_buckets); return (table->count > table->n_buckets);
} }
struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table, struct sw_flow *ovs_flow_lookup(struct flow_table *,
struct sw_flow_key *key, int len); const struct sw_flow_key *);
void ovs_flow_tbl_destroy(struct flow_table *table); struct sw_flow *ovs_flow_lookup_unmasked_key(struct flow_table *table,
void ovs_flow_tbl_deferred_destroy(struct flow_table *table); struct sw_flow_match *match);
void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred);
struct flow_table *ovs_flow_tbl_alloc(int new_size); struct flow_table *ovs_flow_tbl_alloc(int new_size);
struct flow_table *ovs_flow_tbl_expand(struct flow_table *table); struct flow_table *ovs_flow_tbl_expand(struct flow_table *table);
struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table); struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table);
void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
struct sw_flow_key *key, int key_len);
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); void ovs_flow_insert(struct flow_table *table, struct sw_flow *flow);
void ovs_flow_remove(struct flow_table *table, struct sw_flow *flow);
struct sw_flow *ovs_flow_dump_next(struct flow_table *table, u32 *bucket, u32 *idx);
extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1]; extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1];
int ovs_ipv4_tun_from_nlattr(const struct nlattr *attr, int ovs_ipv4_tun_from_nlattr(const struct nlattr *attr,
struct ovs_key_ipv4_tunnel *tun_key); struct sw_flow_match *match, bool is_mask);
int ovs_ipv4_tun_to_nlattr(struct sk_buff *skb, int ovs_ipv4_tun_to_nlattr(struct sk_buff *skb,
const struct ovs_key_ipv4_tunnel *tun_key); const struct ovs_key_ipv4_tunnel *tun_key,
const struct ovs_key_ipv4_tunnel *output);
bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
const struct sw_flow_key *key, int key_len);
struct sw_flow_mask {
int ref_count;
struct rcu_head rcu;
struct list_head list;
struct sw_flow_key_range range;
struct sw_flow_key key;
};
static inline u16
ovs_sw_flow_mask_actual_size(const struct sw_flow_mask *mask)
{
return ovs_sw_flow_key_range_actual_size(&mask->range);
}
static inline u16
ovs_sw_flow_mask_size_roundup(const struct sw_flow_mask *mask)
{
return roundup(ovs_sw_flow_mask_actual_size(mask), sizeof(u32));
}
struct sw_flow_mask *ovs_sw_flow_mask_alloc(void);
void ovs_sw_flow_mask_add_ref(struct sw_flow_mask *);
void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *, bool deferred);
void ovs_sw_flow_mask_insert(struct flow_table *, struct sw_flow_mask *);
struct sw_flow_mask *ovs_sw_flow_mask_find(const struct flow_table *,
const struct sw_flow_mask *);
void ovs_flow_key_mask(struct sw_flow_key *dst, const struct sw_flow_key *src,
const struct sw_flow_mask *mask);
#endif /* flow.h */ #endif /* flow.h */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment