@@ -67,6 +67,7 @@ OXM_CLASSES = {"NXM_OF_": (0, 0x0000),
"NXM_NX_": (0, 0x0001),
"OXM_OF_": (0, 0x8000),
"OXM_OF_PKT_REG": (0, 0x8001),
+ "OXM_NSH_": (0, 0x8004),
"ONFOXM_ET_": (0x4f4e4600, 0xffff),
# This is the experimenter OXM class for Nicira, which is the
@@ -40,6 +40,18 @@ struct match {
/* Initializer for a "struct match" that matches every packet. */
#define MATCH_CATCHALL_INITIALIZER { .flow = { .dl_type = 0 } }
+#define MATCH_SET_FIELD_MASKED(match, field, value, msk) \
+ do { \
+ (match)->wc.masks.field = (msk); \
+ (match)->flow.field = (value) & (msk); \
+ } while (0)
+
+#define MATCH_SET_FIELD_UINT8(match, field, value) \
+ MATCH_SET_FIELD_MASKED(match, field, value, UINT8_MAX)
+
+#define MATCH_SET_FIELD_BE32(match, field, value) \
+ MATCH_SET_FIELD_MASKED(match, field, value, OVS_BE32_MAX)
+
void match_init(struct match *,
const struct flow *, const struct flow_wildcards *);
void match_wc_init(struct match *match, const struct flow *flow);
@@ -1729,6 +1729,137 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_ND_TLL,
+/* ## ---- ## */
+/* ## NSH ## */
+/* ## ---- ## */
+
+ /* "nsh_flags".
+ *
+ * flags field in NSH base header (8 bits).
+ *
+ * Type: u8.
+ * Maskable: bitwise.
+ * Formatting: decimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_FLAGS(126) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_FLAGS(1) since OF1.3 and v2.8.
+ */
+ MFF_NSH_FLAGS,
+
+ /* "nsh_mdtype".
+ *
+ * mdtype field in NSH base header (8 bits).
+ *
+ * Type: u8.
+ * Maskable: bitwise.
+ * Formatting: decimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_MDTYPE(127) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_MDTYPE(2) since OF1.3 and v2.8.
+ */
+ MFF_NSH_MDTYPE,
+
+ /* "nsh_np".
+ *
+ * np (next protocol) field in NSH base header (8 bits)
+ *
+ * Type: u8.
+ * Maskable: bitwise.
+ * Formatting: decimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_NP(128) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_NP(3) since OF1.3 and v2.8.
+ */
+ MFF_NSH_NP,
+
+ /* "nsh_spi" (aka "nsp").
+ *
+ * spi (service path identifier) field in NSH base
+ * header (24 bits).
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_SPI(129) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_SPI(4) since OF1.3 and v2.8.
+ */
+ MFF_NSH_SPI,
+
+ /* "nsh_si" (aka "nsi").
+ *
+ * si (service index) field in NSH base header (8 bits).
+ *
+ * Type: u8.
+ * Maskable: bitwise.
+ * Formatting: decimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_SI(130) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_SI(5) since OF1.3 and v2.8.
+ */
+ MFF_NSH_SI,
+
+ /* "nsh_c1" (aka "nshc1").
+ *
+ * c1 (Network Platform Context) field in NSH context header (32 bits)
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C1(131) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_C1(6) since OF1.3 and v2.8.
+ */
+ MFF_NSH_C1,
+
+ /* "nsh_c2" (aka "nshc2").
+ *
+ * c2 (Network Shared Context) field in NSH context header (32 bits)
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C2(132) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_C2(7) since OF1.3 and v2.8.
+ */
+ MFF_NSH_C2,
+
+ /* "nsh_c3" (aka "nshc3").
+ *
+ * c3 (Service Platform Context) field in NSH context header (32 bits)
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C3(133) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_C3(8) since OF1.3 and v2.8.
+ */
+ MFF_NSH_C3,
+
+ /* "nsh_c4" (aka "nshc4").
+ *
+ * c4 (Service Shared Context) field in NSH context header (32 bits)
+ *
+ * Type: be32.
+ * Maskable: bitwise.
+ * Formatting: hexadecimal.
+ * Prerequisites: none.
+ * Access: read/write.
+ * NXM: NXM_NX_NSH_C4(134) since OF1.3 and v2.8.
+ * OXM: OXM_NSH_C4(9) since OF1.3 and v2.8.
+ */
+ MFF_NSH_C4,
+
MFF_N_IDS
};
@@ -1485,22 +1485,6 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
WC_MASK_FIELD(wc, dp_hash);
WC_MASK_FIELD(wc, in_port);
- if (flow->nsh.mdtype) {
- WC_MASK_FIELD(wc, nsh.flags);
- WC_MASK_FIELD(wc, nsh.mdtype);
- WC_MASK_FIELD(wc, nsh.np);
- WC_MASK_FIELD(wc, nsh.si);
- WC_MASK_FIELD(wc, nsh.spi);
- if (flow->nsh.mdtype == NSH_M_TYPE1) {
- WC_MASK_FIELD(wc, nsh.c1);
- WC_MASK_FIELD(wc, nsh.c2);
- WC_MASK_FIELD(wc, nsh.c3);
- WC_MASK_FIELD(wc, nsh.c4);
- } else if (flow->nsh.mdtype == NSH_M_TYPE2) {
- /* TODO */
- }
- }
-
/* actset_output wildcarded. */
if (flow->packet_type == htonl(PT_ETH)) {
WC_MASK_FIELD(wc, dl_dst);
@@ -1552,6 +1536,16 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
}
}
return;
+ } else if (flow->dl_type == htons(ETH_TYPE_NSH)) {
+ WC_MASK_FIELD(wc, nsh.flags);
+ WC_MASK_FIELD(wc, nsh.mdtype);
+ WC_MASK_FIELD(wc, nsh.np);
+ WC_MASK_FIELD(wc, nsh.spi);
+ WC_MASK_FIELD(wc, nsh.si);
+ WC_MASK_FIELD(wc, nsh.c1);
+ WC_MASK_FIELD(wc, nsh.c2);
+ WC_MASK_FIELD(wc, nsh.c3);
+ WC_MASK_FIELD(wc, nsh.c4);
} else {
return; /* Unknown ethertype. */
}
@@ -24,6 +24,7 @@
#include "openvswitch/ofp-util.h"
#include "packets.h"
#include "tun-metadata.h"
+#include "openvswitch/nsh.h"
/* Converts the flow in 'flow' into a match in 'match', with the given
* 'wildcards'. */
@@ -1033,6 +1034,21 @@ format_ipv6_netmask(struct ds *s, const char *name,
}
static void
+format_uint8_masked(struct ds *s, const char *name,
+ uint8_t value, uint8_t mask)
+{
+ if (mask != 0) {
+ ds_put_format(s, "%s%s=%s", colors.param, name, colors.end);
+ if (mask == UINT8_MAX) {
+ ds_put_format(s, "%"PRIu8, value);
+ } else {
+ ds_put_format(s, "0x%02"PRIx8"/0x%02"PRIx8, value, mask);
+ }
+ ds_put_char(s, ',');
+ }
+}
+
+static void
format_uint16_masked(struct ds *s, const char *name,
uint16_t value, uint16_t mask)
{
@@ -1072,7 +1088,7 @@ format_be32_masked(struct ds *s, const char *name,
if (mask == OVS_BE32_MAX) {
ds_put_format(s, "%"PRIu32, ntohl(value));
} else {
- ds_put_format(s, "0x%"PRIx32"/0x%"PRIx32,
+ ds_put_format(s, "0x%08"PRIx32"/0x%08"PRIx32,
ntohl(value), ntohl(mask));
}
ds_put_char(s, ',');
@@ -1162,6 +1178,33 @@ format_ct_label_masked(struct ds *s, const ovs_u128 *key, const ovs_u128 *mask)
}
}
+static void
+format_flow_nsh(struct ds *s, const struct match *match)
+{
+ const struct flow_wildcards *wc = &match->wc;
+ const struct flow *f = &match->flow;
+
+ if (wc->masks.nsh.flags)
+ format_uint8_masked(s, "nsh_flags", f->nsh.flags, wc->masks.nsh.flags);
+ if (wc->masks.nsh.mdtype)
+ format_uint8_masked(s, "nsh_mdtype", f->nsh.mdtype, wc->masks.nsh.mdtype);
+ if (wc->masks.nsh.np)
+ format_uint8_masked(s, "nsh_np", f->nsh.np, wc->masks.nsh.np);
+ if (wc->masks.nsh.spi)
+ format_be32_masked(s, "nsh_spi", f->nsh.spi, wc->masks.nsh.spi);
+ if (wc->masks.nsh.si)
+ format_uint8_masked(s, "nsh_si", f->nsh.si, wc->masks.nsh.si);
+
+ if (wc->masks.nsh.c1)
+ format_be32_masked(s, "nsh_c1", f->nsh.c1, wc->masks.nsh.c1);
+ if (wc->masks.nsh.c2)
+ format_be32_masked(s, "nsh_c2", f->nsh.c2, wc->masks.nsh.c2);
+ if (wc->masks.nsh.c3)
+ format_be32_masked(s, "nsh_c3", f->nsh.c3, wc->masks.nsh.c3);
+ if (wc->masks.nsh.c4)
+ format_be32_masked(s, "nsh_c4", f->nsh.c4, wc->masks.nsh.c4);
+}
+
/* Appends a string representation of 'match' to 's'. If 'priority' is
* different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
void
@@ -1313,6 +1356,8 @@ match_format(const struct match *match, struct ds *s, int priority)
} else {
ds_put_format(s, "%sipv6%s,", colors.value, colors.end);
}
+ } else if (f->dl_type == htons(ETH_TYPE_NSH)) {
+ format_flow_nsh(s, match);
} else if (dl_type == htons(ETH_TYPE_ARP)) {
ds_put_format(s, "%sarp%s,", colors.value, colors.end);
} else if (dl_type == htons(ETH_TYPE_RARP)) {
@@ -359,6 +359,25 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
case MFF_TCP_FLAGS:
return !wc->masks.tcp_flags;
+ case MFF_NSH_FLAGS:
+ return !wc->masks.nsh.flags;
+ case MFF_NSH_MDTYPE:
+ return !wc->masks.nsh.mdtype;
+ case MFF_NSH_NP:
+ return !wc->masks.nsh.np;
+ case MFF_NSH_SPI:
+ return !wc->masks.nsh.spi;
+ case MFF_NSH_SI:
+ return !wc->masks.nsh.si;
+ case MFF_NSH_C1:
+ return !wc->masks.nsh.c1;
+ case MFF_NSH_C2:
+ return !wc->masks.nsh.c2;
+ case MFF_NSH_C3:
+ return !wc->masks.nsh.c3;
+ case MFF_NSH_C4:
+ return !wc->masks.nsh.c4;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -586,6 +605,17 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_CT_STATE:
return !(value->be32 & ~htonl(CS_SUPPORTED_MASK));
+ case MFF_NSH_FLAGS:
+ case MFF_NSH_MDTYPE:
+ case MFF_NSH_NP:
+ case MFF_NSH_SPI:
+ case MFF_NSH_SI:
+ case MFF_NSH_C1:
+ case MFF_NSH_C2:
+ case MFF_NSH_C3:
+ case MFF_NSH_C4:
+ return true;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -863,6 +893,34 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
value->ipv6 = flow->nd_target;
break;
+ case MFF_NSH_FLAGS:
+ value->u8 = flow->nsh.flags;
+ break;
+ case MFF_NSH_MDTYPE:
+ value->u8 = flow->nsh.mdtype;
+ break;
+ case MFF_NSH_NP:
+ value->u8 = flow->nsh.np;
+ break;
+ case MFF_NSH_SPI:
+ value->be32 = flow->nsh.spi;
+ break;
+ case MFF_NSH_SI:
+ value->u8 = flow->nsh.si;
+ break;
+ case MFF_NSH_C1:
+ value->be32 = flow->nsh.c1;
+ break;
+ case MFF_NSH_C2:
+ value->be32 = flow->nsh.c2;
+ break;
+ case MFF_NSH_C3:
+ value->be32 = flow->nsh.c3;
+ break;
+ case MFF_NSH_C4:
+ value->be32 = flow->nsh.c4;
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1156,6 +1214,34 @@ mf_set_value(const struct mf_field *mf,
match_set_nd_target(match, &value->ipv6);
break;
+ case MFF_NSH_FLAGS:
+ MATCH_SET_FIELD_UINT8(match, nsh.flags, value->u8);
+ break;
+ case MFF_NSH_MDTYPE:
+ MATCH_SET_FIELD_UINT8(match, nsh.mdtype, value->u8);
+ break;
+ case MFF_NSH_NP:
+ MATCH_SET_FIELD_UINT8(match, nsh.np, value->u8);
+ break;
+ case MFF_NSH_SPI:
+ MATCH_SET_FIELD_BE32(match, nsh.spi, value->be32);
+ break;
+ case MFF_NSH_SI:
+ MATCH_SET_FIELD_UINT8(match, nsh.si, value->u8);
+ break;
+ case MFF_NSH_C1:
+ MATCH_SET_FIELD_BE32(match, nsh.c1, value->be32);
+ break;
+ case MFF_NSH_C2:
+ MATCH_SET_FIELD_BE32(match, nsh.c2, value->be32);
+ break;
+ case MFF_NSH_C3:
+ MATCH_SET_FIELD_BE32(match, nsh.c3, value->be32);
+ break;
+ case MFF_NSH_C4:
+ MATCH_SET_FIELD_BE32(match, nsh.c4, value->be32);
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1525,6 +1611,34 @@ mf_set_flow_value(const struct mf_field *mf,
flow->nd_target = value->ipv6;
break;
+ case MFF_NSH_FLAGS:
+ flow->nsh.flags = value->u8;
+ break;
+ case MFF_NSH_MDTYPE:
+ flow->nsh.mdtype = value->u8;
+ break;
+ case MFF_NSH_NP:
+ flow->nsh.np = value->u8;
+ break;
+ case MFF_NSH_SPI:
+ flow->nsh.spi = value->be32;
+ break;
+ case MFF_NSH_SI:
+ flow->nsh.si = value->u8;
+ break;
+ case MFF_NSH_C1:
+ flow->nsh.c1 = value->be32;
+ break;
+ case MFF_NSH_C2:
+ flow->nsh.c2 = value->be32;
+ break;
+ case MFF_NSH_C3:
+ flow->nsh.c3 = value->be32;
+ break;
+ case MFF_NSH_C4:
+ flow->nsh.c4 = value->be32;
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1894,6 +2008,34 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
memset(&match->flow.nd_target, 0, sizeof match->flow.nd_target);
break;
+ case MFF_NSH_FLAGS:
+ MATCH_SET_FIELD_MASKED(match, nsh.flags, 0, 0);
+ break;
+ case MFF_NSH_MDTYPE:
+ MATCH_SET_FIELD_MASKED(match, nsh.mdtype, 0, 0);
+ break;
+ case MFF_NSH_NP:
+ MATCH_SET_FIELD_MASKED(match, nsh.np, 0, 0);
+ break;
+ case MFF_NSH_SPI:
+ MATCH_SET_FIELD_MASKED(match, nsh.spi, htonl(0), htonl(0));
+ break;
+ case MFF_NSH_SI:
+ MATCH_SET_FIELD_MASKED(match, nsh.si, 0, 0);
+ break;
+ case MFF_NSH_C1:
+ MATCH_SET_FIELD_MASKED(match, nsh.c1, htonl(0), htonl(0));
+ break;
+ case MFF_NSH_C2:
+ MATCH_SET_FIELD_MASKED(match, nsh.c2, htonl(0), htonl(0));
+ break;
+ case MFF_NSH_C3:
+ MATCH_SET_FIELD_MASKED(match, nsh.c3, htonl(0), htonl(0));
+ break;
+ case MFF_NSH_C4:
+ MATCH_SET_FIELD_MASKED(match, nsh.c4, htonl(0), htonl(0));
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -2131,6 +2273,34 @@ mf_set(const struct mf_field *mf,
match_set_tcp_flags_masked(match, value->be16, mask->be16);
break;
+ case MFF_NSH_FLAGS:
+ MATCH_SET_FIELD_MASKED(match, nsh.flags, value->u8, mask->u8);
+ break;
+ case MFF_NSH_MDTYPE:
+ MATCH_SET_FIELD_MASKED(match, nsh.mdtype, value->u8, mask->u8);
+ break;
+ case MFF_NSH_NP:
+ MATCH_SET_FIELD_MASKED(match, nsh.np, value->u8, mask->u8);
+ break;
+ case MFF_NSH_SPI:
+ MATCH_SET_FIELD_MASKED(match, nsh.spi, value->be32, mask->be32);
+ break;
+ case MFF_NSH_SI:
+ MATCH_SET_FIELD_MASKED(match, nsh.si, value->u8, mask->u8);
+ break;
+ case MFF_NSH_C1:
+ MATCH_SET_FIELD_MASKED(match, nsh.c1, value->be32, mask->be32);
+ break;
+ case MFF_NSH_C2:
+ MATCH_SET_FIELD_MASKED(match, nsh.c2, value->be32, mask->be32);
+ break;
+ case MFF_NSH_C3:
+ MATCH_SET_FIELD_MASKED(match, nsh.c3, value->be32, mask->be32);
+ break;
+ case MFF_NSH_C4:
+ MATCH_SET_FIELD_MASKED(match, nsh.c4, value->be32, mask->be32);
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1276,6 +1276,27 @@ tcp,tp_src=0x07c0/0xfff0
</field>
</group>
+ <group title="Network Service Header">
+ <field id="MFF_NSH_FLAGS"
+ title="flags field in NSH base header (8 bits)"/>
+ <field id="MFF_NSH_MDTYPE"
+ title="mdtype field in NSH base header (8 bits)"/>
+ <field id="MFF_NSH_NP"
+ title="np (next protocol) field in NSH base header (8 bits)"/>
+ <field id="MFF_NSH_SPI"
+ title="spi (service path identifier) field in NSH base header (24 bits)"/>
+ <field id="MFF_NSH_SI"
+ title="si (service index) field in NSH base header (8 bits)"/>
+ <field id="MFF_NSH_C1"
+ title="c1 (Network Platform Context) field in NSH context header (32 bits)"/>
+ <field id="MFF_NSH_C2"
+ title="c2 (Network Shared Context) field in NSH context header (32 bits)"/>
+ <field id="MFF_NSH_C3"
+ title="c3 (Service Platform Context) field in NSH context header (32 bits)"/>
+ <field id="MFF_NSH_C4"
+ title="c4 (Service Shared Context) field in NSH context header (32 bits)"/>
+ </group>
+
<group title="Tunnel">
<p>
The fields in this group relate to tunnels, which Open vSwitch
@@ -1115,6 +1115,24 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match,
flow->tunnel.gbp_flags, match->wc.masks.tunnel.gbp_flags);
tun_metadata_to_nx_match(b, oxm, match);
+ /* Network Service Header */
+ nxm_put_8m(b, MFF_NSH_FLAGS, oxm, flow->nsh.flags,
+ match->wc.masks.nsh.flags);
+ nxm_put_8m(b, MFF_NSH_MDTYPE, oxm, flow->nsh.mdtype,
+ match->wc.masks.nsh.mdtype);
+ nxm_put_8m(b, MFF_NSH_NP, oxm, flow->nsh.np,
+ match->wc.masks.nsh.np);
+ nxm_put_32m(b, MFF_NSH_SPI, oxm, flow->nsh.spi, match->wc.masks.nsh.spi);
+ nxm_put_8m(b, MFF_NSH_SI, oxm, flow->nsh.si, match->wc.masks.nsh.si);
+ nxm_put_32m(b, MFF_NSH_C1, oxm, flow->nsh.c1,
+ match->wc.masks.nsh.c1);
+ nxm_put_32m(b, MFF_NSH_C2, oxm, flow->nsh.c2,
+ match->wc.masks.nsh.c2);
+ nxm_put_32m(b, MFF_NSH_C3, oxm, flow->nsh.c3,
+ match->wc.masks.nsh.c3);
+ nxm_put_32m(b, MFF_NSH_C4, oxm, flow->nsh.c4,
+ match->wc.masks.nsh.c4);
+
/* Registers. */
if (oxm < OFP15_VERSION) {
for (i = 0; i < FLOW_N_REGS; i++) {