[ovs-dev] [PATCH v2 2/2] NSH: Adjust NSH wire format to the latest IETF draft

Jan Scheurich jan.scheurich at ericsson.com
Tue Nov 7 15:34:09 UTC 2017


This commit adjusts the NSH user space implementation in OVS to
the latest wire format defined in draft-ietf-sfc-nsh-28 (November 3
2017). The NSH_MDTYPE field was reduced from 8 to 4 bits. The FLAGS
field is reduced from 8 to 2 bits. A new 6 bit TTL header field is
added. The TTL field is set to 63 at encap(nsh).

Match and set_field support for the newly introduced TTL header field
and a corresponding dec_nsh_ttl action is not yet included and will be
implemented in a future patch.

Signed-off-by: Jan Scheurich <jan.scheurich at ericsson.com>
Signed-off-by: Ben Pfaff <blp at ovn.org>
---
 include/openvswitch/nsh.h | 219 +++++++++++++++++++++++++++++++++++++++-------
 lib/flow.c                |   2 +-
 lib/odp-execute.c         |  15 ++--
 lib/packets.c             |   9 +-
 4 files changed, 204 insertions(+), 41 deletions(-)

diff --git a/include/openvswitch/nsh.h b/include/openvswitch/nsh.h
index a3611d0..38d443b 100644
--- a/include/openvswitch/nsh.h
+++ b/include/openvswitch/nsh.h
@@ -5,41 +5,189 @@

 /*
  * Network Service Header:
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |Ver|O|C|R|R|R|R|R|R|    Length   |   MD Type   |  Next Proto   |
+ * |Ver|O|U|    TTL    |   Length  |U|U|U|U|MD Type| Next Protocol |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |                Service Path ID                | Service Index |
+ * |          Service Path Identifier (SPI)        | Service Index |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * |                                                               |
- * ~               Mandatory/Optional Context Header               ~
+ * ~               Mandatory/Optional Context Headers              ~
  * |                                                               |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * Ver = The version field is used to ensure backward compatibility
- *       going forward with future NSH updates.  It MUST be set to 0x0
- *       by the sender, in this first revision of NSH.
  *
- * O = OAM. when set to 0x1 indicates that this packet is an operations
- *     and management (OAM) packet.  The receiving SFF and SFs nodes
- *     MUST examine the payload and take appropriate action.
+ * Version: The version field is used to ensure backward compatibility
+ * going forward with future NSH specification updates.  It MUST be set
+ * to 0x0 by the sender, in this first revision of NSH.  Given the
+ * widespread implementation of existing hardware that uses the first
+ * nibble after an MPLS label stack for ECMP decision processing, this
+ * document reserves version 01b and this value MUST NOT be used in
+ * future versions of the protocol.  Please see [RFC7325] for further
+ * discussion of MPLS-related forwarding requirements.
  *
- * C = context. Indicates that a critical metadata TLV is present.
+ * O bit: Setting this bit indicates an Operations, Administration, and
+ * Maintenance (OAM) packet.  The actual format and processing of SFC
+ * OAM packets is outside the scope of this specification (see for
+ * example [I-D.ietf-sfc-oam-framework] for one approach).
  *
- * Length : total length, in 4-byte words, of NSH including the Base
- *          Header, the Service Path Header and the optional variable
- *          TLVs.
- * MD Type: indicates the format of NSH beyond the mandatory Base Header
- *          and the Service Path Header.
+ * The O bit MUST be set for OAM packets and MUST NOT be set for non-OAM
+ * packets.  The O bit MUST NOT be modified along the SFP.
  *
- * Next Protocol: indicates the protocol type of the original packet. A
- *          new IANA registry will be created for protocol type.
+ * SF/SFF/SFC Proxy/Classifier implementations that do not support SFC
+ * OAM procedures SHOULD discard packets with O bit set, but MAY support
+ * a configurable parameter to enable forwarding received SFC OAM
+ * packets unmodified to the next element in the chain.  Forwarding OAM
+ * packets unmodified by SFC elements that do not support SFC OAM
+ * procedures may be acceptable for a subset of OAM functions, but can
+ * result in unexpected outcomes for others, thus it is recommended to
+ * analyze the impact of forwarding an OAM packet for all OAM functions
+ * prior to enabling this behavior.  The configurable parameter MUST be
+ * disabled by default.
  *
- * Service Path Identifier (SPI): identifies a service path.
- *          Participating nodes MUST use this identifier for Service
- *          Function Path selection.
+ * TTL: Indicates the maximum SFF hops for an SFP.  This field is used
+ * for service plane loop detection.  The initial TTL value SHOULD be
+ * configurable via the control plane; the configured initial value can
+ * be specific to one or more SFPs.  If no initial value is explicitly
+ * provided, the default initial TTL value of 63 MUST be used.  Each SFF
+ * involved in forwarding an NSH packet MUST decrement the TTL value by
+ * 1 prior to NSH forwarding lookup.  Decrementing by 1 from an incoming
+ * value of 0 shall result in a TTL value of 63.  The packet MUST NOT be
+ * forwarded if TTL is, after decrement, 0.
  *
- * Service Index (SI): provides location within the SFP.
+ * All other flag fields, marked U, are unassigned and available for
+ * future use, see Section 11.2.1.  Unassigned bits MUST be set to zero
+ * upon origination, and MUST be ignored and preserved unmodified by
+ * other NSH supporting elements.  Elements which do not understand the
+ * meaning of any of these bits MUST NOT modify their actions based on
+ * those unknown bits.
  *
- * [0] https://tools.ietf.org/html/draft-ietf-sfc-nsh-13
+ * Length: The total length, in 4-byte words, of NSH including the Base
+ * Header, the Service Path Header, the Fixed Length Context Header or
+ * Variable Length Context Header(s).  The length MUST be 0x6 for MD
+ * Type equal to 0x1, and MUST be 0x2 or greater for MD Type equal to
+ * 0x2.  The length of the NSH header MUST be an integer multiple of 4
+ * bytes, thus variable length metadata is always padded out to a
+ * multiple of 4 bytes.
+ *
+ * MD Type: Indicates the format of NSH beyond the mandatory Base Header
+ * and the Service Path Header.  MD Type defines the format of the
+ * metadata being carried.
+ *
+ * 0x0 - This is a reserved value.  Implementations SHOULD silently
+ * discard packets with MD Type 0x0.
+ *
+ * 0x1 - This indicates that the format of the header includes a fixed
+ * length Context Header (see Figure 4 below).
+ *
+ * 0x2 - This does not mandate any headers beyond the Base Header and
+ * Service Path Header, but may contain optional variable length Context
+ * Header(s).  The semantics of the variable length Context Header(s)
+ * are not defined in this document.  The format of the optional
+ * variable length Context Headers is provided in Section 2.5.1.
+ *
+ * 0xF - This value is reserved for experimentation and testing, as per
+ * [RFC3692].  Implementations not explicitly configured to be part of
+ * an experiment SHOULD silently discard packets with MD Type 0xF.
+ *
+ * Next Protocol: indicates the protocol type of the encapsulated data.
+ * NSH does not alter the inner payload, and the semantics on the inner
+ * protocol remain unchanged due to NSH service function chaining.
+ * Please see the IANA Considerations section below, Section 11.2.5.
+ *
+ * This document defines the following Next Protocol values:
+ *
+ * 0x1: IPv4
+ * 0x2: IPv6
+ * 0x3: Ethernet
+ * 0x4: NSH
+ * 0x5: MPLS
+ * 0xFE: Experiment 1
+ * 0xFF: Experiment 2
+ *
+ * Packets with Next Protocol values not supported SHOULD be silently
+ * dropped by default, although an implementation MAY provide a
+ * configuration parameter to forward them.  Additionally, an
+ * implementation not explicitly configured for a specific experiment
+ * [RFC3692] SHOULD silently drop packets with Next Protocol values 0xFE
+ * and 0xFF.
+ *
+ * Service Path Identifier (SPI): Identifies a service path.
+ * Participating nodes MUST use this identifier for Service Function
+ * Path selection.  The initial classifier MUST set the appropriate SPI
+ * for a given classification result.
+ *
+ * Service Index (SI): Provides location within the SFP.  The initial
+ * classifier for a given SFP SHOULD set the SI to 255, however the
+ * control plane MAY configure the initial value of SI as appropriate
+ * (i.e., taking into account the length of the service function path).
+ * The Service Index MUST be decremented by a value of 1 by Service
+ * Functions or by SFC Proxy nodes after performing required services
+ * and the new decremented SI value MUST be used in the egress packet's
+ * NSH.  The initial Classifier MUST send the packet to the first SFF in
+ * the identified SFP for forwarding along an SFP.  If re-classification
+ * occurs, and that re-classification results in a new SPI, the
+ * (re)classifier is, in effect, the initial classifier for the
+ * resultant SPI.
+ *
+ * The SI is used in conjunction the with Service Path Identifier for
+ * Service Function Path Selection and for determining the next SFF/SF
+ * in the path.  The SI is also valuable when troubleshooting or
+ * reporting service paths.  Additionally, while the TTL field is the
+ * main mechanism for service plane loop detection, the SI can also be
+ * used for detecting service plane loops.
+ *
+ * When the Base Header specifies MD Type = 0x1, a Fixed Length Context
+ * Header (16-bytes) MUST be present immediately following the Service
+ * Path Header. The value of a Fixed Length Context
+ * Header that carries no metadata MUST be set to zero.
+ *
+ * When the base header specifies MD Type = 0x2, zero or more Variable
+ * Length Context Headers MAY be added, immediately following the
+ * Service Path Header (see Figure 5).  Therefore, Length = 0x2,
+ * indicates that only the Base Header followed by the Service Path
+ * Header are present.  The optional Variable Length Context Headers
+ * MUST be of an integer number of 4-bytes.  The base header Length
+ * field MUST be used to determine the offset to locate the original
+ * packet or frame for SFC nodes that require access to that
+ * information.
+ *
+ * The format of the optional variable length Context Headers
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |          Metadata Class       |      Type     |U|    Length   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      Variable Metadata                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Metadata Class (MD Class): Defines the scope of the 'Type' field to
+ * provide a hierarchical namespace.  The IANA Considerations
+ * Section 11.2.4 defines how the MD Class values can be allocated to
+ * standards bodies, vendors, and others.
+ *
+ * Type: Indicates the explicit type of metadata being carried.  The
+ * definition of the Type is the responsibility of the MD Class owner.
+ *
+ * Unassigned bit: One unassigned bit is available for future use. This
+ * bit MUST NOT be set, and MUST be ignored on receipt.
+ *
+ * Length: Indicates the length of the variable metadata, in bytes.  In
+ * case the metadata length is not an integer number of 4-byte words,
+ * the sender MUST add pad bytes immediately following the last metadata
+ * byte to extend the metadata to an integer number of 4-byte words.
+ * The receiver MUST round up the length field to the nearest 4-byte
+ * word boundary, to locate and process the next field in the packet.
+ * The receiver MUST access only those bytes in the metadata indicated
+ * by the length field (i.e., actual number of bytes) and MUST ignore
+ * the remaining bytes up to the nearest 4-byte word boundary.  The
+ * Length may be 0 or greater.
+ *
+ * A value of 0 denotes a Context Header without a Variable Metadata
+ * field.
+ *
+ * [0] https://www.ietf.org/id/draft-ietf-sfc-nsh-19.txt
  */

 #ifdef  __cplusplus
@@ -62,32 +210,36 @@ struct nsh_md2_tlv {
 };

 struct nsh_hdr {
-    ovs_be16 ver_flags_len;
+    ovs_be16 ver_flags_ttl_len;
     uint8_t md_type;
     uint8_t next_proto;
     ovs_16aligned_be32 path_hdr;
     union {
         struct nsh_md1_ctx md1;
-        struct nsh_md2_tlv md2;
+        struct nsh_md2_tlv md2;     /* This represents the first element of
+                                       a list of zero or more md2_tlv structs.
+                                       It may not be present. */
     };
 };

 /* Masking NSH header fields. */
 #define NSH_VER_MASK       0xc000
 #define NSH_VER_SHIFT      14
-#define NSH_FLAGS_MASK     0x3fc0
-#define NSH_FLAGS_SHIFT    6
+#define NSH_FLAGS_MASK     0x3000
+#define NSH_FLAGS_SHIFT    12
+#define NSH_TTL_MASK       0x0fc0
+#define NSH_TTL_SHIFT      6
 #define NSH_LEN_MASK       0x003f
 #define NSH_LEN_SHIFT      0

+#define NSH_MDTYPE_MASK    0x0f
+#define NSH_MDTYPE_SHIFT   0
+
 #define NSH_SPI_MASK       0xffffff00
 #define NSH_SPI_SHIFT      8
 #define NSH_SI_MASK        0x000000ff
 #define NSH_SI_SHIFT       0

