Signed-off-by: Yi Yang <[email protected]>
---
lib/flow.c | 6 ++-
lib/flow.h | 1 +
lib/odp-execute.c | 18 +++++++-
lib/odp-util.c | 126 +++++++++++++++++++++++++++++++++++++++++-------------
lib/odp-util.h | 3 ++
lib/packets.c | 37 ++++++++++++++++
lib/packets.h | 2 +
7 files changed, 161 insertions(+), 32 deletions(-)
diff --git a/lib/flow.c b/lib/flow.c
index 091ebf0..d285080 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -531,7 +531,7 @@ parse_ipv6_ext_hdrs(const void **datap, size_t *sizep,
uint8_t *nw_proto,
return parse_ipv6_ext_hdrs__(datap, sizep, nw_proto, nw_frag);
}
-static int
+int
parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key)
{
const struct nsh_hdr *nsh = (const struct nsh_hdr *) *datap;
@@ -543,6 +543,10 @@ parse_nsh(const void **datap, size_t *sizep, struct
flow_nsh *key)
if (length > NSH_LEN_MAX)
return -EINVAL;
+ key->flags = (nsh->base.version << 6) &
+ (nsh->base.oam_flag << 5) &
+ (nsh->base.context_flag << 4) &
+ nsh->base.reserved_flags1;
key->mdtype = nsh->base.md_type;
key->np = nsh->base.next_proto;
key->si = nsh->base.svc_idx;
diff --git a/lib/flow.h b/lib/flow.h
index d29dcb1..fc499dc 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -120,6 +120,7 @@ void flow_compose(struct dp_packet *, const struct flow *);
bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
uint8_t *nw_frag);
ovs_be16 parse_dl_type(const struct eth_header *data_, size_t size);
+int parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key);
static inline uint64_t
flow_get_xreg(const struct flow *flow, int idx)
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 0891607..6b9a642 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -203,6 +203,20 @@ odp_set_tunnel_action(const struct nlattr *a, struct
flow_tnl *tun_key)
}
static void
+odp_set_nsh(struct dp_packet *packet, const struct nlattr *a, const struct
flow_nsh *mask)
+{
+ struct flow_nsh key;
+ enum odp_key_fitness fitness;
+
+ const void *data = dp_packet_l3(packet);
+ size_t size = dp_packet_size(packet);
+ parse_nsh(&data, &size, &key);
+ fitness = odp_nsh_key_from_attr(a, &key);
+ ovs_assert(fitness != ODP_FIT_ERROR);
+ packet_set_nsh(packet, &key, mask);
+}
+
+static void
set_arp(struct dp_packet *packet, const struct ovs_key_arp *key,
const struct ovs_key_arp *mask)
{
@@ -296,7 +310,7 @@ odp_execute_set_action(struct dp_packet *packet, const
struct nlattr *a)
break;
case OVS_KEY_ATTR_NSH:
- /* TODO */
+ odp_set_nsh(packet, a, NULL);
break;
case OVS_KEY_ATTR_IPV4:
@@ -424,7 +438,7 @@ odp_execute_masked_set_action(struct dp_packet *packet,
break;
case OVS_KEY_ATTR_NSH:
- /* TODO */
+ odp_set_nsh(packet, a, get_mask(a, struct flow_nsh));
break;
case OVS_KEY_ATTR_IPV4:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 3a685df..476bc8b 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -41,7 +41,6 @@
#include "util.h"
#include "uuid.h"
#include "openvswitch/vlog.h"
-#include "openvswitch/nsh.h"
VLOG_DEFINE_THIS_MODULE(odp_util);
@@ -2181,44 +2180,81 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl
*tun_key,
}
static void
-nsh_key_to_attr(struct ofpbuf *a, const struct flow *key)
+nsh_key_to_attr(struct ofpbuf *a, const struct flow *base, const struct flow
*key)
{
size_t nsh_key_ofs = 0;
nsh_key_ofs = nl_msg_start_nested(a, OVS_KEY_ATTR_NSH);
- if (key->nsh.flags) {
+ if (base->nsh.flags != key->nsh.flags) {
nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_FLAGS, key->nsh.flags);
}
- if (key->nsh.mdtype) {
+ if (base->nsh.mdtype != key->nsh.mdtype) {
nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_MDTYPE, key->nsh.mdtype);
}
- if (key->nsh.np) {
+ if (base->nsh.np != key->nsh.np) {
nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_NP, key->nsh.np);
}
- if (key->nsh.spi) {
+ if (base->nsh.spi != key->nsh.spi) {
nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_SPI, key->nsh.spi);
}
- if (key->nsh.si) {
+ if (base->nsh.si != key->nsh.si) {
nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_SI, key->nsh.si);
}
- if (key->nsh.c1) {
+ if (base->nsh.c1 != key->nsh.c1) {
nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C1, key->nsh.c1);
}
- if (key->nsh.c2) {
+ if (base->nsh.c2 != key->nsh.c2) {
nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C2, key->nsh.c2);
}
- if (key->nsh.c3) {
+ if (base->nsh.c3 != key->nsh.c3) {
nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C3, key->nsh.c3);
}
- if (key->nsh.c4) {
+ if (base->nsh.c4 != key->nsh.c4) {
nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C4, key->nsh.c4);
}
nl_msg_end_nested(a, nsh_key_ofs);
}
-static enum odp_key_fitness
-odp_nsh_key_from_attr(const struct nlattr *attr, struct flow *key)
+static void
+nsh_key_to_attr_masked(struct ofpbuf *a, const struct flow *base, const struct
flow *key, const struct flow *mask)
+{
+ size_t nsh_key_ofs = 0;
+
+ nsh_key_ofs = nl_msg_start_nested(a, OVS_KEY_ATTR_NSH);
+
+ if (base->nsh.flags != key->nsh.flags) {
+ nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_FLAGS, key->nsh.flags &
mask->nsh.flags);
+ }
+ if (base->nsh.mdtype != key->nsh.mdtype) {
+ nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_MDTYPE, key->nsh.mdtype &
mask->nsh.mdtype);
+ }
+ if (base->nsh.np != key->nsh.np) {
+ nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_NP, key->nsh.np & mask->nsh.np);
+ }
+ if (base->nsh.spi != key->nsh.spi) {
+ nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_SPI, key->nsh.spi & mask->nsh.spi);
+ }
+ if (base->nsh.si != key->nsh.si) {
+ nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_SI, key->nsh.si & mask->nsh.si);
+ }
+ if (base->nsh.c1 != key->nsh.c1) {
+ nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C1, key->nsh.c1 & mask->nsh.c1);
+ }
+ if (base->nsh.c2 != key->nsh.c2) {
+ nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C2, key->nsh.c2 & mask->nsh.c2);
+ }
+ if (base->nsh.c3 != key->nsh.c3) {
+ nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C3, key->nsh.c3 & mask->nsh.c3);
+ }
+ if (base->nsh.c4 != key->nsh.c4) {
+ nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_C4, key->nsh.c4 & mask->nsh.c4);
+ }
+ nl_msg_end_nested(a, nsh_key_ofs);
+}
+
+enum odp_key_fitness
+odp_nsh_key_from_attr(const struct nlattr *attr, struct flow_nsh *key)
{
unsigned int left;
const struct nlattr *a;
@@ -2236,31 +2272,31 @@ odp_nsh_key_from_attr(const struct nlattr *attr, struct
flow *key)
switch (type) {
case OVS_NSH_KEY_ATTR_FLAGS:
- key->nsh.flags = nl_attr_get_u8(a);
+ key->flags = nl_attr_get_u8(a);
break;
case OVS_NSH_KEY_ATTR_MDTYPE:
- key->nsh.mdtype = nl_attr_get_u8(a);
+ key->mdtype = nl_attr_get_u8(a);
break;
case OVS_NSH_KEY_ATTR_NP:
- key->nsh.np = nl_attr_get_u8(a);
+ key->np = nl_attr_get_u8(a);
break;
case OVS_NSH_KEY_ATTR_SPI:
- key->nsh.spi = nl_attr_get_be32(a);
+ key->spi = nl_attr_get_be32(a);
break;
case OVS_NSH_KEY_ATTR_SI:
- key->nsh.si = nl_attr_get_u8(a);
+ key->si = nl_attr_get_u8(a);
break;
case OVS_NSH_KEY_ATTR_C1:
- key->nsh.c1 = nl_attr_get_be32(a);
+ key->c1 = nl_attr_get_be32(a);
break;
case OVS_NSH_KEY_ATTR_C2:
- key->nsh.c2 = nl_attr_get_be32(a);
+ key->c2 = nl_attr_get_be32(a);
break;
case OVS_NSH_KEY_ATTR_C3:
- key->nsh.c3 = nl_attr_get_be32(a);
+ key->c3 = nl_attr_get_be32(a);
break;
case OVS_NSH_KEY_ATTR_C4:
- key->nsh.c4 = nl_attr_get_be32(a);
+ key->c4 = nl_attr_get_be32(a);
break;
default:
/* Allow this to show up as unexpected, if there are unknown
@@ -2304,6 +2340,18 @@ odp_mask_is_exact(enum ovs_key_attr attr, const void
*mask, size_t size)
if (attr == OVS_KEY_ATTR_TUNNEL) {
return false;
}
+ if (attr == OVS_KEY_ATTR_NSH) {
+ const struct flow_nsh *nsh_mask = mask;
+ return (((nsh_mask->flags == 0) || (nsh_mask->flags == UINT8_MAX))
+ && ((nsh_mask->mdtype == 0) || (nsh_mask->mdtype == UINT8_MAX))
+ && ((nsh_mask->np == 0) || (nsh_mask->np == UINT8_MAX))
+ && ((nsh_mask->spi == 0) || (nsh_mask->spi == OVS_BE32_MAX))
+ && ((nsh_mask->si == 0) || (nsh_mask->si == UINT8_MAX))
+ && ((nsh_mask->c1 == 0) || (nsh_mask->c1 == OVS_BE32_MAX))
+ && ((nsh_mask->c2 == 0) || (nsh_mask->c2 == OVS_BE32_MAX))
+ && ((nsh_mask->c3 == 0) || (nsh_mask->c3 == OVS_BE32_MAX))
+ && ((nsh_mask->c4 == 0) || (nsh_mask->c4 == OVS_BE32_MAX)));
+ }
if (attr == OVS_KEY_ATTR_ARP) {
/* ARP key has padding, ignore it. */
@@ -2903,11 +2951,6 @@ format_odp_nsh_attr(const struct nlattr *attr, const
struct nlattr *mask_attr,
if (mask_attr) {
ma = nl_attr_find__(nl_attr_get(mask_attr),
nl_attr_get_size(mask_attr), type);
- if (!ma) {
- ma = generate_all_wildcard_mask(ovs_nsh_key_attr_lens,
- OVS_NSH_KEY_ATTR_MAX,
- &ofp, a);
- }
}
if (!check_attr_len(ds, a, ma, ovs_nsh_key_attr_lens,
@@ -4899,7 +4942,7 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms
*parms,
mpls_key[i].mpls_lse = data->mpls_lse[i];
}
} else if (flow->dl_type == htons(ETH_TYPE_NSH)) {
- nsh_key_to_attr(buf, data);
+ nsh_key_to_attr(buf, flow, data);
}
if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
@@ -5471,7 +5514,7 @@ parse_l2_5_onward(const struct nlattr
*attrs[OVS_KEY_ATTR_MAX + 1],
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_NSH)) {
enum odp_key_fitness res;
- res = odp_nsh_key_from_attr(attrs[OVS_KEY_ATTR_NSH], flow);
+ res = odp_nsh_key_from_attr(attrs[OVS_KEY_ATTR_NSH], &flow->nsh);
if (res == ODP_FIT_ERROR) {
return ODP_FIT_ERROR;
} else if (res == ODP_FIT_PERFECT) {
@@ -6582,6 +6625,30 @@ commit_set_pkt_mark_action(const struct flow *flow,
struct flow *base_flow,
}
}
+static void
+commit_set_nsh_action(const struct flow *flow, struct flow *base_flow,
+ struct ofpbuf *odp_actions,
+ struct flow_wildcards *wc,
+ bool use_masked)
+{
+ if (!memcmp(&base_flow->nsh, &flow->nsh, sizeof base_flow->nsh)) {
+ return;
+ }
+
+ bool fully_masked = odp_mask_is_exact(OVS_KEY_ATTR_NSH, &wc->masks.nsh,
sizeof(struct flow_nsh));
+
+ if (use_masked && !fully_masked) {
+ size_t offset = nl_msg_start_nested(odp_actions,
OVS_ACTION_ATTR_SET_MASKED);
+ nsh_key_to_attr_masked(odp_actions, base_flow, flow, &wc->masks);
+ nl_msg_end_nested(odp_actions, offset);
+ } else {
+ size_t offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SET);
+ nsh_key_to_attr(odp_actions, base_flow, flow);
+ nl_msg_end_nested(odp_actions, offset);
+ }
+ memcpy(&base_flow->nsh, &flow->nsh, sizeof base_flow->nsh);
+}
+
/* If any of the flow key data that ODP actions can modify are different in
* 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
* key from 'base' into 'flow', and then changes 'base' the same way. Does not
@@ -6606,6 +6673,7 @@ commit_odp_actions(const struct flow *flow, struct flow
*base,
commit_mpls_action(flow, base, odp_actions);
mpls_done = true;
}
+ commit_set_nsh_action(flow, base, odp_actions, wc, use_masked);
slow1 = commit_set_nw_action(flow, base, odp_actions, wc, use_masked);
commit_set_port_action(flow, base, odp_actions, wc, use_masked);
slow2 = commit_set_icmp_action(flow, base, odp_actions, wc);
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 1d7dcc4..f167eaf 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -155,6 +155,9 @@ struct odputil_keybuf {
enum odp_key_fitness odp_tun_key_from_attr(const struct nlattr *,
struct flow_tnl *);
+enum odp_key_fitness odp_nsh_key_from_attr(const struct nlattr *attr,
+ struct flow_nsh *key);
+
int odp_ufid_from_string(const char *s_, ovs_u128 *ufid);
void odp_format_ufid(const ovs_u128 *ufid, struct ds *);
diff --git a/lib/packets.c b/lib/packets.c
index 3bf5e94..9467768 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -267,6 +267,43 @@ pop_eth(struct dp_packet *packet)
packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, htons(ethertype));
}
+void packet_set_nsh(struct dp_packet *packet, const struct flow_nsh * nsh_key,
const struct flow_nsh * nsh_mask)
+{
+ struct nsh_hdr * nsh_header = (struct nsh_hdr *)dp_packet_l3(packet);
+ struct nsh_md1_ctx * md1_ctx = nsh_md1_ctx(nsh_header);
+
+ if (!nsh_mask) {
+ nsh_header->base.reserved_flags1 = nsh_key->flags & 0x0F;
+ nsh_header->base.context_flag = (nsh_key->flags & 0x10) >> 4;
+ nsh_header->base.oam_flag = (nsh_key->flags & 0x20) >> 5;
+ nsh_header->base.version = (nsh_key->flags & 0xC0) >> 6;
+ nsh_header->base.md_type = nsh_key->mdtype;
+ nsh_header->base.next_proto = nsh_key->np;
+ nsh_header->base.path_hdr = (nsh_key->spi >> 8) | (nsh_key->si << 24);
+ md1_ctx->c1 = nsh_key->c1;
+ md1_ctx->c2 = nsh_key->c2;
+ md1_ctx->c3 = nsh_key->c3;
+ md1_ctx->c4 = nsh_key->c4;
+ } else {
+ nsh_header->base.reserved_flags1 = ~nsh_mask->flags &
+ nsh_key->flags & 0x0F;
+ nsh_header->base.context_flag = (~nsh_mask->flags &
+ nsh_key->flags & 0x10) >> 4;
+ nsh_header->base.oam_flag = (~nsh_mask->flags &
+ nsh_key->flags & 0x20) >> 5;
+ nsh_header->base.version = (~nsh_mask->flags &
+ nsh_key->flags & 0xC0) >> 6;
+ nsh_header->base.md_type = ~nsh_mask->mdtype & nsh_key->mdtype;
+ nsh_header->base.next_proto = ~nsh_mask->np & nsh_key->np;
+ nsh_header->base.path_hdr = ((~nsh_mask->spi & nsh_key->spi) >> 8) |
+ ((~nsh_mask->si & nsh_key->si) << 24);
+ md1_ctx->c1 = ~nsh_mask->c1 & nsh_key->c1;
+ md1_ctx->c2 = ~nsh_mask->c2 & nsh_key->c2;
+ md1_ctx->c3 = ~nsh_mask->c3 & nsh_key->c3;
+ md1_ctx->c4 = ~nsh_mask->c4 & nsh_key->c4;
+ }
+}
+
/* Set ethertype of the packet. */
static void
set_ethertype(struct dp_packet *packet, ovs_be16 eth_type)
diff --git a/lib/packets.h b/lib/packets.h
index 34d56b4..e271246 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -25,6 +25,7 @@
#include "openvswitch/geneve.h"
#include "openvswitch/packets.h"
#include "openvswitch/types.h"
+#include "openvswitch/nsh.h"
#include "odp-netlink.h"
#include "random.h"
#include "hash.h"
@@ -1198,6 +1199,7 @@ void packet_set_sctp_port(struct dp_packet *, ovs_be16
src, ovs_be16 dst);
void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code);
void packet_set_nd(struct dp_packet *, const struct in6_addr *target,
const struct eth_addr sll, const struct eth_addr tll);
+void packet_set_nsh(struct dp_packet *packet, const struct flow_nsh * nsh_key,
const struct flow_nsh *nsh_mask);
void packet_format_tcp_flags(struct ds *, uint16_t);
const char *packet_tcp_flag_to_string(uint32_t flag);
--
2.1.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev