> On Sep 9, 2015, at 7:00 PM, Joe Stringer <[email protected]> wrote:
>
>
(snip)
> diff --git a/datapath/linux/compat/include/linux/openvswitch.h
> b/datapath/linux/compat/include/linux/openvswitch.h
> index 578cd88..69bdf32 100644
> --- a/datapath/linux/compat/include/linux/openvswitch.h
> +++ b/datapath/linux/compat/include/linux/openvswitch.h
> @@ -343,6 +343,8 @@ enum ovs_key_attr {
> OVS_KEY_ATTR_MPLS, /* array of struct ovs_key_mpls.
> * The implementation may restrict
> * the accepted length of the array. */
> + OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */
> + OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */
>
> #ifdef __KERNEL__
> /* Only used within kernel data path. */
> @@ -456,6 +458,15 @@ struct ovs_key_nd {
> __u8 nd_tll[ETH_ALEN];
> };
>
> +/* OVS_KEY_ATTR_CT_STATE flags */
> +#define OVS_CS_F_NEW 0x01 /* Beginning of a new connection. */
> +#define OVS_CS_F_ESTABLISHED 0x02 /* Part of an existing connection. */
> +#define OVS_CS_F_RELATED 0x04 /* Related to an established
> + * connection. */
> +#define OVS_CS_F_INVALID 0x20 /* Could not track connection. */
> +#define OVS_CS_F_REPLY_DIR 0x40 /* Flow is in the reply direction. */
> +#define OVS_CS_F_TRACKED 0x80 /* Conntrack has occurred. */
> +
> /**
> * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
> * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
> @@ -642,6 +653,28 @@ struct ovs_action_push_tnl {
> #endif
>
> /**
> + * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action.
> + * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags.
> + * @OVS_CT_ATTR_ZONE: u16 connection tracking zone.
> + */
> +enum ovs_ct_attr {
> + OVS_CT_ATTR_UNSPEC,
> + OVS_CT_ATTR_FLAGS, /* u32 bitmask of OVS_CT_F_*. */
> + OVS_CT_ATTR_ZONE, /* u16 zone id. */
> + __OVS_CT_ATTR_MAX
> +};
> +
> +#define OVS_CT_ATTR_MAX (__OVS_CT_ATTR_MAX - 1)
> +
> +/*
> + * OVS_CT_ATTR_FLAGS flags - bitmask of %OVS_CT_F_*
> + * @OVS_CT_F_COMMIT: Commits the flow to the conntrack table. This allows
> + * future packets for the same connection to be identified as 'established'
> + * or 'related'.
> + */
> +#define OVS_CT_F_COMMIT 0x01
> +
> +/**
> * enum ovs_action_attr - Action types.
> *
> * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
> @@ -672,6 +705,8 @@ struct ovs_action_push_tnl {
> * 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_CT: Track the connection. Populate the conntrack-related
> + * entries in the flow key.
> *
> * 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
> @@ -702,6 +737,7 @@ enum ovs_action_attr {
> * data immediately followed by a mask.
> * The data must be zero for the unmasked
> * bits. */
> + OVS_ACTION_ATTR_CT, /* One nested OVS_CT_ATTR_* . */
>
I guess this should be “Nested OVS_CT_ATTR_*”, as there can be multiple nested
attributes?
> #ifndef __KERNEL__
> OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/
>
(snip)
> diff --git a/lib/flow.h b/lib/flow.h
> index d8632ff..2d6d3ee 100644
> --- a/lib/flow.h
> +++ b/lib/flow.h
> @@ -103,8 +103,10 @@ struct flow {
> union flow_in_port in_port; /* Input port.*/
> uint32_t recirc_id; /* Must be exact match. */
> uint32_t conj_id; /* Conjunction ID. */
> + uint16_t ct_zone; /* Connection Zone. */
> + uint8_t ct_state; /* Connection state. */
> + uint8_t pad1[3]; /* Pad to 64 bits. */
> ofp_port_t actset_output; /* Output port in action set. */
> - uint8_t pad1[6]; /* Pad to 64 bits. */
>
It would be slightly better to put ct_zone and ct_state right after recirc_id.
This would make miniflows smaller, as the recirc_id, ct_zone, and ct_state
would all be in the same miniflow data unit (conj_id and actset_output are
userspace-only fields, so they would be zeroes for datapath miniflows).
We should probably make ct_state a 16 bit field (uint16_t) in struct flow
already, for future-proofness, even if the kernel interface is still 8 bits.
Also, you should bump FLOW_WC_SEQ to make sure all the relevant places are
updated for the new fields.
> /* L2, Order the same as in the Ethernet header! (64-bit aligned) */
> struct eth_addr dl_dst; /* Ethernet destination address. */
> @@ -980,6 +982,8 @@ pkt_metadata_from_flow(struct pkt_metadata *md, const
> struct flow *flow)
> md->skb_priority = flow->skb_priority;
> md->pkt_mark = flow->pkt_mark;
> md->in_port = flow->in_port;
> + md->ct_state = flow->ct_state;
> + md->ct_zone = flow->ct_zone;
> }
>
> static inline bool is_ip_any(const struct flow *flow)
>
(snip)
> diff --git a/lib/meta-flow.h b/lib/meta-flow.h
> index 02272ef..44a29e9 100644
> --- a/lib/meta-flow.h
> +++ b/lib/meta-flow.h
> @@ -703,6 +703,51 @@ enum OVS_PACKED_ENUM mf_field_id {
> */
> MFF_PKT_MARK,
>
> + /* "ct_state".
> + *
> + * Connection tracking state. The field is populated by the NXAST_CT
> + * action. The following bit values describe the state of the connection:
> + *
> + * - New (0x01): This is the beginning of a new connection.
> + * - Established (0x02): This is part of an already existing
> connection.
> + * - Related (0x04): This is a separate connection that is related to
> an
> + * existing connection.
> + * - Invalid (0x20): This flow could not be associated with a
> connection.
> + * This could be set for a variety of reasons,
> + * including (but not limited to):
> + * - L3/L4 protocol handler is not
> loaded/unavailable.
> + * - L3/L4 protocol handler determines that the
> packet
> + * is malformed or invalid for the current FSM
> stage.
> + * - Packets are unexpected length for protocol.
> + * - Reply (0x40): This flow is in the reply direction, ie it did not
> + * initiate the connection.
> + * - Tracked (0x80): Connection tracking has occurred.
> + *
Have we documented anywhere which of the bits are mutually exclusive and how.
E.g.,
- If -trk, all the other bits are also zeroes (also invalid?)
- new and established are mutually exclusive (+new+est is not possible)
- new and reply are mutually exclusive (reply direction is defined as opposite
of the initial +new)
- related and new can be set at the same time (but does related remain set for
the duration of the connection, or is it also mutually exclusive with
established?)
- apparently related and reply are not mutually exclusive, but when are they
set at the same time?
- are invalid and tracked mutually exclusive?
Also, what are the possible transitions from one state to another?
IMO this information is invaluable for anyone crafting the flows using these
bits.
> + * Type: u8.
> + * Maskable: bitwise.
> + * Formatting: conn state.
> + * Prerequisites: none.
> + * Access: read-only.
> + * NXM: NXM_NX_CT_STATE(105) since v2.5.
> + * OXM: none.
> + */
> + MFF_CT_STATE,
> +
> + /* "ct_zone".
> + *
> + * Connection tracking zone. The field is populated by the
> + * NXAST_CT action.
> + *
> + * Type: be16.
> + * Maskable: no.
> + * Formatting: hexadecimal.
> + * Prerequisites: none.
> + * Access: read-only.
> + * NXM: NXM_NX_CT_ZONE(106) since v2.5.
> + * OXM: none.
> + */
> + MFF_CT_ZONE,
> +
(snip)
> diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
> index c1e46b5..6ea421f 100644
> --- a/lib/ofp-actions.c
> +++ b/lib/ofp-actions.c
> @@ -286,6 +286,9 @@ enum ofp_raw_action_type {
> /* NX1.0+(34): struct nx_action_conjunction. */
> NXAST_RAW_CONJUNCTION,
>
> + /* NX1.0+(35): struct nx_action_conntrack, ... */
> + NXAST_RAW_CT,
> +
> /* ## ------------------ ## */
> /* ## Debugging actions. ## */
> /* ## ------------------ ## */
> @@ -346,6 +349,10 @@ static void *ofpact_put_raw(struct ofpbuf *, enum
> ofp_version,
> static char *OVS_WARN_UNUSED_RESULT ofpacts_parse(
> char *str, struct ofpbuf *ofpacts, enum ofputil_protocol
> *usable_protocols,
> bool allow_instructions, enum ofpact_type outer_action);
> +static enum ofperr ofpacts_pull_openflow_actions__(
> + struct ofpbuf *openflow, unsigned int actions_len,
> + enum ofp_version version, uint32_t allowed_ovsinsts,
> + struct ofpbuf *ofpacts, enum ofpact_type outer_action);
>
> /* Pull off existing actions or instructions. Used by nesting actions to keep
> * ofpacts_parse() oblivious of actions nesting. */
> @@ -4448,6 +4455,245 @@ format_DEBUG_RECIRC(const struct ofpact_null *a
> OVS_UNUSED, struct ds *s)
> {
> ds_put_cstr(s, "debug_recirc");
> }
> +
> +/* Action structure for NXAST_CT.
> + *
> + * Pass traffic to the connection tracker.
> + *
> + * The "zone" specifies a context within which the tracking is done:
> + *
> + * If 'zone_src' is nonzero, this specifies that the zone should be
> + * sourced from a field zone_src[ofs:ofs+nbits]. The format and
> semantics
> + * of 'zone_src' and 'zone_ofs_nbits' are similar to those for the
> + * NXAST_REG_LOAD action. The acceptable nxm_header values for
> 'zone_src'
> + * are the same as the acceptable nxm_header values for the 'src' field
> of
> + * NXAST_REG_MOVE.
> + *
> + * If 'zone_src' is zero, then the value of 'zone_imm' will be used as
> the
> + * connection tracking zone.
> + *
> + * If "recirc_table" has a value other than NX_CT_RECIRC_NONE, then this
> field
> + * specifies that the packet should be logically cloned after the packet is
The packet is logically cloned *before* it is sent through the connection
tracker,
as only the cloned packet gets the ct_state and ct_zone, right?
> + * sent through the connection tracker, and pipeline processing for the
> cloned
> + * packet will continue in the OpenFlow table specified by this value. The
> + * NXM_NX_CT_* fields will be populated for the subsequent processing. It is
> + * strongly recommended that this table is later than the current table, to
> + * prevent loops.
> + *
‘alg’ and ofpacts are introduced in later patches, and I guess it is too much
work to not deal with them here yet?
Anyway, a thought about the nested actions just popped in my mind: The fact
that the actions are nested means that they all must be produced by a single
OpenFlow rule. I.e., the same rule that does conntrack must also set the
labels, etc. This means that either there will be a potentially huge number of
rules with conntrack actions, or the values used must be passed through
registers (which is kind of redundant). Also, a register may not be wide enough
for the data in question (e.g., labels).
> + * A standard "resubmit" action is not sufficient to populate NXM_NX_CT_*
> + * fields, since connection tracking occurs outside of the classifier.
> + */
> +struct nx_action_conntrack {
> + ovs_be16 type; /* OFPAT_VENDOR. */
> + ovs_be16 len; /* At least 24. */
> + ovs_be32 vendor; /* NX_VENDOR_ID. */
> + ovs_be16 subtype; /* NXAST_CT. */
> + ovs_be16 flags; /* Zero or more NX_CT_F_* flags.
> + * Unspecified flag bits must be zero. */
> + ovs_be32 zone_src; /* Connection tracking context. */
> + union {
> + ovs_be16 zone_ofs_nbits;/* Range to use from source field. */
> + ovs_be16 zone_imm; /* Immediate value for zone. */
> + };
> + uint8_t recirc_table; /* Recirculate to a specific table, or
> + NX_CT_RECIRC_NONE for no recirculation. */
> + uint8_t pad[3]; /* Zeroes */
> + ovs_be16 alg; /* Well-known port number for the protocol.
> + * 0 indicates no ALG is required. */
> + /* Followed by a sequence of ofpact elements, until the end of the action
> + * is reached. */
> +};
> +OFP_ASSERT(sizeof(struct nx_action_conntrack) == 24);
> +
> +static enum ofperr
> +decode_ct_zone(const struct nx_action_conntrack *nac,
> + struct ofpact_conntrack *out)
> +{
> + if (nac->zone_src) {
> + enum ofperr error;
> +
> + out->zone_src.field = mf_from_nxm_header(ntohl(nac->zone_src));
> + out->zone_src.ofs = nxm_decode_ofs(nac->zone_ofs_nbits);
> + out->zone_src.n_bits = nxm_decode_n_bits(nac->zone_ofs_nbits);
> + error = mf_check_src(&out->zone_src, NULL);
> + if (error) {
> + return error;
> + }
> +
> + if (out->zone_src.n_bits != 16) {
> + VLOG_WARN_RL(&rl, "zone n_bits %d not within valid range
> [16..16]",
> + out->zone_src.n_bits);
> + return OFPERR_OFPBAC_BAD_SET_LEN;
> + }
> + } else {
> + out->zone_src.field = NULL;
> + out->zone_imm = ntohs(nac->zone_imm);
> + }
> +
> + return 0;
> +}
> +
> +static enum ofperr
> +decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac, struct ofpbuf
> *out)
> +{
> + const size_t ct_offset = ofpacts_pull(out);
> + struct ofpact_conntrack *conntrack;
> + struct ofpbuf openflow;
> + int error = 0;
> +
> + conntrack = ofpact_put_CT(out);
> + conntrack->flags = ntohs(nac->flags);
> + error = decode_ct_zone(nac, conntrack);
> + if (error) {
> + goto out;
> + }
> + conntrack->recirc_table = nac->recirc_table;
> + conntrack->alg = ntohs(nac->alg);
> +
> + ofpbuf_pull(out, sizeof(*conntrack));
> +
> + /* XXX: version */
What about the version?
> + ofpbuf_use_const(&openflow, nac + 1, ntohs(nac->len) - sizeof(*nac));
> + error = ofpacts_pull_openflow_actions__(&openflow, openflow.size,
> + OFP10_VERSION,
> + 1u <<
> OVSINST_OFPIT11_APPLY_ACTIONS,
> + out, OFPACT_CT);
> + if (error) {
> + goto out;
> + }
> +
> + conntrack = ofpbuf_push_uninit(out, sizeof(*conntrack));
> + out->header = &conntrack->ofpact;
> + ofpact_update_len(out, &conntrack->ofpact);
> +
> +out:
> + ofpbuf_push_uninit(out, ct_offset);
> + return error;
> +}
> +
> +static void
> +encode_CT(const struct ofpact_conntrack *conntrack,
> + enum ofp_version ofp_version, struct ofpbuf *out)
> +{
> + struct nx_action_conntrack *nac;
> + const size_t ofs = out->size;
> + size_t len;
> +
> + nac = put_NXAST_CT(out);
> + nac->flags = htons(conntrack->flags);
> + if (conntrack->zone_src.field) {
> + nac->zone_src = htonl(mf_nxm_header(conntrack->zone_src.field->id));
> + nac->zone_ofs_nbits = nxm_encode_ofs_nbits(conntrack->zone_src.ofs,
> +
> conntrack->zone_src.n_bits);
> + } else {
> + nac->zone_src = htonl(0);
> + nac->zone_imm = htons(conntrack->zone_imm);
> + }
> + nac->recirc_table = conntrack->recirc_table;
> + nac->alg = htons(conntrack->alg);
> +
> + len = ofpacts_put_openflow_actions(conntrack->actions,
> + ofpact_ct_get_action_len(conntrack),
> + out, ofp_version);
> + len += sizeof(*nac);
> + nac = ofpbuf_at(out, ofs, sizeof(*nac));
> + nac->len = htons(len);
nac->len should include the conntrack action itself, too, not just the length
of the actions?
> +}
> +
> +/* Parses 'arg' as the argument to a "ct" action, and appends such an
> + * action to 'ofpacts'.
> + *
(snip)
> diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
> index 818f5c8..38a9547 100644
> --- a/lib/ofp-actions.h
> +++ b/lib/ofp-actions.h
> @@ -106,6 +106,7 @@
> OFPACT(EXIT, ofpact_null, ofpact, "exit") \
> OFPACT(SAMPLE, ofpact_sample, ofpact, "sample") \
> OFPACT(UNROLL_XLATE, ofpact_unroll_xlate, ofpact, "unroll_xlate") \
> + OFPACT(CT, ofpact_conntrack, ofpact, "ct") \
> \
> /* Debugging actions. \
> * \
> @@ -471,6 +472,52 @@ BUILD_ASSERT_DECL(offsetof(struct ofpact_nest, actions)
> % OFPACT_ALIGNTO == 0);
> BUILD_ASSERT_DECL(offsetof(struct ofpact_nest, actions)
> == sizeof(struct ofpact_nest));
>
> +/* Bits for 'flags' in struct nx_action_conntrack.
> + *
> + * If NX_CT_F_COMMIT is set, then the connection entry is moved from the
> + * unconfirmed to confirmed list in the tracker. */
> +enum nx_conntrack_flags {
> + NX_CT_F_COMMIT = 1 << 0,
> +};
> +
> +/* Magic value for struct nx_action_conntrack 'recirc_table' field, to
> specify
> + * that the packet should not be recirculated. This value should commonly be
> + * used in conjunction with the NX_CT_F_COMMIT flag above. */
> +#define NX_CT_RECIRC_NONE 0xFF
> +
Maybe this should be defined as OFPTT_ALL, as that is the only invalid table
number (0xff), i.e., NX_CT_RECIRC_NONE may not be defined as anything else,
right?
> +#define CT_MEMBERS \
> + uint16_t flags; \
> + uint16_t zone_imm; \
> + struct mf_subfield zone_src; \
> + uint8_t recirc_table; \
> + uint16_t alg
> +
Maybe put the struct member first to avoid internal padding (mf_subfield has a
pointer, so it will be 64-bit aligned on 64-bit systems)?
> +/* Used to perform build-time size checking for ofpact_conntrack. */
> +struct ofpact_ct_size {
> + CT_MEMBERS;
> +};
> +
> +/* OFPACT_CT.
> + *
> + * Used for NXAST_CT. */
> +struct ofpact_conntrack {
> + struct ofpact ofpact;
> + CT_MEMBERS;
This is slightly ugly, seems to be necessary.
> + uint8_t pad[PAD_SIZE(sizeof(struct ofpact) + sizeof(struct
> ofpact_ct_size),
> + OFPACT_ALIGNTO)];
> + struct ofpact actions[];
> +};
> +BUILD_ASSERT_DECL(offsetof(struct ofpact_conntrack, actions)
> + % OFPACT_ALIGNTO == 0);
> +BUILD_ASSERT_DECL(offsetof(struct ofpact_conntrack, actions)
> + == sizeof(struct ofpact_conntrack));
> +
>
(snip)
> bool dpid_from_string(const char *s, uint64_t *dpidp);
> @@ -710,6 +717,18 @@ struct tcp_header {
> };
> BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header));
>
> +/* Connection states */
> +#define CS_NEW 0x01
> +#define CS_ESTABLISHED 0x02
> +#define CS_RELATED 0x04
> +#define CS_INVALID 0x20
> +#define CS_REPLY_DIR 0x40
> +#define CS_TRACKED 0x80
> +
These seem to match the datapath interface flags. Is that an invariant? Which
ones we use in struct flow?
> +/* Undefined connection state bits. */
> +#define CS_UNSUPPORTED_MASK 0x18
> +#define CS_SUPPORTED_MASK (~CS_UNSUPPORTED_MASK & 0xFF)
> +
>
(snip)
> diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h
> index e7d95bf..7754e68 100644
> --- a/ofproto/ofproto-dpif-rid.h
> +++ b/ofproto/ofproto-dpif-rid.h
> @@ -142,6 +142,7 @@ struct recirc_state {
> struct recirc_metadata metadata; /* Flow metadata. */
> struct ofpbuf *stack; /* Stack if any. */
> mirror_mask_t mirrors; /* Mirrors already output. */
> + bool conntrack; /* Conntrack occurred prior to recirc. */
>
Should this be also called ‘conntracked’?
> /* Actions to be translated on recirculation. */
> uint32_t action_set_len; /* How much of 'ofpacts' consists of an
(snip)
> static void
> check_support(struct dpif_backer *backer)
> {
> @@ -1239,6 +1278,9 @@ check_support(struct dpif_backer *backer)
> backer->support.masked_set_action = check_masked_set_action(backer);
> backer->support.ufid = check_ufid(backer);
> backer->support.tnl_push_pop = dpif_supports_tnl_push_pop(backer->dpif);
> +
> + backer->support.odp.ct_state = check_ct_state(backer);
> + backer->support.odp.ct_zone = check_ct_zone(backer);
> }
>
> static int
> @@ -3935,10 +3977,38 @@ rule_dealloc(struct rule *rule_)
> }
>
> static enum ofperr
> +rule_check(struct rule *rule)
> +{
> + struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->ofproto);
> + const struct odp_support *support;
> + struct match match;
> +
> + minimatch_expand(&rule->cr.match, &match);
> + support = &ofproto_dpif_get_support(ofproto)->odp;
> +
> + if ((match.wc.masks.ct_state && !support->ct_state)
> + || (match.wc.masks.ct_zone && !support->ct_zone)) {
> + return OFPERR_OFPBMC_BAD_FIELD;
> + }
> + if (match.wc.masks.ct_state & CS_UNSUPPORTED_MASK) {
> + return OFPERR_OFPBMC_BAD_MASK;
> + }
> +
> + return 0;
> +}
This check seems somewhat expensive. Maybe get the masks from the minimatch
without expanding it (using MINIFLOW_GET_U8() and MINIFLOW_GET_U16()), like
this:
static enum ofperr
rule_check(struct rule *rule)
{
ct_state_mask = MINIFLOW_GET_U8(&rule->cr.match.mask.masks, ct_state);
ct_zone_mask = MINIFLOW_GET_U16(&rule->cr.match.mask.masks, ct_zone);
if (ct_state_mask || ct_zone_mask) {
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->ofproto);
const struct odp_support *support =
&ofproto_dpif_get_support(ofproto)->odp;
if ((ct_state_mask && !support->ct_state)
|| (ct_zone_mask && !support->ct_zone)) {
return OFPERR_OFPBMC_BAD_FIELD;
}
if (ct_state_mask & CS_UNSUPPORTED_MASK) {
return OFPERR_OFPBMC_BAD_MASK;
}
}
return 0;
}
> +
> +static enum ofperr
> rule_construct(struct rule *rule_)
> OVS_NO_THREAD_SAFETY_ANALYSIS
> {
> struct rule_dpif *rule = rule_dpif_cast(rule_);
> + int error;
> +
> + error = rule_check(rule_);
> + if (error) {
> + return error;
> + }
> +
> ovs_mutex_init_adaptive(&rule->stats_mutex);
> rule->stats.n_packets = 0;
> rule->stats.n_bytes = 0;
(snip)
> --- a/tests/system-traffic.at
> +++ b/tests/system-traffic.at
> @@ -139,3 +139,472 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w
> 2 10.1.1.100 | FORMAT_PI
>
> OVS_TRAFFIC_VSWITCHD_STOP
> AT_CLEANUP
> +
> +AT_SETUP([conntrack - controller])
> +CHECK_CONNTRACK()
> +OVS_TRAFFIC_VSWITCHD_START(
> + [set-fail-mode br0 standalone -- ])
> +
> +ADD_NAMESPACES(at_ns0, at_ns1)
> +
> +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
> +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
> +
> +dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from
> ns1->ns0.
> +AT_DATA([flows.txt], [dnl
> +priority=1,action=drop
> +priority=10,arp,action=normal
> +in_port=1,udp,action=ct(commit),controller
> +in_port=2,ct_state=-trk,udp,action=ct(table=0)
> +in_port=2,ct_state=+trk+est-new,udp,action=controller
I forgot the default priority value, would be useful to specify the priority of
all the flows to make this more readable.
I’ll check the rest later. However, I was not able to run any of the tests with
the net-next openvswitch kernel module, so I need to look at that before going
on.
Jarno
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev