@@ -439,6 +439,46 @@ invalid:
arp_buf[1] = eth_addr_zero;
}
+static int
+parse_nsh(const void **datap, size_t *sizep,
+ struct flow_nsh *key, struct tun_metadata *md OVS_UNUSED)
+{
+ const struct nsh_header *nsh = (const struct nsh_header *) *datap;
+ uint16_t length = 0;
+
+ memset(key, 0, sizeof(struct flow_nsh));
+
+ length = nsh->base.length << 2;
+ if (length > NSH_LEN_MAX)
+ return -EINVAL;
+
+ key->flags = nsh->base.flags;
+ key->md_type = nsh->base.md_type;
+ key->next_proto = nsh->base.next_proto;
+ key->nsi = nsh->base.nsi;
+ key->nsp = nsh->base.sfp << 8;
+
+ if (nsh->base.md_type == NSH_MD_TYPE1) {
+ const struct nsh_md1_ctx *ctx = (struct nsh_md1_ctx *)(nsh + 1);
+ key->nshc1 = ctx->nshc1;
+ key->nshc2 = ctx->nshc2;
+ key->nshc3 = ctx->nshc3;
+ key->nshc4 = ctx->nshc4;
+#if 0
+ } else if (nsh->base.md_type == NSH_MD_TYPE2) {
+ const struct nsh_md2_ctx *ctx = (struct nsh_md2_ctx *)(nsh + 1);
+
+ /* Prototype with TUN_METADATA APIs. */
+ tun_metadata_from_nsh_ctx((struct geneve_opt *)ctx,
+ md, length - sizeof *nsh);
+#endif
+ }
+
+ data_pull(datap, sizep, length);
+
+ return 0;
+}
+
/* Initializes 'flow' members from 'packet' and 'md'
*
* Initializes 'packet' header l2 pointer to the start of the Ethernet
@@ -563,6 +603,27 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
/* Network layer. */
packet->l3_ofs = (char *)data - l2;
+ /* Network Service Header */
+ if (dl_type == htons(ETH_TYPE_NSH)) {
+ struct flow_nsh nsh;
+ struct tun_metadata metadata;
+
+ if (OVS_LIKELY(!parse_nsh(&data, &size, &nsh, &metadata))) {
+ miniflow_push_words(mf, nsh, &nsh, sizeof(struct flow_nsh) /
+ sizeof(uint64_t));
+#if 0
+ if (nsh.md_type == NSH_MD_TYPE2) {
+ /* MD type 2 is not fully implemented yet. */
+ if (metadata.present.map) {
+ miniflow_push_words(mf, tunnel.metadata, &metadata,
+ sizeof(metadata) / sizeof(uint64_t));
+ }
+ }
+#endif
+ }
+ goto out;
+ }
+
nw_frag = 0;
if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) {
const struct ip_header *nh = data;
@@ -1293,6 +1354,18 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
WC_MASK_FIELD(wc, dp_hash);
WC_MASK_FIELD(wc, in_port);
+ if (flow->nsh.nsp) {
+ WC_MASK_FIELD(wc, nsh.flags);
+ WC_MASK_FIELD(wc, nsh.md_type);
+ WC_MASK_FIELD(wc, nsh.next_proto);
+ WC_MASK_FIELD(wc, nsh.nsi);
+ WC_MASK_FIELD(wc, nsh.nsp);
+ WC_MASK_FIELD(wc, nsh.nshc1);
+ WC_MASK_FIELD(wc, nsh.nshc2);
+ WC_MASK_FIELD(wc, nsh.nshc3);
+ WC_MASK_FIELD(wc, nsh.nshc4);
+ }
+
/* actset_output wildcarded. */
WC_MASK_FIELD(wc, dl_dst);
@@ -1397,6 +1470,18 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
FLOWMAP_SET(map, ct_mark);
FLOWMAP_SET(map, ct_label);
+ if (flow->nsh.nsp) {
+ FLOWMAP_SET(map, nsh.flags);
+ FLOWMAP_SET(map, nsh.md_type);
+ FLOWMAP_SET(map, nsh.next_proto);
+ FLOWMAP_SET(map, nsh.nsi);
+ FLOWMAP_SET(map, nsh.nsp);
+ FLOWMAP_SET(map, nsh.nshc1);
+ FLOWMAP_SET(map, nsh.nshc2);
+ FLOWMAP_SET(map, nsh.nshc3);
+ FLOWMAP_SET(map, nsh.nshc4);
+ }
+
/* Ethertype-dependent fields. */
if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
FLOWMAP_SET(map, nw_src);
@@ -334,6 +334,7 @@ ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
#define ETH_TYPE_RARP 0x8035
#define ETH_TYPE_MPLS 0x8847
#define ETH_TYPE_MPLS_MCAST 0x8848
+#define ETH_TYPE_NSH 0x894F
static inline bool eth_type_mpls(ovs_be16 eth_type)
{
@@ -1018,6 +1019,53 @@ struct vxlanhdr {
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
+/* Network service header */
+struct nsh_base_hdr {
+ uint8_t flags;
+ uint8_t length;
+ uint8_t md_type;
+ uint8_t next_proto;
+ union {
+ struct {
+ uint8_t nsp[3];
+ uint8_t nsi;
+ };
+ ovs_be32 sfp;
+ };
+};
+
+struct nsh_md1_ctx {
+ ovs_be32 nshc1;
+ ovs_be32 nshc2;
+ ovs_be32 nshc3;
+ ovs_be32 nshc4;
+};
+
+struct nsh_md2_ctx {
+ ovs_be16 md_class;
+ uint8_t type;
+ uint8_t length;
+ uint8_t md_value[];
+};
+
+struct nsh_header {
+ struct nsh_base_hdr base;
+ uint8_t ctx[];
+};
+
+#define NSH_P_IPV4 0x01
+#define NSH_P_IPV6 0x02
+#define NSH_P_ETHERNET 0x03
+
+#define NSH_MD_TYPE_NONE 0x00
+#define NSH_MD_TYPE1 0x01
+#define NSH_MD_TYPE2 0x02
+#define NSH_MD_EXP1 0xFE
+#define NSH_MD_EXP2 0xFF
+
+#define NSH_TYPE1_LEN 24
+#define NSH_LEN_MAX 256
+
void ipv6_format_addr(const struct in6_addr *addr, struct ds *);
void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *,
bool bracket);
Signed-off-by: Johnson Li <johnson.li@intel.com>