-#define NSH_DST_PORT    4790     /* UDP Port for NSH on VXLAN. */
-#define ETH_P_NSH       0x894F   /* Ethertype for NSH. */
-
 /* NSH Base Header Next Protocol. */
 #define NSH_P_IPV4        0x01
 #define NSH_P_IPV6        0x02
@@ -113,7 +265,14 @@ struct nsh_hdr {
 static inline uint16_t
 nsh_hdr_len(const struct nsh_hdr *nsh)
 {
-    return ((ntohs(nsh->ver_flags_len) & NSH_LEN_MASK) >> NSH_LEN_SHIFT) << 2;
+    return ((ntohs(nsh->ver_flags_ttl_len) & NSH_LEN_MASK)
+            >> NSH_LEN_SHIFT) << 2;
+}
+
+static inline uint8_t
+nsh_md_type(const struct nsh_hdr *nsh)
+{
+    return (nsh->md_type & NSH_MDTYPE_MASK) >> NSH_MDTYPE_SHIFT;
 }

 static inline struct nsh_md1_ctx *
diff --git a/lib/flow.c b/lib/flow.c
index e30ca98..1adc499 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -546,7 +546,7 @@ parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key)

     memset(key, 0, sizeof(struct flow_nsh));

-    ver_flags_len = ntohs(nsh->ver_flags_len);
+    ver_flags_len = ntohs(nsh->ver_flags_ttl_len);
     version = (ver_flags_len & NSH_VER_MASK) >> NSH_VER_SHIFT;
     flags = (ver_flags_len & NSH_FLAGS_MASK) >> NSH_FLAGS_SHIFT;

diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 3109f39..3011479 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -277,12 +277,13 @@ odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key,
             const struct ovs_key_nsh *mask)
 {
     struct nsh_hdr *nsh = dp_packet_l3(packet);
+    uint8_t mdtype = nsh_md_type(nsh);

     if (!mask) {
-        nsh->ver_flags_len = htons(key->flags << NSH_FLAGS_SHIFT) |
-                             (nsh->ver_flags_len & ~htons(NSH_FLAGS_MASK));
+        nsh->ver_flags_ttl_len = htons(key->flags << NSH_FLAGS_SHIFT) |
+                (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK));
         put_16aligned_be32(&nsh->path_hdr, key->path_hdr);
-        switch (nsh->md_type) {
+        switch (mdtype) {
             case NSH_M_TYPE1:
                 for (int i = 0; i < 4; i++) {
                     put_16aligned_be32(&nsh->md1.c[i], key->c[i]);
@@ -294,16 +295,16 @@ odp_set_nsh(struct dp_packet *packet, const struct ovs_key_nsh *key,
                 break;
         }
     } else {
-        uint8_t flags = (ntohs(nsh->ver_flags_len) & NSH_FLAGS_MASK) >>
+        uint8_t flags = (ntohs(nsh->ver_flags_ttl_len) & NSH_FLAGS_MASK) >>
                             NSH_FLAGS_SHIFT;
         flags = key->flags | (flags & ~mask->flags);
-        nsh->ver_flags_len = htons(flags << NSH_FLAGS_SHIFT) |
-                             (nsh->ver_flags_len & ~htons(NSH_FLAGS_MASK));
+        nsh->ver_flags_ttl_len = htons(flags << NSH_FLAGS_SHIFT) |
+                (nsh->ver_flags_ttl_len & ~htons(NSH_FLAGS_MASK));

         ovs_be32 path_hdr = get_16aligned_be32(&nsh->path_hdr);
         path_hdr = key->path_hdr | (path_hdr & ~mask->path_hdr);
         put_16aligned_be32(&nsh->path_hdr, path_hdr);
-        switch (nsh->md_type) {
+        switch (mdtype) {
             case NSH_M_TYPE1:
                 for (int i = 0; i < 4; i++) {
                     ovs_be32 p = get_16aligned_be32(&nsh->md1.c[i]);
diff --git a/lib/packets.c b/lib/packets.c
index c991e9f..f589370 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -429,11 +429,14 @@ encap_nsh(struct dp_packet *packet, const struct ovs_action_encap_nsh *encap)
     }

     nsh = (struct nsh_hdr *) dp_packet_push_uninit(packet, length);
-    nsh->ver_flags_len = htons(encap->flags << NSH_FLAGS_SHIFT | length >> 2);
+    nsh->ver_flags_ttl_len =
+            htons(((encap->flags << NSH_FLAGS_SHIFT) & NSH_FLAGS_MASK)
+                    | (63 << NSH_TTL_SHIFT)
+                    | ((length >> 2) << NSH_LEN_SHIFT));
+    nsh->md_type = (encap->mdtype << NSH_MDTYPE_SHIFT) & NSH_MDTYPE_MASK;
     nsh->next_proto = next_proto;
     put_16aligned_be32(&nsh->path_hdr, encap->path_hdr);
-    nsh->md_type = encap->mdtype;
-    switch (nsh->md_type) {
+    switch (encap->mdtype) {
         case NSH_M_TYPE1:
             nsh->md1 = *ALIGNED_CAST(struct nsh_md1_ctx *, encap->metadata);
             break;
--
1.9.1




More information about the dev mailing list