[ovs-dev] [PATCH V11 1/4] Flow and action changes for 802.1AD

Jarno Rajahalme jrajahalme at nicira.com
Mon Jun 29 20:38:06 UTC 2015


> On Jun 23, 2015, at 11:38 AM, Thomas F Herbert <thomasfherbert at gmail.com> wrote:
> 
> From: "Thomas F. Herbert" <thomasfherbert at gmail.com>
> 
> The flow structure is updated to hold the customer tci.
> Flow key extraction is changed to add support for ctci and both TPIDs.
> Parsing to support pushing and popping with both single and double
> tagged vlans. In response to reviewers comments on V6, all changes
> affected by the flow structure are gathered in this patch.
> 
> Signed-off-by: Thomas F Herbert <thomasfherbert at gmail.com>
> ---
> lib/flow.c                   | 14 +++++++-------
> lib/flow.h                   | 16 +++++++++++-----
> lib/match.c                  |  2 +-
> lib/nx-match.c               |  2 +-
> lib/ofp-actions.c            | 32 +++++++++++++++++++-------------
> lib/ofp-actions.h            | 14 +++++++++++---
> lib/ofp-util.c               |  2 +-
> ofproto/ofproto-dpif-rid.h   |  2 +-
> ofproto/ofproto-dpif-xlate.c | 13 ++++++++++++-
> 9 files changed, 64 insertions(+), 33 deletions(-)
> 
> diff --git a/lib/flow.c b/lib/flow.c
> index 3e99d5e..3bfcb26 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -123,7 +123,7 @@ struct mf_ctx {
>  * away.  Some GCC versions gave warnings on ALWAYS_INLINE, so these are
>  * defined as macros. */
> 
> -#if (FLOW_WC_SEQ != 31)
> +#if (FLOW_WC_SEQ != 32)
> #define MINIFLOW_ASSERT(X) ovs_assert(X)
> BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
>                "assertions enabled. Consider updating FLOW_WC_SEQ after "
> @@ -291,7 +291,7 @@ parse_vlan(const void **datap, size_t *sizep)
> 
>     data_pull(datap, sizep, ETH_ADDR_LEN * 2);
> 
> -    if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
> +    if (eth_type_vlan(eth->eth_type)) {
>         if (OVS_LIKELY(*sizep
>                        >= sizeof(struct qtag_prefix) + sizeof(ovs_be16))) {
>             const struct qtag_prefix *qp = data_pull(datap, sizep, sizeof *qp);

Maybe I am missing something, but I am surprised that the new struct flow fields are not populated in miniflow_extract() following the call to parse_vlan(). Or is the customer TCI not present in the packet?

  Jarno

> @@ -766,7 +766,7 @@ flow_get_metadata(const struct flow *flow, struct match *flow_metadata)
> {
>     int i;
> 
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
>     match_init_catchall(flow_metadata);
>     if (flow->tunnel.tun_id != htonll(0)) {
> @@ -942,7 +942,7 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
>     memset(&wc->masks, 0x0, sizeof wc->masks);
> 
>     /* Update this function whenever struct flow changes. */
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
>     if (flow->tunnel.ip_dst) {
>         if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
> @@ -1041,7 +1041,7 @@ uint64_t
> flow_wc_map(const struct flow *flow)
> {
>     /* Update this function whenever struct flow changes. */
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
>     uint64_t map = (flow->tunnel.ip_dst) ? MINIFLOW_MAP(tunnel) : 0;
> 
> @@ -1093,7 +1093,7 @@ void
> flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
> {
>     /* Update this function whenever struct flow changes. */
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
>     memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
>     memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
> @@ -1648,7 +1648,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,
>         flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label));
> 
>         /* Clear all L3 and L4 fields and dp_hash. */
> -        BUILD_ASSERT(FLOW_WC_SEQ == 31);
> +        BUILD_ASSERT(FLOW_WC_SEQ == 32);
>         memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
>                sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
>         flow->dp_hash = 0;
> diff --git a/lib/flow.h b/lib/flow.h
> index 70554e4..9d34775 100644
> --- a/lib/flow.h
> +++ b/lib/flow.h
> @@ -39,7 +39,7 @@ struct match;
> /* This sequence number should be incremented whenever anything involving flows
>  * or the wildcarding of flows changes.  This will cause build assertion
>  * failures in places which likely need to be updated. */
> -#define FLOW_WC_SEQ 31
> +#define FLOW_WC_SEQ 32
> 
> /* Number of Open vSwitch extension 32-bit registers. */
> #define FLOW_N_REGS 8
> @@ -114,7 +114,13 @@ struct flow {
>     uint8_t dl_dst[ETH_ADDR_LEN]; /* Ethernet destination address. */
>     uint8_t dl_src[ETH_ADDR_LEN]; /* Ethernet source address. */
>     ovs_be16 dl_type;           /* Ethernet frame type. */
> -    ovs_be16 vlan_tci;          /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
> +    ovs_be16 vlan_tci;          /* If 802.1Q, TCI | VLAN_CFI; If 802.1ad,
> +                                 * outer tag, otherwise 0. */
> +    ovs_be16 vlan_ctci;         /* If 802.1ad, Customer TCI | VLAN_CFI,
> +                                 * inner tag, otherwise 0. */
> +    ovs_be16 vlan_tpid;         /* Vlan protocol type,
> +                                 * either 802.1ad or 802.1q. */
> +    uint32_t pad2;              /* Pad to 64 bits. */
>     ovs_be32 mpls_lse[ROUND_UP(FLOW_MAX_MPLS_LABELS, 2)]; /* MPLS label stack
>                                                              (with padding). */
>     /* L3 (64-bit aligned) */
> @@ -131,7 +137,7 @@ struct flow {
>     uint8_t arp_sha[ETH_ADDR_LEN]; /* ARP/ND source hardware address. */
>     uint8_t arp_tha[ETH_ADDR_LEN]; /* ARP/ND target hardware address. */
>     ovs_be16 tcp_flags;         /* TCP flags. With L3 to avoid matching L4. */
> -    ovs_be16 pad2;              /* Pad to 64 bits. */
> +    ovs_be16 pad3;              /* Pad to 64 bits. */
> 
>     /* L4 (64-bit aligned) */
>     ovs_be16 tp_src;            /* TCP/UDP/SCTP source port. */
> @@ -156,8 +162,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0);
> 
> /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
> BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t)
> -                  == sizeof(struct flow_tnl) + 192
> -                  && FLOW_WC_SEQ == 31);
> +                  == sizeof(struct flow_tnl) + 200
> +                  && FLOW_WC_SEQ == 32);
> 
> /* Incremental points at which flow classification may be performed in
>  * segments.
> diff --git a/lib/match.c b/lib/match.c
> index 7d0b409..cab70e8 100644
> --- a/lib/match.c
> +++ b/lib/match.c
> @@ -912,7 +912,7 @@ match_format(const struct match *match, struct ds *s, int priority)
> 
>     int i;
> 
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
>     if (priority != OFP_DEFAULT_PRIORITY) {
>         ds_put_format(s, "priority=%d,", priority);
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index 21f291c..aed283c 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -865,7 +865,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
>     int match_len;
>     int i;
> 
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
>     /* Metadata. */
>     if (match->wc.masks.dp_hash) {
> diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
> index 10e2a92..9ed8b49 100644
> --- a/lib/ofp-actions.c
> +++ b/lib/ofp-actions.c
> @@ -1269,16 +1269,20 @@ format_STRIP_VLAN(const struct ofpact_null *a, struct ds *s)
> static enum ofperr
> decode_OFPAT_RAW11_PUSH_VLAN(ovs_be16 eth_type, struct ofpbuf *out)
> {
> -    if (eth_type != htons(ETH_TYPE_VLAN_8021Q)) {
> -        /* XXX 802.1AD(QinQ) isn't supported at the moment */
> +    struct ofpact_push_vlan *oam;
> +
> +    if (!eth_type_vlan(eth_type)) {
> +        /* XXX Only 802.1q or 802.1AD(QinQ) are supported.  */
>         return OFPERR_OFPBAC_BAD_ARGUMENT;
>     }
> -    ofpact_put_PUSH_VLAN(out);
> +    oam = ofpact_put_PUSH_VLAN(out);
> +    oam->ethertype = eth_type;
> +
>     return 0;
> }
> 
> static void
> -encode_PUSH_VLAN(const struct ofpact_null *null OVS_UNUSED,
> +encode_PUSH_VLAN(const struct ofpact_push_vlan *push_vlan,
>                  enum ofp_version ofp_version, struct ofpbuf *out)
> {
>     if (ofp_version == OFP10_VERSION) {
> @@ -1286,7 +1290,7 @@ encode_PUSH_VLAN(const struct ofpact_null *null OVS_UNUSED,
>          * follow this action. */
>     } else {
>         /* XXX ETH_TYPE_VLAN_8021AD case */
> -        put_OFPAT11_PUSH_VLAN(out, htons(ETH_TYPE_VLAN_8021Q));
> +        put_OFPAT11_PUSH_VLAN(out, push_vlan->ethertype);
>     }
> }
> 
> @@ -1298,25 +1302,25 @@ parse_PUSH_VLAN(char *arg, struct ofpbuf *ofpacts,
>     char *error;
> 
>     *usable_protocols &= OFPUTIL_P_OF11_UP;
> -    error = str_to_u16(arg, "ethertype", &ethertype);
> +    error = str_to_u16(arg, "push_vlan", &ethertype);
>     if (error) {
>         return error;
>     }
> 
> -    if (ethertype != ETH_TYPE_VLAN_8021Q) {
> -        /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */
> +    if (!eth_type_vlan(htons(ethertype))) {
> +        /* Check for valid VLAN ethertypes */
>         return xasprintf("%s: not a valid VLAN ethertype", arg);
>     }
> 
> -    ofpact_put_PUSH_VLAN(ofpacts);
> +    ofpact_put_PUSH_VLAN(ofpacts)->ethertype = htons(ethertype);
>     return NULL;
> }
> 
> static void
> -format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
> +format_PUSH_VLAN(const struct ofpact_push_vlan *a OVS_UNUSED, struct ds *s)
> {
>     /* XXX 802.1AD case*/
> -    ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q);
> +    ds_put_format(s, "push_vlan:%#"PRIx16, ntohs(a->ethertype));
> }
> 
> /* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */
> @@ -5491,8 +5495,9 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
>         return 0;
> 
>     case OFPACT_PUSH_VLAN:
> -        if (flow->vlan_tci & htons(VLAN_CFI)) {
> -            /* Multiple VLAN headers not supported. */
> +        if (flow->vlan_tci & htons(VLAN_CFI) &&
> +            flow->vlan_ctci & htons(VLAN_CFI)) {
> +            /* More then 2 levels of VLAN headers not supported. */
>             return OFPERR_OFPBAC_BAD_TAG;
>         }
>         /* Temporary mark that we have a vlan tag. */
> @@ -6131,6 +6136,7 @@ ofpacts_get_meter(const struct ofpact ofpacts[], size_t ofpacts_len)
> 
> /* Formatting ofpacts. */
> 
> +
> static void
> ofpact_format(const struct ofpact *a, struct ds *s)
> {
> diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
> index 785c814..0314da3 100644
> --- a/lib/ofp-actions.h
> +++ b/lib/ofp-actions.h
> @@ -66,7 +66,7 @@
>     OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,    ofpact, "set_vlan_vid") \
>     OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,    ofpact, "set_vlan_pcp") \
>     OFPACT(STRIP_VLAN,      ofpact_null,        ofpact, "strip_vlan")   \
> -    OFPACT(PUSH_VLAN,       ofpact_null,        ofpact, "push_vlan")    \
> +    OFPACT(PUSH_VLAN,       ofpact_push_vlan,   ofpact, "push_vlan")    \
>     OFPACT(SET_ETH_SRC,     ofpact_mac,         ofpact, "mod_dl_src")   \
>     OFPACT(SET_ETH_DST,     ofpact_mac,         ofpact, "mod_dl_dst")   \
>     OFPACT(SET_IPV4_SRC,    ofpact_ipv4,        ofpact, "mod_nw_src")   \
> @@ -395,7 +395,15 @@ struct ofpact_set_field {
>     union mf_value mask;
> };
> 
> -/* OFPACT_PUSH_VLAN/MPLS/PBB
> +/* OFPACT_PUSH_VLAN
> + *
> + * Used for OFPAT11_PUSH_VLAN. */
> +struct ofpact_push_vlan {
> +    struct ofpact ofpact;
> +    ovs_be16 ethertype;
> +};
> +
> +/* OFPACT_PUSH_MPLS
>  *
>  * Used for NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */
> struct ofpact_push_mpls {
> @@ -405,7 +413,7 @@ struct ofpact_push_mpls {
> 
> /* OFPACT_POP_MPLS
>  *
> - * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS.. */
> + * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS. */
> struct ofpact_pop_mpls {
>     struct ofpact ofpact;
>     ovs_be16 ethertype;
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index 89359c1..dc063d7 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -195,7 +195,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
> void
> ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
> {
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
>     /* Initialize most of wc. */
>     flow_wildcards_init_catchall(wc);
> diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h
> index 81a61a2..dc533ce 100644
> --- a/ofproto/ofproto-dpif-rid.h
> +++ b/ofproto/ofproto-dpif-rid.h
> @@ -91,7 +91,7 @@ struct rule;
> /* Metadata for restoring pipeline context after recirculation.  Helpers
>  * are inlined below to keep them together with the definition for easier
>  * updates. */
> -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
> 
> struct recirc_metadata {
>     /* Metadata in struct flow. */
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 8c68273..7395f14 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -2761,6 +2761,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
>     struct flow *flow = &ctx->xin->flow;
>     struct flow_tnl flow_tnl;
>     ovs_be16 flow_vlan_tci;
> +    ovs_be16 flow_vlan_ctci;
>     uint32_t flow_pkt_mark;
>     uint8_t flow_nw_tos;
>     odp_port_t out_port, odp_port;
> @@ -2769,7 +2770,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
> 
>     /* If 'struct flow' gets additional metadata, we'll need to zero it out
>      * before traversing a patch port. */
> -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
> +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32);
>     memset(&flow_tnl, 0, sizeof flow_tnl);
> 
>     if (!xport) {
> @@ -2912,6 +2913,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
>     }
> 
>     flow_vlan_tci = flow->vlan_tci;
> +    flow_vlan_ctci = flow->vlan_ctci;
>     flow_pkt_mark = flow->pkt_mark;
>     flow_nw_tos = flow->nw_tos;
> 
> @@ -3033,6 +3035,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
>  out:
>     /* Restore flow */
>     flow->vlan_tci = flow_vlan_tci;
> +    flow->vlan_ctci = flow_vlan_ctci;
>     flow->pkt_mark = flow_pkt_mark;
>     flow->nw_tos = flow_nw_tos;
> }
> @@ -4174,6 +4177,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
>             /* XXX 802.1AD(QinQ) */
>             memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
>             flow->vlan_tci = htons(VLAN_CFI);
> +            if (ofpact_get_PUSH_VLAN(a)->ethertype == htons(ETH_TYPE_VLAN_8021AD)) {
> +                memset(&wc->masks.vlan_ctci, 0xff, sizeof wc->masks.vlan_ctci);
> +                flow->vlan_ctci |= htons(VLAN_CFI);
> +                memset(&wc->masks.vlan_tpid, 0xff, sizeof wc->masks.vlan_tpid);
> +                flow->vlan_tpid = htons(ETH_TYPE_VLAN_8021AD);
> +            } else if (ofpact_get_PUSH_VLAN(a)->ethertype == htons(ETH_TYPE_VLAN_8021Q)) {
> +                flow->vlan_tpid = htons(ETH_TYPE_VLAN_8021Q);
> +            }
>             break;
> 
>         case OFPACT_SET_ETH_SRC:
> -- 
> 2.1.0
> 
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev




More information about the dev mailing list