* [PATCH/RFC repost 4/8] datapath: execution of select group action
From: Simon Horman @ 2014-09-18 1:55 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005311-11752-1-git-send-email-simon.horman@netronome.com>
Allow execution of select group action in the datapath.
A subsequent patch will add validation and copying of
the select group action in the datapath.
The selection algorithm used is based on the RSS hash.
This was chosen because it resembles the algorithm currently
used by the implementation of select groups in ovs-vswitchd.
It may well be that in this case it is more efficient to handle
things in ovs-vswitchd, avoiding the cost of hashing on each packet.
Or that the hashing mechanism used can be optimised somehow. However,
we would like to avoid focusing on these questions of this particular
implementation.
The purpose of this patch is to form part of a prototype for a select
group action. The current Open Flow specification allows for the
implementation to select an algorithm. And we have made a separate
proposal to allow the selection algorithm to be configured via Open Flow.
Thus the algorithm and used and its implementation are not central
to the prototype.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
datapath/actions.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/datapath/actions.c b/datapath/actions.c
index 8d18848..51ca40b 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -809,6 +809,72 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
return 0;
}
+const struct nlattr *bucket_actions(const struct nlattr *attr)
+{
+ const struct nlattr *a;
+ int rem;
+
+ for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
+ a = nla_next(a, &rem)) {
+ if (nla_type(a) == OVS_BUCKET_ATTR_ACTIONS) {
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
+static u16 bucket_weight(const struct nlattr *attr)
+{
+ const struct nlattr *weight;
+
+ /* validate_and_copy_bucket() ensures that the first
+ * attribute is OVS_BUCKET_ATTR_WEIGHT */
+ weight = nla_data(attr);
+ BUG_ON(nla_type(weight) != OVS_BUCKET_ATTR_WEIGHT);
+ return nla_get_u16(weight);
+}
+
+static int select_group(struct datapath *dp, struct sk_buff *skb,
+ const struct nlattr *attr)
+{
+ const struct nlattr *best_bucket = NULL;
+ const struct nlattr *acts_list;
+ const struct nlattr *bucket;
+ struct sk_buff *sample_skb;
+ u32 best_score = 0;
+ u32 basis;
+ u32 i = 0;
+ int rem;
+
+ basis = skb_get_hash(skb);
+
+ /* Only possible type of attributes is OVS_SELECT_GROUP_ATTR_BUCKET */
+ for (bucket = nla_data(attr), rem = nla_len(attr); rem > 0;
+ bucket = nla_next(bucket, &rem)) {
+ uint16_t weight = bucket_weight(bucket);
+ // XXX: This hashing seems expensive
+ u32 score = (jhash_1word(i, basis) & 0xffff) * weight;
+
+ if (score >= best_score) {
+ best_bucket = bucket;
+ best_score = score;
+ }
+ i++;
+ }
+
+ acts_list = bucket_actions(best_bucket);
+
+ /* A select group action is always the final action so
+ * there is no need to clone the skb in case of side effects.
+ * Instead just take a reference to it which will be released
+ * by do_execute_actions(). */
+ skb_get(skb);
+
+ return do_execute_actions(dp, skb, nla_data(acts_list),
+ nla_len(acts_list));
+}
+
static void execute_hash(struct sk_buff *skb, const struct nlattr *attr)
{
struct sw_flow_key *key = OVS_CB(skb)->pkt_key;
@@ -986,6 +1052,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
case OVS_ACTION_ATTR_SAMPLE:
err = sample(dp, skb, a);
break;
+
+ case OVS_ACTION_ATTR_SELECT_GROUP:
+ err = select_group(dp, skb, a);
+ break;
}
if (unlikely(err)) {
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC repost 3/8] odp-util: formatting of datapath select group action
From: Simon Horman @ 2014-09-18 1:55 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005311-11752-1-git-send-email-simon.horman@netronome.com>
Allow formatting of select group action. This is used
when pretty-printing datapath flows. Subsequent patches
will add support for the select group action to the datapath
and ovs-vswtichd.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
lib/odp-util.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 77b456f..4c8dd39 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -182,6 +182,71 @@ format_odp_sample_action(struct ds *ds, const struct nlattr *attr)
ds_put_format(ds, "))");
}
+static bool
+format_odp_bucket(struct ds *ds, const struct nlattr *attr)
+{
+ static const struct nl_policy ovs_sample_policy[] = {
+ [OVS_BUCKET_ATTR_WEIGHT] = { .type = NL_A_U16 },
+ [OVS_BUCKET_ATTR_ACTIONS] = { .type = NL_A_NESTED }
+ };
+ struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
+ const struct nlattr *nla_acts;
+ int len;
+
+ ds_put_cstr(ds, "bucket");
+
+ if (!nl_parse_nested(attr, ovs_sample_policy, a, ARRAY_SIZE(a))) {
+ ds_put_cstr(ds, "(error)");
+ return false;
+ }
+
+ ds_put_format(ds, "(weight=%d,",
+ nl_attr_get_u16(a[OVS_BUCKET_ATTR_WEIGHT]));
+
+ ds_put_cstr(ds, "actions(");
+ nla_acts = nl_attr_get(a[OVS_SAMPLE_ATTR_ACTIONS]);
+ len = nl_attr_get_size(a[OVS_SAMPLE_ATTR_ACTIONS]);
+ format_odp_actions(ds, nla_acts, len);
+ ds_put_format(ds, "))");
+
+ return true;
+}
+
+static void
+format_odp_select_group_action(struct ds *ds, const struct nlattr *attr)
+{
+ static const struct nl_policy ovs_sample_policy[] = {
+ [OVS_SELECT_GROUP_ATTR_BUCKET] = { .type = NL_A_NESTED,
+ .multiple = true }
+ };
+ struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
+ struct nlattr *nla;
+ struct ofpbuf buf;
+ size_t left;
+
+ ds_put_cstr(ds, "select_group");
+
+ if (!nl_parse_nested(attr, ovs_sample_policy, a, ARRAY_SIZE(a))) {
+ ds_put_cstr(ds, "(error)");
+ return;
+ }
+
+ ds_put_cstr(ds, "(actions(");
+
+ nl_attr_get_nested(attr, &buf);
+ NL_ATTR_FOR_EACH (nla, left, ofpbuf_data(&buf), ofpbuf_size(&buf))
+ {
+ uint16_t type = nl_attr_type(nla);
+
+ ovs_assert(type == OVS_SELECT_GROUP_ATTR_BUCKET);
+ if (!format_odp_bucket(ds, nla)) {
+ break;
+ }
+ }
+
+ ds_put_format(ds, "))");
+}
+
static const char *
slow_path_reason_to_string(uint32_t reason)
{
@@ -583,6 +648,8 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
format_odp_sample_action(ds, a);
break;
case OVS_ACTION_ATTR_SELECT_GROUP:
+ format_odp_select_group_action(ds, a);
+ break;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC repost 2/8] netlink: Allow suppression of warnings for duplicate attributes
From: Simon Horman @ 2014-09-18 1:55 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005311-11752-1-git-send-email-simon.horman@netronome.com>
Add a multiple field to struct nl_policy which if set suppresses
warning of duplicate attributes in nl_parse_nested().
As is the case without this patch only the last occurrence of an
attribute is stored in attrs by nl_parse_nested(). As such
if the multiple field of struct nl_policy is set then it
is up to the caller to parse the message to extract all the attributes.
This is in preparation for allowing multiple OVS_SELECT_GROUP_ATTR_BUCKET
attributes in a nested OVS_ACTION_ATTR_SELECT_GROUP attribute.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
lib/netlink.c | 2 +-
lib/netlink.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/netlink.c b/lib/netlink.c
index 24b2168..bc30248 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -743,7 +743,7 @@ nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
if (!nl_attr_validate(nla, e)) {
return false;
}
- if (attrs[type]) {
+ if (attrs[type] && !e->multiple) {
VLOG_DBG_RL(&rl, "duplicate attr %"PRIu16, type);
}
attrs[type] = nla;
diff --git a/lib/netlink.h b/lib/netlink.h
index f9234da..b0a72fd 100644
--- a/lib/netlink.h
+++ b/lib/netlink.h
@@ -195,6 +195,7 @@ struct nl_policy
enum nl_attr_type type;
size_t min_len, max_len;
bool optional;
+ bool multiple;
};
#define NL_POLICY_FOR(TYPE) \
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC repost 1/8] odp: select group action attributes
From: Simon Horman @ 2014-09-18 1:55 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005311-11752-1-git-send-email-simon.horman@netronome.com>
This is the core of a proposed ODP select group action.
It models OpenFlow select groups without any extensions.
Further work:
We believe there is scope to add OVS_SELECT_GROUP_ATTR_* attributes
to supply parameters to the selection method: for example which
selection algorithm to use. This relates to a proposed
Open Flow extension that we have made.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
datapath/linux/compat/include/linux/openvswitch.h | 31 +++++++++++++++++++++++
lib/dpif-netdev.c | 1 +
lib/dpif.c | 1 +
lib/odp-execute.c | 1 +
lib/odp-util.c | 2 ++
5 files changed, 36 insertions(+)
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 6910dc4..91ff939 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -510,6 +510,35 @@ enum ovs_sample_attr {
#define OVS_SAMPLE_ATTR_MAX (__OVS_SAMPLE_ATTR_MAX - 1)
/**
+ * enum ovs_bucket_attr - Bucket for * %OVS_ACTION_ATTR_SELECT_GROUP action.
+ * @OVS_BUCKET_ATTR_WEIGHT. Relative weight of bucket.
+ * @OVS_BUCKET_ATTR_ACTIONS. Set of actions to execute.
+ */
+enum ovs_bucket_attr {
+ OVS_BUCKET_ATTR_UNSPEC,
+ OVS_BUCKET_ATTR_WEIGHT, /* u16. Relative weight of bucket. */
+ OVS_BUCKET_ATTR_ACTIONS, /* Nested OVS_BUCKET_ATTR_* attributes. */
+ __OVS_BUCKET_ATTR_MAX,
+};
+
+#define OVS_BUCKET_ATTR_MAX (__OVS_BUCKET_ATTR_MAX - 1)
+
+/**
+ * enum ovs_select_group_attr - Attributes for * %OVS_ACTION_ATTR_SELECT_GROUP action.
+ * @OVS_SELECT_GROUP_ATTR_BUCKET. A bucket whose actions will be executed
+ * if the bucket is selected. One ore more buckets may be present.
+ *
+ * Selects a bucket and executes its actions.
+ */
+enum ovs_select_group_attr {
+ OVS_SELECT_GROUP_ATTR_UNSPEC,
+ OVS_SELECT_GROUP_ATTR_BUCKET, /* Nested OVS_BUCKET_ATTR_* attributes. */
+ __OVS_SELECT_GROUP_ATTR_MAX,
+};
+
+#define OVS_SELECT_GROUP_ATTR_MAX (__OVS_SELECT_GROUP_ATTR_MAX - 1)
+
+/**
* enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
* @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
* message should be sent. Required.
@@ -609,6 +638,7 @@ struct ovs_action_hash {
* indicate the new packet contents. This could potentially still be
* %ETH_P_MPLS if the resulting MPLS label stack is not empty. If there
* is no MPLS label stack, as determined by ethertype, no action is taken.
+ * @OVS_ACTION_ATTR_SELECT_GROUP: Select a bucket and execute its actions.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -631,6 +661,7 @@ enum ovs_action_attr {
* data immediately followed by a mask.
* The data must be zero for the unmasked
* bits. */
+ OVS_ACTION_ATTR_SELECT_GROUP, /* Nested OVS_SELECT_GROUP_*. */
__OVS_ACTION_ATTR_MAX
};
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 409c9bf..bfcfd8c 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2560,6 +2560,7 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt,
case OVS_ACTION_ATTR_SET:
case OVS_ACTION_ATTR_SET_MASKED:
case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/dpif.c b/lib/dpif.c
index bf2c5f9..90b561f 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1043,6 +1043,7 @@ dpif_execute_helper_cb(void *aux_, struct dpif_packet **packets, int cnt,
case OVS_ACTION_ATTR_SET:
case OVS_ACTION_ATTR_SET_MASKED:
case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index e4bee18..c0ba868 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -518,6 +518,7 @@ odp_execute_actions__(void *dp, struct dpif_packet **packets, int cnt,
}
break;
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/odp-util.c b/lib/odp-util.c
index d205473..77b456f 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -83,6 +83,7 @@ odp_action_len(uint16_t type)
case OVS_ACTION_ATTR_HASH: return sizeof(struct ovs_action_hash);
case OVS_ACTION_ATTR_SET: return -2;
case OVS_ACTION_ATTR_SET_MASKED: return -2;
+ case OVS_ACTION_ATTR_SELECT_GROUP: return -2;
case OVS_ACTION_ATTR_SAMPLE: return -2;
case OVS_ACTION_ATTR_UNSPEC:
@@ -581,6 +582,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
case OVS_ACTION_ATTR_SAMPLE:
format_odp_sample_action(ds, a);
break;
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC repost 0/8] Open vSwtich ODP Select Group Action
From: Simon Horman @ 2014-09-18 1:55 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
[repost with correct dev@openvswitch.org address]
Hi,
the purpose of this patch-set is to provide a prototype of a select group
action in the Open vSwitch datapath. And the motivation for that is to
allow offloading of selection either in the datapath or by any hooks
provided by the datapath for hardware offloads (a topic of quite some
discussion elsewhere).
This proposal is also designed to tie in with another proposal we have
made to allow the selection method of a select group to be configured using
Open Flow. As such the selection method included in this patchset is
not the focus of this work: any method may be implemented. Rather,
the focus is on the ability to do selection in the datapath.
There are several implementation limitations of this prototype:
* It does not address per-bucket statistics.
- We believe that the datapath can track per-bucket statistics and;
- Expose them to user-space using new netlink attributes
* It assumes the select group comes last as the resulting packet
may vary depending on the bucket that is chosen. Some possibilities
for handling this include:
- Performing selection in userspace for such cases
- Using recirculation
* It seems that if recirculation may occur in more than one bucket
then separate recirculation ids would be required. This prototype
does not implement that.
This series is based on the Open vSwitch and its datapath maintained at
https://github.com/openvswitch/ovs.git
It is based on commit 5545e7826896e861c ("lib/odp-util: Add tunnel tp_src,
tp_dst parsing and formatting") of that tree.
Simon Horman (8):
odp: select group action attributes
netlink: Allow suppression of warnings for duplicate attributes
odp-util: formatting of datapath select group action
datapath: execution of select group action
datapath: Move last_action() helper to datapath.h
datapath: validation of select group action
ofproto: translate datapath select group action
hack: ofproto: enable odp select action
datapath/actions.c | 74 ++++++++++++++-
datapath/datapath.h | 5 +
datapath/flow_netlink.c | 102 ++++++++++++++++++++
datapath/linux/compat/include/linux/openvswitch.h | 31 +++++++
lib/dpif-netdev.c | 1 +
lib/dpif.c | 1 +
lib/netlink.c | 2 +-
lib/netlink.h | 1 +
lib/odp-execute.c | 1 +
lib/odp-util.c | 69 ++++++++++++++
ofproto/ofproto-dpif-xlate.c | 108 +++++++++++++++++++++-
11 files changed, 388 insertions(+), 7 deletions(-)
--
2.0.1
^ permalink raw reply
* [PATCH/RFC 8/8] hack: ofproto: enable odp select action
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
This is a quick hack to enable the datapath group select action.
It is in lieu of some combination of:
* probing
* run-time configuration by the end-use.
* run-time heuristic to use the action as appropriate
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
ofproto/ofproto-dpif-xlate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index b08a821..eca617d 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2896,7 +2896,7 @@ xlate_select_group_userspace(struct xlate_ctx *ctx, struct group_dpif *group)
static void
xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
{
- if (ctx->xbridge->dp_select_group) {
+ if (true /*ctx->xbridge->dp_select_group*/ ) {
xlate_select_group_datapath(ctx, group);
} else {
xlate_select_group_userspace(ctx, group);
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 7/8] ofproto: translate datapath select group action
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
This add support for the select group action to ovs-vswtichd.
This new feature is currently disabled in xlate_select_group()
because ctx->xbridge->dp_select_group is always false.
This patch is a prototype and has several limitations:
* It assumes that no actions follow a select group action
because the resulting packet after a select group action may
differ depending on the bucket used. It may be possible
to address this problem using recirculation. Or to not use
the datapath select group in such situations. In any case
this patch does not solve this problem or even prevent it
from occurring.
* If recirculation occurs inside more than one bucket then
it seems that separate recirculation ids would be required
for each occurrence. This patch does not solve this problem or even
prevent it from occurring.
* No attempt is made to handle per-bucket statistics.
This would most likely require further datapath modifications.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
ofproto/ofproto-dpif-xlate.c | 108 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 107 insertions(+), 1 deletion(-)
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 6e33a27..b08a821 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -103,6 +103,9 @@ struct xbridge {
* False if the datapath supports only 8-byte (or shorter) userdata. */
bool variable_length_userdata;
+ /* True if datapath supports select group action */
+ bool dp_select_group;
+
/* Number of MPLS label stack entries that the datapath supports
* in matches. */
size_t max_mpls_depth;
@@ -329,6 +332,9 @@ static void xlate_report(struct xlate_ctx *, const char *);
static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port,
uint8_t table_id, bool may_packet_in,
bool honor_table_miss);
+static void xlate_group_stats(struct xlate_ctx *, struct group_dpif *,
+ struct ofputil_bucket *);
+static void xlate_group_bucket(struct xlate_ctx *, struct ofputil_bucket *);
static bool input_vid_is_valid(uint16_t vid, struct xbundle *, bool warn);
static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid);
static void output_normal(struct xlate_ctx *, const struct xbundle *,
@@ -2353,6 +2359,61 @@ fix_sflow_action(struct xlate_ctx *ctx)
ctx->sflow_odp_port, ctx->sflow_n_outputs, cookie);
}
+/* Compose bucket for SELECT_GROUP action. */
+static void
+compose_bucket_action(struct xlate_ctx *ctx, struct group_dpif *group,
+ struct ofputil_bucket *bucket)
+{
+ size_t bucket_offset, actions_offset;
+ struct ofpbuf *odp_actions = ctx->xout->odp_actions;
+
+ bucket_offset = nl_msg_start_nested(odp_actions,
+ OVS_SELECT_GROUP_ATTR_BUCKET);
+
+ nl_msg_put_u16(odp_actions, OVS_BUCKET_ATTR_WEIGHT, bucket->weight);
+
+ actions_offset = nl_msg_start_nested(odp_actions, OVS_BUCKET_ATTR_ACTIONS);
+
+ xlate_group_bucket(ctx, bucket);
+ xlate_group_stats(ctx, group, bucket);
+
+ nl_msg_end_nested(odp_actions, actions_offset);
+ nl_msg_end_nested(odp_actions, bucket_offset);
+
+ ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
+ odp_actions, &ctx->xout->wc);
+}
+
+/* Compose SELECT_GROUP action.
+ * May be called multiple times to add multiple buckets.
+ * The first call should pass SIZE_MAX as the value for offset_
+ * and subsequent calls should pass returned by the previous call.
+ * The last call should pass NULL as the bucket parameter
+ * and previous calls should pass a valid bucket to add to the
+ * select group. */
+static size_t
+compose_select_group_action(struct xlate_ctx *ctx, struct group_dpif *group,
+ struct ofputil_bucket *bucket,
+ const size_t offset_)
+{
+ size_t offset = offset_;
+
+ if (bucket != NULL) {
+ if (offset == SIZE_MAX) {
+ offset = nl_msg_start_nested(ctx->xout->odp_actions,
+ OVS_ACTION_ATTR_SELECT_GROUP);
+ }
+
+ compose_bucket_action(ctx, group, bucket);
+ } else {
+ if (offset != SIZE_MAX) {
+ nl_msg_end_nested(ctx->xout->odp_actions, offset);
+ }
+ }
+
+ return offset;
+}
+
static enum slow_path_reason
process_special(struct xlate_ctx *ctx, const struct flow *flow,
const struct xport *xport, const struct ofpbuf *packet)
@@ -2775,7 +2836,40 @@ xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group)
}
static void
-xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+xlate_select_group_datapath(struct xlate_ctx *ctx, struct group_dpif *group)
+{
+ struct flow_wildcards *wc = &ctx->xout->wc;
+ struct ofputil_bucket *bucket;
+ const struct list *buckets;
+ struct flow old_flow = ctx->xin->flow;
+ size_t offset = SIZE_MAX;
+
+ group_dpif_get_buckets(group, &buckets);
+ LIST_FOR_EACH (bucket, list_node, buckets) {
+ if (bucket_is_alive(ctx, bucket, 0)) {
+ offset = compose_select_group_action(ctx, group, bucket, offset);
+
+ /* Roll back flow to previous state.
+ *
+ * This allows composition of the actions for subsequent
+ * buckets in such a way that they apply to the state of the
+ * packet present before the select group action.
+ *
+ * XXX: Assumes no actions follow the select group action.
+ * Handle with recirculation?
+ */
+ ctx->xin->flow = old_flow;
+ }
+ }
+
+ if (offset != SIZE_MAX) {
+ memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+ compose_select_group_action(ctx, group, NULL, offset);
+ }
+}
+
+static void
+xlate_select_group_userspace(struct xlate_ctx *ctx, struct group_dpif *group)
{
struct flow_wildcards *wc = &ctx->xout->wc;
struct ofputil_bucket *bucket;
@@ -2800,6 +2894,16 @@ xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
}
static void
+xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+{
+ if (ctx->xbridge->dp_select_group) {
+ xlate_select_group_datapath(ctx, group);
+ } else {
+ xlate_select_group_userspace(ctx, group);
+ }
+}
+
+static void
xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
{
ctx->in_group = true;
@@ -2990,6 +3094,8 @@ compose_recirculate_action(struct xlate_ctx *ctx,
ofpacts_len = ofpacts_base_len -
((uint8_t *)ofpact_current - (uint8_t *)ofpacts_base);
+ /* XXX: If recirculation occurs inside buckets of a select group action
+ * then multiple recirculation ids may be required. */
if (ctx->rule) {
id = rule_dpif_get_recirc_id(ctx->rule);
} else {
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 6/8] datapath: validation of select group action
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
Allow validation and copying of select group actions.
This completes the prototype select group action implementation
in the datapath. Subsequent patches will add support to ovs-vswtichd.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
datapath/flow_netlink.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index 6c74841..90eddba 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -1497,6 +1497,94 @@ static int validate_and_copy_sample(const struct nlattr *attr,
return 0;
}
+static int validate_and_copy_bucket(const struct nlattr *attr,
+ const struct sw_flow_key *key, int depth,
+ struct sw_flow_actions **sfa,
+ __be16 eth_type, __be16 vlan_tci)
+{
+ const struct nlattr *attrs[OVS_BUCKET_ATTR_MAX + 1];
+ const struct nlattr *weight, *actions;
+ const struct nlattr *a;
+ int rem, start, err, st_acts;
+
+ memset(attrs, 0, sizeof(attrs));
+ nla_for_each_nested(a, attr, rem) {
+ int type = nla_type(a);
+ if (!type || type > OVS_BUCKET_ATTR_MAX || attrs[type])
+ return -EINVAL;
+ attrs[type] = a;
+ }
+ if (rem)
+ return -EINVAL;
+
+ weight = attrs[OVS_BUCKET_ATTR_WEIGHT];
+ if (!weight || nla_len(weight) != sizeof(u16))
+ return -EINVAL;
+
+ actions = attrs[OVS_BUCKET_ATTR_ACTIONS];
+ if (!actions || (nla_len(actions) && nla_len(actions) < NLA_HDRLEN))
+ return -EINVAL;
+
+ /* validation done, copy sample action. */
+ start = add_nested_action_start(sfa, OVS_SELECT_GROUP_ATTR_BUCKET);
+ if (start < 0)
+ return start;
+ err = add_action(sfa, OVS_BUCKET_ATTR_WEIGHT,
+ nla_data(weight), sizeof(u16));
+ if (err)
+ return err;
+ st_acts = add_nested_action_start(sfa, OVS_SAMPLE_ATTR_ACTIONS);
+ if (st_acts < 0)
+ return st_acts;
+
+ err = __ovs_nla_copy_actions(actions, key, depth + 1, sfa,
+ eth_type, vlan_tci);
+ if (err)
+ return err;
+
+ add_nested_action_end(*sfa, st_acts);
+ add_nested_action_end(*sfa, start);
+
+ return 0;
+}
+
+static int validate_and_copy_select_group(const struct nlattr *attr,
+ const struct sw_flow_key *key,
+ int depth,
+ struct sw_flow_actions **sfa,
+ __be16 eth_type, __be16 vlan_tci)
+{
+ bool have_bucket = false;
+ const struct nlattr *a;
+ int rem, start, err;
+
+ start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SELECT_GROUP);
+ if (start < 0)
+ return start;
+
+ nla_for_each_nested(a, attr, rem) {
+ int type = nla_type(a);
+
+ if (!type || type > OVS_SAMPLE_ATTR_MAX)
+ return -EINVAL;
+
+ /* Only possible type is OVS_SELECT_GROUP_ATTR_BUCKET */
+ if ((nla_len(a) && nla_len(a) < NLA_HDRLEN))
+ return -EINVAL;
+ err = validate_and_copy_bucket(a, key, depth, sfa,
+ eth_type, vlan_tci);
+ if (err < 0)
+ return err;
+ have_bucket = true;
+ }
+ if (rem || !have_bucket)
+ return -EINVAL;
+
+ add_nested_action_end(*sfa, start);
+
+ return 0;
+}
+
static int validate_tp_port(const struct sw_flow_key *flow_key,
__be16 eth_type)
{
@@ -1750,6 +1838,7 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
[OVS_ACTION_ATTR_POP_VLAN] = 0,
[OVS_ACTION_ATTR_SET] = (u32)-1,
[OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
+ [OVS_ACTION_ATTR_SELECT_GROUP] = (u32)-1,
[OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash)
};
const struct ovs_action_push_vlan *vlan;
@@ -1856,6 +1945,19 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
skip_copy = true;
break;
+ case OVS_ACTION_ATTR_SELECT_GROUP:
+ /* Nothing may come after a select group */
+ if (!last_action(a, rem))
+ return -EINVAL;
+
+ err = validate_and_copy_select_group(a, key, depth,
+ sfa, eth_type,
+ vlan_tci);
+ if (err)
+ return err;
+ skip_copy = true;
+ break;
+
default:
return -EINVAL;
}
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 5/8] datapath: Move last_action() helper to datapath.h
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
This is in preparation for using last_action() from
more than one C file as part of supporting an odp select group action.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
datapath/actions.c | 6 ------
datapath/datapath.h | 5 +++++
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/datapath/actions.c b/datapath/actions.c
index 51ca40b..9d27234 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -752,11 +752,6 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
return ovs_dp_upcall(dp, skb, &upcall);
}
-static bool last_action(const struct nlattr *a, int rem)
-{
- return a->nla_len == rem;
-}
-
static int sample(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr)
{
@@ -841,7 +836,6 @@ static int select_group(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *best_bucket = NULL;
const struct nlattr *acts_list;
const struct nlattr *bucket;
- struct sk_buff *sample_skb;
u32 best_score = 0;
u32 basis;
u32 i = 0;
diff --git a/datapath/datapath.h b/datapath/datapath.h
index c5d3c86..74a15e6 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -209,4 +209,9 @@ do { \
if (net_ratelimit()) \
pr_info("netlink: " fmt, ##__VA_ARGS__); \
} while (0)
+
+static inline bool last_action(const struct nlattr *a, int rem)
+{
+ return a->nla_len == rem;
+}
#endif /* datapath.h */
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 4/8] datapath: execution of select group action
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
Allow execution of select group action in the datapath.
A subsequent patch will add validation and copying of
the select group action in the datapath.
The selection algorithm used is based on the RSS hash.
This was chosen because it resembles the algorithm currently
used by the implementation of select groups in ovs-vswitchd.
It may well be that in this case it is more efficient to handle
things in ovs-vswitchd, avoiding the cost of hashing on each packet.
Or that the hashing mechanism used can be optimised somehow. However,
we would like to avoid focusing on these questions of this particular
implementation.
The purpose of this patch is to form part of a prototype for a select
group action. The current Open Flow specification allows for the
implementation to select an algorithm. And we have made a separate
proposal to allow the selection algorithm to be configured via Open Flow.
Thus the algorithm and used and its implementation are not central
to the prototype.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
datapath/actions.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/datapath/actions.c b/datapath/actions.c
index 8d18848..51ca40b 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -809,6 +809,72 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
return 0;
}
+const struct nlattr *bucket_actions(const struct nlattr *attr)
+{
+ const struct nlattr *a;
+ int rem;
+
+ for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
+ a = nla_next(a, &rem)) {
+ if (nla_type(a) == OVS_BUCKET_ATTR_ACTIONS) {
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
+static u16 bucket_weight(const struct nlattr *attr)
+{
+ const struct nlattr *weight;
+
+ /* validate_and_copy_bucket() ensures that the first
+ * attribute is OVS_BUCKET_ATTR_WEIGHT */
+ weight = nla_data(attr);
+ BUG_ON(nla_type(weight) != OVS_BUCKET_ATTR_WEIGHT);
+ return nla_get_u16(weight);
+}
+
+static int select_group(struct datapath *dp, struct sk_buff *skb,
+ const struct nlattr *attr)
+{
+ const struct nlattr *best_bucket = NULL;
+ const struct nlattr *acts_list;
+ const struct nlattr *bucket;
+ struct sk_buff *sample_skb;
+ u32 best_score = 0;
+ u32 basis;
+ u32 i = 0;
+ int rem;
+
+ basis = skb_get_hash(skb);
+
+ /* Only possible type of attributes is OVS_SELECT_GROUP_ATTR_BUCKET */
+ for (bucket = nla_data(attr), rem = nla_len(attr); rem > 0;
+ bucket = nla_next(bucket, &rem)) {
+ uint16_t weight = bucket_weight(bucket);
+ // XXX: This hashing seems expensive
+ u32 score = (jhash_1word(i, basis) & 0xffff) * weight;
+
+ if (score >= best_score) {
+ best_bucket = bucket;
+ best_score = score;
+ }
+ i++;
+ }
+
+ acts_list = bucket_actions(best_bucket);
+
+ /* A select group action is always the final action so
+ * there is no need to clone the skb in case of side effects.
+ * Instead just take a reference to it which will be released
+ * by do_execute_actions(). */
+ skb_get(skb);
+
+ return do_execute_actions(dp, skb, nla_data(acts_list),
+ nla_len(acts_list));
+}
+
static void execute_hash(struct sk_buff *skb, const struct nlattr *attr)
{
struct sw_flow_key *key = OVS_CB(skb)->pkt_key;
@@ -986,6 +1052,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
case OVS_ACTION_ATTR_SAMPLE:
err = sample(dp, skb, a);
break;
+
+ case OVS_ACTION_ATTR_SELECT_GROUP:
+ err = select_group(dp, skb, a);
+ break;
}
if (unlikely(err)) {
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 3/8] odp-util: formatting of datapath select group action
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
Allow formatting of select group action. This is used
when pretty-printing datapath flows. Subsequent patches
will add support for the select group action to the datapath
and ovs-vswtichd.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
lib/odp-util.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 77b456f..4c8dd39 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -182,6 +182,71 @@ format_odp_sample_action(struct ds *ds, const struct nlattr *attr)
ds_put_format(ds, "))");
}
+static bool
+format_odp_bucket(struct ds *ds, const struct nlattr *attr)
+{
+ static const struct nl_policy ovs_sample_policy[] = {
+ [OVS_BUCKET_ATTR_WEIGHT] = { .type = NL_A_U16 },
+ [OVS_BUCKET_ATTR_ACTIONS] = { .type = NL_A_NESTED }
+ };
+ struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
+ const struct nlattr *nla_acts;
+ int len;
+
+ ds_put_cstr(ds, "bucket");
+
+ if (!nl_parse_nested(attr, ovs_sample_policy, a, ARRAY_SIZE(a))) {
+ ds_put_cstr(ds, "(error)");
+ return false;
+ }
+
+ ds_put_format(ds, "(weight=%d,",
+ nl_attr_get_u16(a[OVS_BUCKET_ATTR_WEIGHT]));
+
+ ds_put_cstr(ds, "actions(");
+ nla_acts = nl_attr_get(a[OVS_SAMPLE_ATTR_ACTIONS]);
+ len = nl_attr_get_size(a[OVS_SAMPLE_ATTR_ACTIONS]);
+ format_odp_actions(ds, nla_acts, len);
+ ds_put_format(ds, "))");
+
+ return true;
+}
+
+static void
+format_odp_select_group_action(struct ds *ds, const struct nlattr *attr)
+{
+ static const struct nl_policy ovs_sample_policy[] = {
+ [OVS_SELECT_GROUP_ATTR_BUCKET] = { .type = NL_A_NESTED,
+ .multiple = true }
+ };
+ struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
+ struct nlattr *nla;
+ struct ofpbuf buf;
+ size_t left;
+
+ ds_put_cstr(ds, "select_group");
+
+ if (!nl_parse_nested(attr, ovs_sample_policy, a, ARRAY_SIZE(a))) {
+ ds_put_cstr(ds, "(error)");
+ return;
+ }
+
+ ds_put_cstr(ds, "(actions(");
+
+ nl_attr_get_nested(attr, &buf);
+ NL_ATTR_FOR_EACH (nla, left, ofpbuf_data(&buf), ofpbuf_size(&buf))
+ {
+ uint16_t type = nl_attr_type(nla);
+
+ ovs_assert(type == OVS_SELECT_GROUP_ATTR_BUCKET);
+ if (!format_odp_bucket(ds, nla)) {
+ break;
+ }
+ }
+
+ ds_put_format(ds, "))");
+}
+
static const char *
slow_path_reason_to_string(uint32_t reason)
{
@@ -583,6 +648,8 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
format_odp_sample_action(ds, a);
break;
case OVS_ACTION_ATTR_SELECT_GROUP:
+ format_odp_select_group_action(ds, a);
+ break;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 2/8] netlink: Allow suppression of warnings for duplicate attributes
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
Add a multiple field to struct nl_policy which if set suppresses
warning of duplicate attributes in nl_parse_nested().
As is the case without this patch only the last occurrence of an
attribute is stored in attrs by nl_parse_nested(). As such
if the multiple field of struct nl_policy is set then it
is up to the caller to parse the message to extract all the attributes.
This is in preparation for allowing multiple OVS_SELECT_GROUP_ATTR_BUCKET
attributes in a nested OVS_ACTION_ATTR_SELECT_GROUP attribute.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
lib/netlink.c | 2 +-
lib/netlink.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/netlink.c b/lib/netlink.c
index 24b2168..bc30248 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -743,7 +743,7 @@ nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
if (!nl_attr_validate(nla, e)) {
return false;
}
- if (attrs[type]) {
+ if (attrs[type] && !e->multiple) {
VLOG_DBG_RL(&rl, "duplicate attr %"PRIu16, type);
}
attrs[type] = nla;
diff --git a/lib/netlink.h b/lib/netlink.h
index f9234da..b0a72fd 100644
--- a/lib/netlink.h
+++ b/lib/netlink.h
@@ -195,6 +195,7 @@ struct nl_policy
enum nl_attr_type type;
size_t min_len, max_len;
bool optional;
+ bool multiple;
};
#define NL_POLICY_FOR(TYPE) \
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 1/8] odp: select group action attributes
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
In-Reply-To: <1411005153-11041-1-git-send-email-simon.horman@netronome.com>
This is the core of a proposed ODP select group action.
It models OpenFlow select groups without any extensions.
Further work:
We believe there is scope to add OVS_SELECT_GROUP_ATTR_* attributes
to supply parameters to the selection method: for example which
selection algorithm to use. This relates to a proposed
Open Flow extension that we have made.
Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
datapath/linux/compat/include/linux/openvswitch.h | 31 +++++++++++++++++++++++
lib/dpif-netdev.c | 1 +
lib/dpif.c | 1 +
lib/odp-execute.c | 1 +
lib/odp-util.c | 2 ++
5 files changed, 36 insertions(+)
diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 6910dc4..91ff939 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -510,6 +510,35 @@ enum ovs_sample_attr {
#define OVS_SAMPLE_ATTR_MAX (__OVS_SAMPLE_ATTR_MAX - 1)
/**
+ * enum ovs_bucket_attr - Bucket for * %OVS_ACTION_ATTR_SELECT_GROUP action.
+ * @OVS_BUCKET_ATTR_WEIGHT. Relative weight of bucket.
+ * @OVS_BUCKET_ATTR_ACTIONS. Set of actions to execute.
+ */
+enum ovs_bucket_attr {
+ OVS_BUCKET_ATTR_UNSPEC,
+ OVS_BUCKET_ATTR_WEIGHT, /* u16. Relative weight of bucket. */
+ OVS_BUCKET_ATTR_ACTIONS, /* Nested OVS_BUCKET_ATTR_* attributes. */
+ __OVS_BUCKET_ATTR_MAX,
+};
+
+#define OVS_BUCKET_ATTR_MAX (__OVS_BUCKET_ATTR_MAX - 1)
+
+/**
+ * enum ovs_select_group_attr - Attributes for * %OVS_ACTION_ATTR_SELECT_GROUP action.
+ * @OVS_SELECT_GROUP_ATTR_BUCKET. A bucket whose actions will be executed
+ * if the bucket is selected. One ore more buckets may be present.
+ *
+ * Selects a bucket and executes its actions.
+ */
+enum ovs_select_group_attr {
+ OVS_SELECT_GROUP_ATTR_UNSPEC,
+ OVS_SELECT_GROUP_ATTR_BUCKET, /* Nested OVS_BUCKET_ATTR_* attributes. */
+ __OVS_SELECT_GROUP_ATTR_MAX,
+};
+
+#define OVS_SELECT_GROUP_ATTR_MAX (__OVS_SELECT_GROUP_ATTR_MAX - 1)
+
+/**
* enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
* @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
* message should be sent. Required.
@@ -609,6 +638,7 @@ struct ovs_action_hash {
* indicate the new packet contents. This could potentially still be
* %ETH_P_MPLS if the resulting MPLS label stack is not empty. If there
* is no MPLS label stack, as determined by ethertype, no action is taken.
+ * @OVS_ACTION_ATTR_SELECT_GROUP: Select a bucket and execute its actions.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -631,6 +661,7 @@ enum ovs_action_attr {
* data immediately followed by a mask.
* The data must be zero for the unmasked
* bits. */
+ OVS_ACTION_ATTR_SELECT_GROUP, /* Nested OVS_SELECT_GROUP_*. */
__OVS_ACTION_ATTR_MAX
};
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 409c9bf..bfcfd8c 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2560,6 +2560,7 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt,
case OVS_ACTION_ATTR_SET:
case OVS_ACTION_ATTR_SET_MASKED:
case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/dpif.c b/lib/dpif.c
index bf2c5f9..90b561f 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1043,6 +1043,7 @@ dpif_execute_helper_cb(void *aux_, struct dpif_packet **packets, int cnt,
case OVS_ACTION_ATTR_SET:
case OVS_ACTION_ATTR_SET_MASKED:
case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index e4bee18..c0ba868 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -518,6 +518,7 @@ odp_execute_actions__(void *dp, struct dpif_packet **packets, int cnt,
}
break;
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/odp-util.c b/lib/odp-util.c
index d205473..77b456f 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -83,6 +83,7 @@ odp_action_len(uint16_t type)
case OVS_ACTION_ATTR_HASH: return sizeof(struct ovs_action_hash);
case OVS_ACTION_ATTR_SET: return -2;
case OVS_ACTION_ATTR_SET_MASKED: return -2;
+ case OVS_ACTION_ATTR_SELECT_GROUP: return -2;
case OVS_ACTION_ATTR_SAMPLE: return -2;
case OVS_ACTION_ATTR_UNSPEC:
@@ -581,6 +582,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
case OVS_ACTION_ATTR_SAMPLE:
format_odp_sample_action(ds, a);
break;
+ case OVS_ACTION_ATTR_SELECT_GROUP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
--
2.0.1
^ permalink raw reply related
* [PATCH/RFC 0/8] Open vSwtich ODP Select Group Action
From: Simon Horman @ 2014-09-18 1:52 UTC (permalink / raw)
To: dev, netdev; +Cc: Pravin Shelar, Jesse Gross, Thomas Graf, Simon Horman
Hi,
the purpose of this patch-set is to provide a prototype of a select group
action in the Open vSwitch datapath. And the motivation for that is to
allow offloading of selection either in the datapath or by any hooks
provided by the datapath for hardware offloads (a topic of quite some
discussion elsewhere).
This proposal is also designed to tie in with another proposal we have
made to allow the selection method of a select group to be configured using
Open Flow. As such the selection method included in this patchset is
not the focus of this work: any method may be implemented. Rather,
the focus is on the ability to do selection in the datapath.
There are several implementation limitations of this prototype:
* It does not address per-bucket statistics.
- We believe that the datapath can track per-bucket statistics and;
- Expose them to user-space using new netlink attributes
* It assumes the select group comes last as the resulting packet
may vary depending on the bucket that is chosen. Some possibilities
for handling this include:
- Performing selection in userspace for such cases
- Using recirculation
* It seems that if recirculation may occur in more than one bucket
then separate recirculation ids would be required. This prototype
does not implement that.
This series is based on the Open vSwitch and its datapath maintained at
https://github.com/openvswitch/ovs.git
It is based on commit 5545e7826896e861c ("lib/odp-util: Add tunnel tp_src,
tp_dst parsing and formatting") of that tree.
Simon Horman (8):
odp: select group action attributes
netlink: Allow suppression of warnings for duplicate attributes
odp-util: formatting of datapath select group action
datapath: execution of select group action
datapath: Move last_action() helper to datapath.h
datapath: validation of select group action
ofproto: translate datapath select group action
hack: ofproto: enable odp select action
datapath/actions.c | 74 ++++++++++++++-
datapath/datapath.h | 5 +
datapath/flow_netlink.c | 102 ++++++++++++++++++++
datapath/linux/compat/include/linux/openvswitch.h | 31 +++++++
lib/dpif-netdev.c | 1 +
lib/dpif.c | 1 +
lib/netlink.c | 2 +-
lib/netlink.h | 1 +
lib/odp-execute.c | 1 +
lib/odp-util.c | 69 ++++++++++++++
ofproto/ofproto-dpif-xlate.c | 108 +++++++++++++++++++++-
11 files changed, 388 insertions(+), 7 deletions(-)
--
2.0.1
^ permalink raw reply
* Re: [net-next PATCH 1/2] net: cls_u32: fix missed pcpu_success free_percpu
From: John Fastabend @ 2014-09-18 1:17 UTC (permalink / raw)
To: xiyou.wangcong, davem, eric.dumazet; +Cc: netdev, jhs
In-Reply-To: <20140917191131.20529.91136.stgit@nitbit.x32>
On 09/17/2014 12:11 PM, John Fastabend wrote:
> This fixes a missed free_percpu in the unwind code path and when
> keys are destroyed.
>
> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
> ---
> net/sched/cls_u32.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
This patch still misses free'ing pcpu_success in an error path
so I'll address it when I send a v2 to address comments on the
second patch
--
John Fastabend Intel Corporation
^ permalink raw reply
* Re: linux-next: build warning after merge of the net tree
From: Randy Dunlap @ 2014-09-18 0:35 UTC (permalink / raw)
To: Stephen Rothwell, David Miller, netdev
Cc: linux-next, linux-kernel, linux-kbuild
In-Reply-To: <20140918103200.12b79941@canb.auug.org.au>
On 09/17/14 17:32, Stephen Rothwell wrote:
> Hi all,
>
> After merging the net tree, today's linux-next build (powerpc
> ppc64_defconfig) produced these warnings:
>
> warning: (PPC_CELL_NATIVE && BLUESTONE && CANYONLANDS && GLACIER && EIGER && 440EPX && 440GRX && 440GX && 460SX && 405EX) selects IBM_EMAC_RGMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
> warning: (PPC_CELL_NATIVE && CANYONLANDS && GLACIER && 440EP && 440EPX && 440GRX && 440GP && 440GX && 460SX && 405GP) selects IBM_EMAC_ZMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
> warning: (PPC_CELL_NATIVE && 440GX && 460EX && 460SX && APM821xx) selects IBM_EMAC_TAH which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
> warning: (PPC_CELL_NATIVE && AKEBONO && 440EPX && 440GRX && 440GX && 440SPe && 460EX && 460SX && APM821xx && 405EX) selects IBM_EMAC_EMAC4 which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
> warning: (PPC_CELL_NATIVE && CANYONLANDS && GLACIER && 440EP && 440EPX && 440GRX && 440GP && 440GX && 460SX && 405GP) selects IBM_EMAC_ZMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
> warning: (PPC_CELL_NATIVE && BLUESTONE && CANYONLANDS && GLACIER && EIGER && 440EPX && 440GRX && 440GX && 460SX && 405EX) selects IBM_EMAC_RGMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
> warning: (PPC_CELL_NATIVE && 440GX && 460EX && 460SX && APM821xx) selects IBM_EMAC_TAH which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
> warning: (PPC_CELL_NATIVE && AKEBONO && 440EPX && 440GRX && 440GX && 440SPe && 460EX && 460SX && APM821xx && 405EX) selects IBM_EMAC_EMAC4 which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
>
I have looked into these and don't see why there is a problem.
Any help would be appreciated.
--
~Randy
^ permalink raw reply
* linux-next: build warning after merge of the net tree
From: Stephen Rothwell @ 2014-09-18 0:32 UTC (permalink / raw)
To: David Miller, netdev; +Cc: linux-next, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1855 bytes --]
Hi all,
After merging the net tree, today's linux-next build (powerpc
ppc64_defconfig) produced these warnings:
warning: (PPC_CELL_NATIVE && BLUESTONE && CANYONLANDS && GLACIER && EIGER && 440EPX && 440GRX && 440GX && 460SX && 405EX) selects IBM_EMAC_RGMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
warning: (PPC_CELL_NATIVE && CANYONLANDS && GLACIER && 440EP && 440EPX && 440GRX && 440GP && 440GX && 460SX && 405GP) selects IBM_EMAC_ZMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
warning: (PPC_CELL_NATIVE && 440GX && 460EX && 460SX && APM821xx) selects IBM_EMAC_TAH which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
warning: (PPC_CELL_NATIVE && AKEBONO && 440EPX && 440GRX && 440GX && 440SPe && 460EX && 460SX && APM821xx && 405EX) selects IBM_EMAC_EMAC4 which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
warning: (PPC_CELL_NATIVE && CANYONLANDS && GLACIER && 440EP && 440EPX && 440GRX && 440GP && 440GX && 460SX && 405GP) selects IBM_EMAC_ZMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
warning: (PPC_CELL_NATIVE && BLUESTONE && CANYONLANDS && GLACIER && EIGER && 440EPX && 440GRX && 440GX && 460SX && 405EX) selects IBM_EMAC_RGMII which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
warning: (PPC_CELL_NATIVE && 440GX && 460EX && 460SX && APM821xx) selects IBM_EMAC_TAH which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
warning: (PPC_CELL_NATIVE && AKEBONO && 440EPX && 440GRX && 440GX && 440SPe && 460EX && 460SX && APM821xx && 405EX) selects IBM_EMAC_EMAC4 which has unmet direct dependencies (NETDEVICES && ETHERNET && NET_VENDOR_IBM)
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [GIT PULL nf-next 00/21] Second Round of IPVS Updates for v3.18
From: Simon Horman @ 2014-09-18 0:27 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: Julian Anastasov, lvs-devel, netdev, netfilter-devel,
Wensong Zhang
In-Reply-To: <20140917235628.GC600@verge.net.au>
On Thu, Sep 18, 2014 at 08:56:29AM +0900, Simon Horman wrote:
> On Wed, Sep 17, 2014 at 10:30:41AM +0200, Pablo Neira Ayuso wrote:
> > On Wed, Sep 17, 2014 at 12:27:03AM +0300, Julian Anastasov wrote:
> > >
> > > Hello,
> > >
> > > On Tue, 16 Sep 2014, Pablo Neira Ayuso wrote:
> > >
> > > > Hi Simon,
> > > >
> > > > On Tue, Sep 16, 2014 at 09:34:14AM +0900, Simon Horman wrote:
> > > > > Hi Pablo,
> > > > >
> > > > > please consider these IPVS updates for v3.18.
> > > > >
> > > > > * Add simple weighted failover scheduler
> > > > > - Thanks to Kenny Mathis
> > > > > * Support v6 real servers in v4 pools and vice versa
> > > > > - Thanks to Alex Gartrell and Julian Anastasov
> > > >
> > > > I need a slightly larger description of this series.
> > > >
> > > > I think you can merge patches 13-19 too. They are mostly two liners
> > > > with a similar description, so they naturally belong to the same
> > > > logical change. I would like to reduce the patchbomb pull request for
> > > > David.
> > >
> > > Good idea, done.
> > >
> > > Simon, I'm attaching such patch that replaces all
> > > these "ipvs: use correct address family in * logs".
> > > It additionally changes the new ip_vs_fo.c scheduler
> > > and ip_vs_wrr.c which was missed.
> >
> > Thanks Julian.
> >
> > @Simon, I can manually apply this batch if that reduces your workload.
> > Please let me know what you prefer.
> >
> > Still I'd really appreciate a longer series description that I can
> > include in the pull-request for David.
>
> Hi Pablo,
>
> I should be able to prepare and send a revised pull-request today.
I have now done so.
^ permalink raw reply
* [PATCH 15/15] ipvs: Allow heterogeneous pools now that we support them
From: Simon Horman @ 2014-09-18 0:26 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Alex Gartrell, Simon Horman
In-Reply-To: <1410999961-7975-1-git-send-email-horms@verge.net.au>
From: Alex Gartrell <agartrell@fb.com>
Remove the temporary consistency check and add a case statement to only
allow ipip mixed dests.
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_ctl.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 462760e..ac7ba68 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -854,10 +854,6 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
EnterFunction(2);
- /* Temporary for consistency */
- if (udest->af != svc->af)
- return -EINVAL;
-
#ifdef CONFIG_IP_VS_IPV6
if (udest->af == AF_INET6) {
atype = ipv6_addr_type(&udest->addr.in6);
@@ -3403,6 +3399,26 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
*/
if (udest.af == 0)
udest.af = svc->af;
+
+ if (udest.af != svc->af) {
+ /* The synchronization protocol is incompatible
+ * with mixed family services
+ */
+ if (net_ipvs(net)->sync_state) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Which connection types do we support? */
+ switch (udest.conn_flags) {
+ case IP_VS_CONN_F_TUNNEL:
+ /* We are able to forward this */
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ }
}
switch (cmd) {
--
2.0.1
^ permalink raw reply related
* [PATCH 13/15] ipvs: use correct address family in scheduler logs
From: Simon Horman @ 2014-09-18 0:25 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Alex Gartrell, Simon Horman
In-Reply-To: <1410999961-7975-1-git-send-email-horms@verge.net.au>
From: Julian Anastasov <ja@ssi.bg>
Needed to support svc->af != dest->af.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_dh.c | 2 +-
net/netfilter/ipvs/ip_vs_fo.c | 2 +-
net/netfilter/ipvs/ip_vs_lc.c | 2 +-
net/netfilter/ipvs/ip_vs_nq.c | 3 ++-
net/netfilter/ipvs/ip_vs_rr.c | 2 +-
net/netfilter/ipvs/ip_vs_sed.c | 3 ++-
net/netfilter/ipvs/ip_vs_sh.c | 8 ++++----
net/netfilter/ipvs/ip_vs_wlc.c | 3 ++-
net/netfilter/ipvs/ip_vs_wrr.c | 2 +-
9 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
index c3b8454..6be5c53 100644
--- a/net/netfilter/ipvs/ip_vs_dh.c
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -234,7 +234,7 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
IP_VS_DBG_BUF(6, "DH: destination IP address %s --> server %s:%d\n",
IP_VS_DBG_ADDR(svc->af, &iph->daddr),
- IP_VS_DBG_ADDR(svc->af, &dest->addr),
+ IP_VS_DBG_ADDR(dest->af, &dest->addr),
ntohs(dest->port));
return dest;
diff --git a/net/netfilter/ipvs/ip_vs_fo.c b/net/netfilter/ipvs/ip_vs_fo.c
index 6a2647d..e09874d 100644
--- a/net/netfilter/ipvs/ip_vs_fo.c
+++ b/net/netfilter/ipvs/ip_vs_fo.c
@@ -44,7 +44,7 @@ ip_vs_fo_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
if (hweight) {
IP_VS_DBG_BUF(6, "FO: server %s:%u activeconns %d weight %d\n",
- IP_VS_DBG_ADDR(svc->af, &hweight->addr),
+ IP_VS_DBG_ADDR(hweight->af, &hweight->addr),
ntohs(hweight->port),
atomic_read(&hweight->activeconns),
atomic_read(&hweight->weight));
diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c
index 2bdcb1c..19a0769 100644
--- a/net/netfilter/ipvs/ip_vs_lc.c
+++ b/net/netfilter/ipvs/ip_vs_lc.c
@@ -59,7 +59,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
else
IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d "
"inactconns %d\n",
- IP_VS_DBG_ADDR(svc->af, &least->addr),
+ IP_VS_DBG_ADDR(least->af, &least->addr),
ntohs(least->port),
atomic_read(&least->activeconns),
atomic_read(&least->inactconns));
diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c
index 961a6de..a8b6340 100644
--- a/net/netfilter/ipvs/ip_vs_nq.c
+++ b/net/netfilter/ipvs/ip_vs_nq.c
@@ -107,7 +107,8 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
out:
IP_VS_DBG_BUF(6, "NQ: server %s:%u "
"activeconns %d refcnt %d weight %d overhead %d\n",
- IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+ IP_VS_DBG_ADDR(least->af, &least->addr),
+ ntohs(least->port),
atomic_read(&least->activeconns),
atomic_read(&least->refcnt),
atomic_read(&least->weight), loh);
diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c
index 176b87c..58bacfc 100644
--- a/net/netfilter/ipvs/ip_vs_rr.c
+++ b/net/netfilter/ipvs/ip_vs_rr.c
@@ -95,7 +95,7 @@ stop:
spin_unlock_bh(&svc->sched_lock);
IP_VS_DBG_BUF(6, "RR: server %s:%u "
"activeconns %d refcnt %d weight %d\n",
- IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
+ IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
atomic_read(&dest->activeconns),
atomic_read(&dest->refcnt), atomic_read(&dest->weight));
diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c
index e446b9f..f8e2d00 100644
--- a/net/netfilter/ipvs/ip_vs_sed.c
+++ b/net/netfilter/ipvs/ip_vs_sed.c
@@ -108,7 +108,8 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
IP_VS_DBG_BUF(6, "SED: server %s:%u "
"activeconns %d refcnt %d weight %d overhead %d\n",
- IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+ IP_VS_DBG_ADDR(least->af, &least->addr),
+ ntohs(least->port),
atomic_read(&least->activeconns),
atomic_read(&least->refcnt),
atomic_read(&least->weight), loh);
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c
index cc65b2f..98a1343 100644
--- a/net/netfilter/ipvs/ip_vs_sh.c
+++ b/net/netfilter/ipvs/ip_vs_sh.c
@@ -138,7 +138,7 @@ ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s,
return dest;
IP_VS_DBG_BUF(6, "SH: selected unavailable server %s:%d, reselecting",
- IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port));
+ IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port));
/* if the original dest is unavailable, loop around the table
* starting from ihash to find a new dest
@@ -153,7 +153,7 @@ ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s,
return dest;
IP_VS_DBG_BUF(6, "SH: selected unavailable "
"server %s:%d (offset %d), reselecting",
- IP_VS_DBG_ADDR(svc->af, &dest->addr),
+ IP_VS_DBG_ADDR(dest->af, &dest->addr),
ntohs(dest->port), roffset);
}
@@ -192,7 +192,7 @@ ip_vs_sh_reassign(struct ip_vs_sh_state *s, struct ip_vs_service *svc)
RCU_INIT_POINTER(b->dest, dest);
IP_VS_DBG_BUF(6, "assigned i: %d dest: %s weight: %d\n",
- i, IP_VS_DBG_ADDR(svc->af, &dest->addr),
+ i, IP_VS_DBG_ADDR(dest->af, &dest->addr),
atomic_read(&dest->weight));
/* Don't move to next dest until filling weight */
@@ -342,7 +342,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
IP_VS_DBG_BUF(6, "SH: source IP address %s --> server %s:%d\n",
IP_VS_DBG_ADDR(svc->af, &iph->saddr),
- IP_VS_DBG_ADDR(svc->af, &dest->addr),
+ IP_VS_DBG_ADDR(dest->af, &dest->addr),
ntohs(dest->port));
return dest;
diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c
index b5b4650..6b366fd 100644
--- a/net/netfilter/ipvs/ip_vs_wlc.c
+++ b/net/netfilter/ipvs/ip_vs_wlc.c
@@ -80,7 +80,8 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
IP_VS_DBG_BUF(6, "WLC: server %s:%u "
"activeconns %d refcnt %d weight %d overhead %d\n",
- IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
+ IP_VS_DBG_ADDR(least->af, &least->addr),
+ ntohs(least->port),
atomic_read(&least->activeconns),
atomic_read(&least->refcnt),
atomic_read(&least->weight), loh);
diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c
index 0546cd5..17e6d44 100644
--- a/net/netfilter/ipvs/ip_vs_wrr.c
+++ b/net/netfilter/ipvs/ip_vs_wrr.c
@@ -216,7 +216,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
found:
IP_VS_DBG_BUF(6, "WRR: server %s:%u "
"activeconns %d refcnt %d weight %d\n",
- IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
+ IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
atomic_read(&dest->activeconns),
atomic_read(&dest->refcnt),
atomic_read(&dest->weight));
--
2.0.1
^ permalink raw reply related
* [PATCH 11/15] ipvs: address family of LBLC entry depends on svc family
From: Simon Horman @ 2014-09-18 0:25 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Alex Gartrell, Simon Horman
In-Reply-To: <1410999961-7975-1-git-send-email-horms@verge.net.au>
From: Julian Anastasov <ja@ssi.bg>
The LBLC entries should use svc->af, not dest->af.
Needed to support svc->af != dest->af.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_lblc.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 547ff33..127f140 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -199,11 +199,11 @@ ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl,
*/
static inline struct ip_vs_lblc_entry *
ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
- struct ip_vs_dest *dest)
+ u16 af, struct ip_vs_dest *dest)
{
struct ip_vs_lblc_entry *en;
- en = ip_vs_lblc_get(dest->af, tbl, daddr);
+ en = ip_vs_lblc_get(af, tbl, daddr);
if (en) {
if (en->dest == dest)
return en;
@@ -213,8 +213,8 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
if (!en)
return NULL;
- en->af = dest->af;
- ip_vs_addr_copy(dest->af, &en->addr, daddr);
+ en->af = af;
+ ip_vs_addr_copy(af, &en->addr, daddr);
en->lastuse = jiffies;
ip_vs_dest_hold(dest);
@@ -521,13 +521,13 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
/* If we fail to create a cache entry, we'll just use the valid dest */
spin_lock_bh(&svc->sched_lock);
if (!tbl->dead)
- ip_vs_lblc_new(tbl, &iph->daddr, dest);
+ ip_vs_lblc_new(tbl, &iph->daddr, svc->af, dest);
spin_unlock_bh(&svc->sched_lock);
out:
IP_VS_DBG_BUF(6, "LBLC: destination IP address %s --> server %s:%d\n",
IP_VS_DBG_ADDR(svc->af, &iph->daddr),
- IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port));
+ IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port));
return dest;
}
--
2.0.1
^ permalink raw reply related
* [PATCH 12/15] ipvs: address family of LBLCR entry depends on svc family
From: Simon Horman @ 2014-09-18 0:25 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Alex Gartrell, Simon Horman
In-Reply-To: <1410999961-7975-1-git-send-email-horms@verge.net.au>
From: Julian Anastasov <ja@ssi.bg>
The LBLCR entries should use svc->af, not dest->af.
Needed to support svc->af != dest->af.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_lblcr.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index 3f21a2f..2229d2d 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -362,18 +362,18 @@ ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl,
*/
static inline struct ip_vs_lblcr_entry *
ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
- struct ip_vs_dest *dest)
+ u16 af, struct ip_vs_dest *dest)
{
struct ip_vs_lblcr_entry *en;
- en = ip_vs_lblcr_get(dest->af, tbl, daddr);
+ en = ip_vs_lblcr_get(af, tbl, daddr);
if (!en) {
en = kmalloc(sizeof(*en), GFP_ATOMIC);
if (!en)
return NULL;
- en->af = dest->af;
- ip_vs_addr_copy(dest->af, &en->addr, daddr);
+ en->af = af;
+ ip_vs_addr_copy(af, &en->addr, daddr);
en->lastuse = jiffies;
/* initialize its dest set */
@@ -706,13 +706,13 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
/* If we fail to create a cache entry, we'll just use the valid dest */
spin_lock_bh(&svc->sched_lock);
if (!tbl->dead)
- ip_vs_lblcr_new(tbl, &iph->daddr, dest);
+ ip_vs_lblcr_new(tbl, &iph->daddr, svc->af, dest);
spin_unlock_bh(&svc->sched_lock);
out:
IP_VS_DBG_BUF(6, "LBLCR: destination IP address %s --> server %s:%d\n",
IP_VS_DBG_ADDR(svc->af, &iph->daddr),
- IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port));
+ IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port));
return dest;
}
--
2.0.1
^ permalink raw reply related
* [PATCH 10/15] ipvs: support ipv4 in ipv6 and ipv6 in ipv4 tunnel forwarding
From: Simon Horman @ 2014-09-18 0:25 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Alex Gartrell, Simon Horman
In-Reply-To: <1410999961-7975-1-git-send-email-horms@verge.net.au>
From: Alex Gartrell <agartrell@fb.com>
Pull the common logic for preparing an skb to prepend the header into a
single function and then set fields such that they can be used in either
case (generalize tos and tclass to dscp, hop_limit and ttl to ttl, etc)
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_conn.c | 12 +++-
net/netfilter/ipvs/ip_vs_xmit.c | 148 +++++++++++++++++++++++++++++-----------
2 files changed, 117 insertions(+), 43 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index fdb4880..13e9cee 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -488,7 +488,12 @@ static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
break;
case IP_VS_CONN_F_TUNNEL:
- cp->packet_xmit = ip_vs_tunnel_xmit;
+#ifdef CONFIG_IP_VS_IPV6
+ if (cp->daf == AF_INET6)
+ cp->packet_xmit = ip_vs_tunnel_xmit_v6;
+ else
+#endif
+ cp->packet_xmit = ip_vs_tunnel_xmit;
break;
case IP_VS_CONN_F_DROUTE:
@@ -514,7 +519,10 @@ static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp)
break;
case IP_VS_CONN_F_TUNNEL:
- cp->packet_xmit = ip_vs_tunnel_xmit_v6;
+ if (cp->daf == AF_INET6)
+ cp->packet_xmit = ip_vs_tunnel_xmit_v6;
+ else
+ cp->packet_xmit = ip_vs_tunnel_xmit;
break;
case IP_VS_CONN_F_DROUTE:
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index fa2fdd7..91f17c1 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -824,6 +824,81 @@ tx_error:
}
#endif
+/* When forwarding a packet, we must ensure that we've got enough headroom
+ * for the encapsulation packet in the skb. This also gives us an
+ * opportunity to figure out what the payload_len, dsfield, ttl, and df
+ * values should be, so that we won't need to look at the old ip header
+ * again
+ */
+static struct sk_buff *
+ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af,
+ unsigned int max_headroom, __u8 *next_protocol,
+ __u32 *payload_len, __u8 *dsfield, __u8 *ttl,
+ __be16 *df)
+{
+ struct sk_buff *new_skb = NULL;
+ struct iphdr *old_iph = NULL;
+#ifdef CONFIG_IP_VS_IPV6
+ struct ipv6hdr *old_ipv6h = NULL;
+#endif
+
+ if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) {
+ new_skb = skb_realloc_headroom(skb, max_headroom);
+ if (!new_skb)
+ goto error;
+ consume_skb(skb);
+ skb = new_skb;
+ }
+
+#ifdef CONFIG_IP_VS_IPV6
+ if (skb_af == AF_INET6) {
+ old_ipv6h = ipv6_hdr(skb);
+ *next_protocol = IPPROTO_IPV6;
+ if (payload_len)
+ *payload_len =
+ ntohs(old_ipv6h->payload_len) +
+ sizeof(*old_ipv6h);
+ *dsfield = ipv6_get_dsfield(old_ipv6h);
+ *ttl = old_ipv6h->hop_limit;
+ if (df)
+ *df = 0;
+ } else
+#endif
+ {
+ old_iph = ip_hdr(skb);
+ /* Copy DF, reset fragment offset and MF */
+ if (df)
+ *df = (old_iph->frag_off & htons(IP_DF));
+ *next_protocol = IPPROTO_IPIP;
+
+ /* fix old IP header checksum */
+ ip_send_check(old_iph);
+ *dsfield = ipv4_get_dsfield(old_iph);
+ *ttl = old_iph->ttl;
+ if (payload_len)
+ *payload_len = ntohs(old_iph->tot_len);
+ }
+
+ return skb;
+error:
+ kfree_skb(skb);
+ return ERR_PTR(-ENOMEM);
+}
+
+static inline int __tun_gso_type_mask(int encaps_af, int orig_af)
+{
+ if (encaps_af == AF_INET) {
+ if (orig_af == AF_INET)
+ return SKB_GSO_IPIP;
+
+ return SKB_GSO_SIT;
+ }
+
+ /* GSO: we need to provide proper SKB_GSO_ value for IPv6:
+ * SKB_GSO_SIT/IPV6
+ */
+ return 0;
+}
/*
* IP Tunneling transmitter
@@ -852,9 +927,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct rtable *rt; /* Route to the other host */
__be32 saddr; /* Source for tunnel */
struct net_device *tdev; /* Device to other host */
- struct iphdr *old_iph = ip_hdr(skb);
- u8 tos = old_iph->tos;
- __be16 df;
+ __u8 next_protocol = 0;
+ __u8 dsfield = 0;
+ __u8 ttl = 0;
+ __be16 df = 0;
+ __be16 *dfp = NULL;
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
int ret, local;
@@ -877,29 +954,21 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
rt = skb_rtable(skb);
tdev = rt->dst.dev;
- /* Copy DF, reset fragment offset and MF */
- df = sysctl_pmtu_disc(ipvs) ? old_iph->frag_off & htons(IP_DF) : 0;
-
/*
* Okay, now see if we can stuff it in the buffer as-is.
*/
max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr);
- if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) {
- struct sk_buff *new_skb =
- skb_realloc_headroom(skb, max_headroom);
-
- if (!new_skb)
- goto tx_error;
- consume_skb(skb);
- skb = new_skb;
- old_iph = ip_hdr(skb);
- }
-
- /* fix old IP header checksum */
- ip_send_check(old_iph);
+ /* We only care about the df field if sysctl_pmtu_disc(ipvs) is set */
+ dfp = sysctl_pmtu_disc(ipvs) ? &df : NULL;
+ skb = ip_vs_prepare_tunneled_skb(skb, cp->af, max_headroom,
+ &next_protocol, NULL, &dsfield,
+ &ttl, dfp);
+ if (IS_ERR(skb))
+ goto tx_error;
- skb = iptunnel_handle_offloads(skb, false, SKB_GSO_IPIP);
+ skb = iptunnel_handle_offloads(
+ skb, false, __tun_gso_type_mask(AF_INET, cp->af));
if (IS_ERR(skb))
goto tx_error;
@@ -916,11 +985,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
iph->version = 4;
iph->ihl = sizeof(struct iphdr)>>2;
iph->frag_off = df;
- iph->protocol = IPPROTO_IPIP;
- iph->tos = tos;
+ iph->protocol = next_protocol;
+ iph->tos = dsfield;
iph->daddr = cp->daddr.ip;
iph->saddr = saddr;
- iph->ttl = old_iph->ttl;
+ iph->ttl = ttl;
ip_select_ident(skb, NULL);
/* Another hack: avoid icmp_send in ip_fragment */
@@ -953,7 +1022,10 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct rt6_info *rt; /* Route to the other host */
struct in6_addr saddr; /* Source for tunnel */
struct net_device *tdev; /* Device to other host */
- struct ipv6hdr *old_iph = ipv6_hdr(skb);
+ __u8 next_protocol = 0;
+ __u32 payload_len = 0;
+ __u8 dsfield = 0;
+ __u8 ttl = 0;
struct ipv6hdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
int ret, local;
@@ -981,19 +1053,14 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/
max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr);
- if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) {
- struct sk_buff *new_skb =
- skb_realloc_headroom(skb, max_headroom);
-
- if (!new_skb)
- goto tx_error;
- consume_skb(skb);
- skb = new_skb;
- old_iph = ipv6_hdr(skb);
- }
+ skb = ip_vs_prepare_tunneled_skb(skb, cp->af, max_headroom,
+ &next_protocol, &payload_len,
+ &dsfield, &ttl, NULL);
+ if (IS_ERR(skb))
+ goto tx_error;
- /* GSO: we need to provide proper SKB_GSO_ value for IPv6 */
- skb = iptunnel_handle_offloads(skb, false, 0); /* SKB_GSO_SIT/IPV6 */
+ skb = iptunnel_handle_offloads(
+ skb, false, __tun_gso_type_mask(AF_INET6, cp->af));
if (IS_ERR(skb))
goto tx_error;
@@ -1008,14 +1075,13 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/
iph = ipv6_hdr(skb);
iph->version = 6;
- iph->nexthdr = IPPROTO_IPV6;
- iph->payload_len = old_iph->payload_len;
- be16_add_cpu(&iph->payload_len, sizeof(*old_iph));
+ iph->nexthdr = next_protocol;
+ iph->payload_len = htons(payload_len);
memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl));
- ipv6_change_dsfield(iph, 0, ipv6_get_dsfield(old_iph));
+ ipv6_change_dsfield(iph, 0, dsfield);
iph->daddr = cp->daddr.in6;
iph->saddr = saddr;
- iph->hop_limit = old_iph->hop_limit;
+ iph->hop_limit = ttl;
/* Another hack: avoid icmp_send in ip_fragment */
skb->ignore_df = 1;
--
2.0.1
^ permalink raw reply related
* [PATCH 09/15] ipvs: Add generic ensure_mtu_is_adequate to handle mixed pools
From: Simon Horman @ 2014-09-18 0:25 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Alex Gartrell, Simon Horman
In-Reply-To: <1410999961-7975-1-git-send-email-horms@verge.net.au>
From: Alex Gartrell <agartrell@fb.com>
The out_rt functions check to see if the mtu is large enough for the packet
and, if not, send icmp messages (TOOBIG or DEST_UNREACH) to the source and
bail out. We needed the ability to send ICMP from the out_rt_v6 function
and DEST_UNREACH from the out_rt function, so we just pulled it out into a
common function.
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
net/netfilter/ipvs/ip_vs_xmit.c | 77 +++++++++++++++++++++++++++--------------
1 file changed, 51 insertions(+), 26 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 034a282..fa2fdd7 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -213,17 +213,57 @@ static inline void maybe_update_pmtu(int skb_af, struct sk_buff *skb, int mtu)
ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu);
}
+static inline bool ensure_mtu_is_adequate(int skb_af, int rt_mode,
+ struct ip_vs_iphdr *ipvsh,
+ struct sk_buff *skb, int mtu)
+{
+#ifdef CONFIG_IP_VS_IPV6
+ if (skb_af == AF_INET6) {
+ struct net *net = dev_net(skb_dst(skb)->dev);
+
+ if (unlikely(__mtu_check_toobig_v6(skb, mtu))) {
+ if (!skb->dev)
+ skb->dev = net->loopback_dev;
+ /* only send ICMP too big on first fragment */
+ if (!ipvsh->fragoffs)
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ IP_VS_DBG(1, "frag needed for %pI6c\n",
+ &ipv6_hdr(skb)->saddr);
+ return false;
+ }
+ } else
+#endif
+ {
+ struct netns_ipvs *ipvs = net_ipvs(skb_net(skb));
+
+ /* If we're going to tunnel the packet and pmtu discovery
+ * is disabled, we'll just fragment it anyway
+ */
+ if ((rt_mode & IP_VS_RT_MODE_TUNNEL) && !sysctl_pmtu_disc(ipvs))
+ return true;
+
+ if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) &&
+ skb->len > mtu && !skb_is_gso(skb))) {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+ htonl(mtu));
+ IP_VS_DBG(1, "frag needed for %pI4\n",
+ &ip_hdr(skb)->saddr);
+ return false;
+ }
+ }
+
+ return true;
+}
+
/* Get route to destination or remote server */
static int
__ip_vs_get_out_rt(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest,
- __be32 daddr, int rt_mode, __be32 *ret_saddr)
+ __be32 daddr, int rt_mode, __be32 *ret_saddr,
+ struct ip_vs_iphdr *ipvsh)
{
struct net *net = dev_net(skb_dst(skb)->dev);
- struct netns_ipvs *ipvs = net_ipvs(net);
struct ip_vs_dest_dst *dest_dst;
struct rtable *rt; /* Route to the other host */
- struct iphdr *iph;
- __be16 df;
int mtu;
int local, noref = 1;
@@ -279,7 +319,6 @@ __ip_vs_get_out_rt(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest,
" daddr=%pI4\n", &dest->addr.ip);
goto err_put;
}
- iph = ip_hdr(skb);
if (unlikely(local)) {
/* skb to local stack, preserve old route */
@@ -290,7 +329,6 @@ __ip_vs_get_out_rt(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest,
if (likely(!(rt_mode & IP_VS_RT_MODE_TUNNEL))) {
mtu = dst_mtu(&rt->dst);
- df = iph->frag_off & htons(IP_DF);
} else {
mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
if (mtu < 68) {
@@ -298,16 +336,10 @@ __ip_vs_get_out_rt(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest,
goto err_put;
}
maybe_update_pmtu(skb_af, skb, mtu);
- /* MTU check allowed? */
- df = sysctl_pmtu_disc(ipvs) ? iph->frag_off & htons(IP_DF) : 0;
}
- /* MTU checking */
- if (unlikely(df && skb->len > mtu && !skb_is_gso(skb))) {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
- IP_VS_DBG(1, "frag needed for %pI4\n", &iph->saddr);
+ if (!ensure_mtu_is_adequate(skb_af, rt_mode, ipvsh, skb, mtu))
goto err_put;
- }
skb_dst_drop(skb);
if (noref) {
@@ -450,15 +482,8 @@ __ip_vs_get_out_rt_v6(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest,
maybe_update_pmtu(skb_af, skb, mtu);
}
- if (unlikely(__mtu_check_toobig_v6(skb, mtu))) {
- if (!skb->dev)
- skb->dev = net->loopback_dev;
- /* only send ICMP too big on first fragment */
- if (!ipvsh->fragoffs)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- IP_VS_DBG(1, "frag needed for %pI6c\n", &ipv6_hdr(skb)->saddr);
+ if (!ensure_mtu_is_adequate(skb_af, rt_mode, ipvsh, skb, mtu))
goto err_put;
- }
skb_dst_drop(skb);
if (noref) {
@@ -565,7 +590,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
rcu_read_lock();
if (__ip_vs_get_out_rt(cp->af, skb, NULL, iph->daddr,
- IP_VS_RT_MODE_NON_LOCAL, NULL) < 0)
+ IP_VS_RT_MODE_NON_LOCAL, NULL, ipvsh) < 0)
goto tx_error;
ip_send_check(iph);
@@ -644,7 +669,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
local = __ip_vs_get_out_rt(cp->af, skb, cp->dest, cp->daddr.ip,
IP_VS_RT_MODE_LOCAL |
IP_VS_RT_MODE_NON_LOCAL |
- IP_VS_RT_MODE_RDR, NULL);
+ IP_VS_RT_MODE_RDR, NULL, ipvsh);
if (local < 0)
goto tx_error;
rt = skb_rtable(skb);
@@ -841,7 +866,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_RT_MODE_LOCAL |
IP_VS_RT_MODE_NON_LOCAL |
IP_VS_RT_MODE_CONNECT |
- IP_VS_RT_MODE_TUNNEL, &saddr);
+ IP_VS_RT_MODE_TUNNEL, &saddr, ipvsh);
if (local < 0)
goto tx_error;
if (local) {
@@ -1032,7 +1057,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
local = __ip_vs_get_out_rt(cp->af, skb, cp->dest, cp->daddr.ip,
IP_VS_RT_MODE_LOCAL |
IP_VS_RT_MODE_NON_LOCAL |
- IP_VS_RT_MODE_KNOWN_NH, NULL);
+ IP_VS_RT_MODE_KNOWN_NH, NULL, ipvsh);
if (local < 0)
goto tx_error;
if (local) {
@@ -1137,7 +1162,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
rcu_read_lock();
local = __ip_vs_get_out_rt(cp->af, skb, cp->dest, cp->daddr.ip, rt_mode,
- NULL);
+ NULL, iph);
if (local < 0)
goto tx_error;
rt = skb_rtable(skb);
--
2.0.1
^ permalink raw reply related
* [PATCH 06/15] ipvs: prevent mixing heterogeneous pools and synchronization
From: Simon Horman @ 2014-09-18 0:25 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: lvs-devel, netdev, netfilter-devel, Wensong Zhang,
Julian Anastasov, Alex Gartrell, Simon Horman
In-Reply-To: <1410999961-7975-1-git-send-email-horms@verge.net.au>
From: Alex Gartrell <agartrell@fb.com>
The synchronization protocol is not compatible with heterogeneous pools, so
we need to verify that we're not turning both on at the same time.
Signed-off-by: Alex Gartrell <agartrell@fb.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
include/net/ip_vs.h | 4 ++++
net/netfilter/ipvs/ip_vs_ctl.c | 15 +++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 7600dbe..576d7f0 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -990,6 +990,10 @@ struct netns_ipvs {
char backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
/* net name space ptr */
struct net *net; /* Needed by timer routines */
+ /* Number of heterogeneous destinations, needed because
+ * heterogeneous are not supported when synchronization is
+ * enabled */
+ unsigned int mixed_address_family_dests;
};
#define DEFAULT_SYNC_THRESHOLD 3
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 6bd2cc6..462760e 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -779,6 +779,12 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
struct ip_vs_scheduler *sched;
int conn_flags;
+ /* We cannot modify an address and change the address family */
+ BUG_ON(!add && udest->af != dest->af);
+
+ if (add && udest->af != svc->af)
+ ipvs->mixed_address_family_dests++;
+
/* set the weight and the flags */
atomic_set(&dest->weight, udest->weight);
conn_flags = udest->conn_flags & IP_VS_CONN_F_DEST_MASK;
@@ -1061,6 +1067,9 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
list_del_rcu(&dest->n_list);
svc->num_dests--;
+ if (dest->af != svc->af)
+ net_ipvs(svc->net)->mixed_address_family_dests--;
+
if (svcupd) {
struct ip_vs_scheduler *sched;
@@ -3256,6 +3265,12 @@ static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs)
attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
return -EINVAL;
+ /* The synchronization protocol is incompatible with mixed family
+ * services
+ */
+ if (net_ipvs(net)->mixed_address_family_dests > 0)
+ return -EINVAL;
+
return start_sync_thread(net,
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
--
2.0.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox