[ovs-dev] [PATCH v2 2/7] nsh: userland support for network service headers
Pritesh Kothari
pritesh.kothari at cisco.com
Tue Feb 25 23:44:15 UTC 2014
NSH service path (nsp) can be set/unset while creating the port
as well as nsp can be matched on incoming packets.
Signed-off-by: Pritesh Kothari <pritesh.kothari at cisco.com>
diff --git a/lib/flow.c b/lib/flow.c
index e7fe4d3..28e96ec 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -563,6 +563,8 @@ flow_tun_flag_to_string(uint32_t flags)
return "csum";
case FLOW_TNL_F_KEY:
return "key";
+ case FLOW_TNL_F_NSP:
+ return "nsp";
default:
return NULL;
}
diff --git a/lib/flow.h b/lib/flow.h
index 3109a84..6086904 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -56,11 +56,13 @@ BUILD_ASSERT_DECL(FLOW_NW_FRAG_LATER == NX_IP_FRAG_LATER);
#define FLOW_TNL_F_DONT_FRAGMENT (1 << 0)
#define FLOW_TNL_F_CSUM (1 << 1)
#define FLOW_TNL_F_KEY (1 << 2)
+#define FLOW_TNL_F_NSP (1 << 3)
const char *flow_tun_flag_to_string(uint32_t flags);
struct flow_tnl {
ovs_be64 tun_id;
+ ovs_be32 nsp;
ovs_be32 ip_src;
ovs_be32 ip_dst;
uint16_t flags;
diff --git a/lib/match.c b/lib/match.c
index b2a25fd..091ada5 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -70,6 +70,9 @@ match_wc_init(struct match *match, const struct flow *flow)
if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
}
+ if (flow->tunnel.flags & FLOW_TNL_F_NSP) {
+ memset(&wc->masks.tunnel.nsp, 0xff, sizeof wc->masks.tunnel.nsp);
+ }
memset(&wc->masks.tunnel.ip_src, 0xff, sizeof wc->masks.tunnel.ip_src);
memset(&wc->masks.tunnel.ip_dst, 0xff, sizeof wc->masks.tunnel.ip_dst);
memset(&wc->masks.tunnel.flags, 0xff, sizeof wc->masks.tunnel.flags);
@@ -79,6 +82,10 @@ match_wc_init(struct match *match, const struct flow *flow)
memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
}
+ if (flow->tunnel.nsp) {
+ memset(&wc->masks.tunnel.nsp, 0xff, sizeof wc->masks.tunnel.nsp);
+ }
+
memset(&wc->masks.metadata, 0xff, sizeof wc->masks.metadata);
memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
@@ -751,6 +758,19 @@ match_set_nd_target_masked(struct match *match,
match->wc.masks.nd_target = *mask;
}
+void
+match_set_nsp_masked(struct match *match, ovs_be32 nsp, ovs_be32 mask)
+{
+ match->wc.masks.tunnel.nsp = mask;
+ match->flow.tunnel.nsp = nsp & mask;
+}
+
+void
+match_set_nsp(struct match *match, ovs_be32 nsp)
+{
+ match_set_nsp_masked(match, nsp, htonl(UINT32_MAX));
+}
+
/* Returns true if 'a' and 'b' wildcard the same fields and have the same
* values for fixed fields, otherwise false. */
bool
@@ -867,6 +887,7 @@ format_flow_tunnel(struct ds *s, const struct match *match)
const struct flow_tnl *tnl = &match->flow.tunnel;
format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
+ format_uint32_masked(s, "nsp", tnl->nsp, wc->masks.tunnel.nsp);
format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
diff --git a/lib/match.h b/lib/match.h
index 7a8ae68..1c8dd15 100644
--- a/lib/match.h
+++ b/lib/match.h
@@ -124,6 +124,8 @@ void match_set_ipv6_label_masked(struct match *, ovs_be32, ovs_be32);
void match_set_nd_target(struct match *, const struct in6_addr *);
void match_set_nd_target_masked(struct match *, const struct in6_addr *,
const struct in6_addr *);
+void match_set_nsp(struct match *, ovs_be32 nsp);
+void match_set_nsp_masked(struct match *, ovs_be32 nsp, ovs_be32 mask);
bool match_equal(const struct match *, const struct match *);
uint32_t match_hash(const struct match *, uint32_t basis);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 3afcd4c..5a620a1 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -763,7 +763,25 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
OFPUTIL_P_NXM_OXM_ANY,
OFPUTIL_P_NXM_OXM_ANY,
-1,
- }
+ },
+
+ /* ## ---- ## */
+ /* ## L"S" ## */
+ /* ## ---- ## */
+
+ {
+ MFF_NSP, "nsp", NULL,
+ sizeof(ovs_be32), 24,
+ MFM_FULLY,
+ MFS_HEXADECIMAL,
+ MFP_NONE,
+ false,
+ 0, NULL,
+ 0, NULL,
+ OFPUTIL_P_NONE,
+ OFPUTIL_P_NONE,
+ -1,
+ },
};
/* Maps an NXM or OXM header value to an mf_field. */
@@ -888,6 +906,8 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
case MFF_TUN_TTL:
case MFF_TUN_FLAGS:
return !wc->masks.tunnel.tun_id;
+ case MFF_NSP:
+ return !wc->masks.tunnel.nsp;
case MFF_METADATA:
return !wc->masks.metadata;
case MFF_IN_PORT:
@@ -1162,6 +1182,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_ND_TARGET:
case MFF_ND_SLL:
case MFF_ND_TLL:
+ case MFF_NSP:
return true;
case MFF_IN_PORT_OXM: {
@@ -1396,6 +1417,10 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
value->ipv6 = flow->nd_target;
break;
+ case MFF_NSP:
+ value->be32 = flow->tunnel.nsp;
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1593,6 +1618,10 @@ mf_set_value(const struct mf_field *mf,
match_set_nd_target(match, &value->ipv6);
break;
+ case MFF_NSP:
+ match_set_nsp(match, value->be32);
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -1810,6 +1839,10 @@ mf_set_flow_value(const struct mf_field *mf,
flow->nd_target = value->ipv6;
break;
+ case MFF_NSP:
+ flow->tunnel.nsp = value->be32;
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -2019,6 +2052,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
memset(&match->flow.nd_target, 0, sizeof match->flow.nd_target);
break;
+ case MFF_NSP:
+ match_set_nsp_masked(match, htonl(0), htonl(0));
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
@@ -2187,6 +2224,10 @@ mf_set(const struct mf_field *mf,
match_set_tcp_flags_masked(match, value->be16, mask->be16);
break;
+ case MFF_NSP:
+ match_set_nsp_masked(match, value->be32, mask->be32);
+ break;
+
case MFF_N_IDS:
default:
OVS_NOT_REACHED();
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index cf92556..a2977e4 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -139,6 +139,9 @@ enum OVS_PACKED_ENUM mf_field_id {
MFF_ND_SLL, /* mac */
MFF_ND_TLL, /* mac */
+ /* Network Service Headers (NSH) Fields */
+ MFF_NSP, /* be32 */
+
MFF_N_IDS
};
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 165c1c6..ce33150 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -45,6 +45,7 @@ VLOG_DEFINE_THIS_MODULE(netdev_vport);
#define VXLAN_DST_PORT 4789
#define LISP_DST_PORT 4341
+#define NSH_DST_PORT 6633
#define DEFAULT_TTL 64
@@ -311,6 +312,33 @@ parse_key(const struct smap *args, const char *name,
}
}
+static ovs_be32
+parse_nsp(const struct smap *args, const char *name,
+ bool *present, bool *flow)
+{
+ const char *s;
+
+ *present = false;
+ *flow = false;
+
+ s = smap_get(args, name);
+ if (!s) {
+ s = smap_get(args, "nsp");
+ if (!s) {
+ return 0;
+ }
+ }
+
+ *present = true;
+
+ if (!strcmp(s, "flow")) {
+ *flow = true;
+ return 0;
+ } else {
+ return htonl(strtoul(s, NULL, 0));
+ }
+}
+
static int
set_tunnel_config(struct netdev *dev_, const struct smap *args)
{
@@ -414,6 +442,10 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
!strcmp(node->key, "in_key") ||
!strcmp(node->key, "out_key")) {
/* Handled separately below. */
+ } else if (!strcmp(node->key, "nsp") ||
+ !strcmp(node->key, "in_nsp") ||
+ !strcmp(node->key, "out_nsp")) {
+ /* Handled separately below. */
} else {
VLOG_WARN("%s: unknown %s argument '%s'", name, type, node->key);
}
@@ -482,6 +514,16 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
&tnl_cfg.out_key_present,
&tnl_cfg.out_key_flow);
+ if (tnl_cfg.dst_port == htons(NSH_DST_PORT)) {
+ tnl_cfg.in_nsp = parse_nsp(args, "in_nsp",
+ &tnl_cfg.in_nsp_present,
+ &tnl_cfg.in_nsp_flow);
+
+ tnl_cfg.out_nsp = parse_nsp(args, "out_nsp",
+ &tnl_cfg.out_nsp_present,
+ &tnl_cfg.out_nsp_flow);
+ }
+
ovs_mutex_lock(&dev->mutex);
dev->tnl_cfg = tnl_cfg;
seq_change(connectivity_seq_get());
@@ -495,6 +537,7 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
{
struct netdev_vport *netdev = netdev_vport_cast(dev);
struct netdev_tunnel_config tnl_cfg;
+ const char *type = netdev_get_type(dev);
ovs_mutex_lock(&netdev->mutex);
tnl_cfg = netdev->tnl_cfg;
@@ -533,6 +576,27 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
}
}
+ if (tnl_cfg.in_nsp_flow && tnl_cfg.out_nsp_flow) {
+ smap_add(args, "nsp", "flow");
+ } else if (tnl_cfg.in_nsp_present && tnl_cfg.out_nsp_present
+ && tnl_cfg.in_nsp == tnl_cfg.out_nsp) {
+ smap_add_format(args, "nsp", "%#"PRIx32, ntohl(tnl_cfg.in_nsp));
+ } else {
+ if (tnl_cfg.in_nsp_flow) {
+ smap_add(args, "in_nsp", "flow");
+ } else if (tnl_cfg.in_nsp_present) {
+ smap_add_format(args, "in_nsp", "%#"PRIx32,
+ ntohl(tnl_cfg.in_nsp));
+ }
+
+ if (tnl_cfg.out_nsp_flow) {
+ smap_add(args, "out_nsp", "flow");
+ } else if (tnl_cfg.out_nsp_present) {
+ smap_add_format(args, "out_nsp", "%#"PRIx32,
+ ntohl(tnl_cfg.out_nsp));
+ }
+ }
+
if (tnl_cfg.ttl_inherit) {
smap_add(args, "ttl", "inherit");
} else if (tnl_cfg.ttl != DEFAULT_TTL) {
@@ -547,7 +611,6 @@ get_tunnel_config(const struct netdev *dev, struct smap *args)
if (tnl_cfg.dst_port) {
uint16_t dst_port = ntohs(tnl_cfg.dst_port);
- const char *type = netdev_get_type(dev);
if ((!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
(!strcmp("lisp", type) && dst_port != LISP_DST_PORT)) {
diff --git a/lib/netdev.h b/lib/netdev.h
index 410c35b..ba99062 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -102,6 +102,14 @@ struct netdev_stats {
/* Configuration specific to tunnels. */
struct netdev_tunnel_config {
+ bool in_nsp_present;
+ bool in_nsp_flow;
+ ovs_be32 in_nsp; /* incoming NSH service path */
+
+ bool out_nsp_present;
+ bool out_nsp_flow;
+ ovs_be32 out_nsp; /* outgoing NSH service path */
+
bool in_key_present;
bool in_key_flow;
ovs_be64 in_key;
diff --git a/lib/odp-util.c b/lib/odp-util.c
index e20564f..8cfcca5 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -801,6 +801,7 @@ tunnel_key_attr_len(int type)
case OVS_TUNNEL_KEY_ATTR_TTL: return 1;
case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: return 0;
case OVS_TUNNEL_KEY_ATTR_CSUM: return 0;
+ case OVS_TUNNEL_KEY_ATTR_NSP: return 4;
case __OVS_TUNNEL_KEY_ATTR_MAX:
return -1;
}
@@ -848,6 +849,10 @@ odp_tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun)
case OVS_TUNNEL_KEY_ATTR_CSUM:
tun->flags |= FLOW_TNL_F_CSUM;
break;
+ case OVS_TUNNEL_KEY_ATTR_NSP:
+ tun->nsp = nl_attr_get_be32(a);
+ tun->flags |= FLOW_TNL_F_NSP;
+ break;
default:
/* Allow this to show up as unexpected, if there are unknown
* tunnel attribute, eventually resulting in ODP_FIT_TOO_MUCH. */
@@ -891,6 +896,9 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key)
if (tun_key->flags & FLOW_TNL_F_CSUM) {
nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_CSUM);
}
+ if (tun_key->flags & FLOW_TNL_F_NSP) {
+ nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_NSP, tun_key->nsp);
+ }
nl_msg_end_nested(a, tun_key_ofs);
}
@@ -917,6 +925,7 @@ odp_mask_attr_is_exact(const struct nlattr *ma)
odp_tun_key_from_attr(ma, &tun_mask);
if (tun_mask.flags == (FLOW_TNL_F_KEY
| FLOW_TNL_F_DONT_FRAGMENT
+ | FLOW_TNL_F_NSP
| FLOW_TNL_F_CSUM)) {
/* The flags are exact match, check the remaining fields. */
tun_mask.flags = 0xffff;
@@ -1041,10 +1050,12 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
memset(&tun_mask, 0, sizeof tun_mask);
odp_tun_key_from_attr(ma, &tun_mask);
ds_put_format(ds, "tun_id=%#"PRIx64"/%#"PRIx64
+ ",nsp=%#"PRIx32"/%#"PRIx32
",src="IP_FMT"/"IP_FMT",dst="IP_FMT"/"IP_FMT
",tos=%#"PRIx8"/%#"PRIx8",ttl=%"PRIu8"/%#"PRIx8
",flags(",
ntohll(tun_key.tun_id), ntohll(tun_mask.tun_id),
+ ntohl(tun_key.nsp), ntohl(tun_mask.nsp),
IP_ARGS(tun_key.ip_src), IP_ARGS(tun_mask.ip_src),
IP_ARGS(tun_key.ip_dst), IP_ARGS(tun_mask.ip_dst),
tun_key.ip_tos, tun_mask.ip_tos,
@@ -1060,9 +1071,11 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
*/
ds_put_char(ds, ')');
} else {
- ds_put_format(ds, "tun_id=0x%"PRIx64",src="IP_FMT",dst="IP_FMT","
+ ds_put_format(ds, "tun_id=0x%"PRIx64",nsp=0x%"PRIx32
+ ",src="IP_FMT",dst="IP_FMT","
"tos=0x%"PRIx8",ttl=%"PRIu8",flags(",
ntohll(tun_key.tun_id),
+ ntohl(tun_key.nsp),
IP_ARGS(tun_key.ip_src),
IP_ARGS(tun_key.ip_dst),
tun_key.ip_tos, tun_key.ip_ttl);
@@ -1621,13 +1634,16 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
{
uint64_t tun_id, tun_id_mask;
struct flow_tnl tun_key, tun_key_mask;
+ uint32_t nsp, nsp_mask;
int n = -1;
if (mask && ovs_scan(s, "tunnel(tun_id=%"SCNi64"/%"SCNi64","
+ "nsp=%"PRIx32"/%"PRIx32","
"src="IP_SCAN_FMT"/"IP_SCAN_FMT",dst="IP_SCAN_FMT
"/"IP_SCAN_FMT",tos=%"SCNi8"/%"SCNi8","
"ttl=%"SCNi8"/%"SCNi8",flags%n",
&tun_id, &tun_id_mask,
+ &nsp, &nsp_mask,
IP_SCAN_ARGS(&tun_key.ip_src),
IP_SCAN_ARGS(&tun_key_mask.ip_src),
IP_SCAN_ARGS(&tun_key.ip_dst),
@@ -1639,6 +1655,8 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
tun_key.tun_id = htonll(tun_id);
tun_key_mask.tun_id = htonll(tun_id_mask);
+ tun_key.nsp = htonl(nsp);
+ tun_key_mask.nsp = htonl(nsp_mask);
res = parse_flags(&s[n], flow_tun_flag_to_string, &flags);
tun_key.flags = flags;
tun_key_mask.flags = UINT16_MAX;
@@ -1657,8 +1675,10 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
}
return n;
} else if (ovs_scan(s, "tunnel(tun_id=%"SCNi64","
+ "nsp=%"PRIx32","
"src="IP_SCAN_FMT",dst="IP_SCAN_FMT
",tos=%"SCNi8",ttl=%"SCNi8",flags%n", &tun_id,
+ &tun_key.nsp,
IP_SCAN_ARGS(&tun_key.ip_src),
IP_SCAN_ARGS(&tun_key.ip_dst),
&tun_key.ip_tos, &tun_key.ip_ttl, &n)) {
@@ -1666,6 +1686,7 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
uint32_t flags;
tun_key.tun_id = htonll(tun_id);
+ tun_key.nsp = htonl(tun_key.nsp);
res = parse_flags(&s[n], flow_tun_flag_to_string, &flags);
tun_key.flags = flags;
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 7bc64c7..1ad272e 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -106,6 +106,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
* - OVS_TUNNEL_KEY_ATTR_TTL 1 3 4 8
* - OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT 0 -- 4 4
* - OVS_TUNNEL_KEY_ATTR_CSUM 0 -- 4 4
+ * - OVS_TUNNEL_KEY_ATTR_NSP 4 -- 4 8
* OVS_KEY_ATTR_IN_PORT 4 -- 4 8
* OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
* OVS_KEY_ATTR_ETHERNET 12 -- 4 16
@@ -117,7 +118,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
* OVS_KEY_ATTR_ICMPV6 2 2 4 8
* OVS_KEY_ATTR_ND 28 -- 4 32
* ----------------------------------------------------------
- * total 208
+ * total 216
*
* We include some slack space in case the calculation isn't quite right or we
* add another field and forget to adjust this value.
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index 38b782f..d1d629c 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -38,11 +38,13 @@ VLOG_DEFINE_THIS_MODULE(tunnel);
struct tnl_match {
ovs_be64 in_key;
+ ovs_be32 in_nsp;
ovs_be32 ip_src;
ovs_be32 ip_dst;
odp_port_t odp_port;
uint32_t pkt_mark;
bool in_key_flow;
+ bool in_nsp_flow;
bool ip_src_flow;
bool ip_dst_flow;
};
@@ -76,17 +78,21 @@ static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER;
* (ip_dst_flow == false) or arrange for the destination IP to be matched
* as tunnel.ip_dst in the OpenFlow flow (ip_dst_flow == true).
*
+ * - in_nsp: A vport may match a specific NSH service path (in_nsp_flow ==
+ * false) or arrange for the service path to be matched as tunnel.in_nsp
+ * in the OpenFlow flow (in_nsp_flow == true).
+ *
* - ip_src: A vport may match a specific IP source address (ip_src_flow ==
* false, ip_src != 0), wildcard all source addresses (ip_src_flow ==
* false, ip_src == 0), or arrange for the IP source address to be
* handled in the OpenFlow flow table (ip_src_flow == true).
*
- * Thus, there are 2 * 2 * 3 == 12 possible ways a vport can match against a
- * tunnel packet. We number the possibilities for each field in increasing
- * order as listed in each bullet above. We order the 12 overall combinations
- * in lexicographic order considering in_key first, then ip_dst, then
- * ip_src. */
-#define N_MATCH_TYPES (2 * 2 * 3)
+ * Thus, there are 2 * 2 * 2 * 3 == 24 possible ways a vport can match
+ * against a tunnel packet. We number the possibilities for each field in
+ * increasing order as listed in each bullet above. We order the 24 overall
+ * combinations in lexicographic order considering in_key first, then ip_dst,
+ * then in_nsp, then ip_src. */
+#define N_MATCH_TYPES (2 * 2 * 2 * 3)
/* The three possibilities (see above) for vport ip_src matches. */
enum ip_src_type {
@@ -101,6 +107,17 @@ enum ip_src_type {
static struct hmap *tnl_match_maps[N_MATCH_TYPES] OVS_GUARDED_BY(rwlock);
static struct hmap **tnl_match_map(const struct tnl_match *);
+/* The tnl_match_maps_bm is a bitmap for tnl_match_maps showing places which
+ * are filled */
+static uint64_t tnl_match_maps_bm OVS_GUARDED_BY(rwlock);
+static void tnl_match_maps_bm_set(unsigned int);
+static void tnl_match_maps_bm_reset(unsigned int);
+static bool tnl_match_maps_bm_check(unsigned int);
+
+static unsigned int tnl_match_m_to_idx(const struct tnl_match *);
+static void tnl_match_idx_to_m(const struct flow *, unsigned int,
+ struct tnl_match *);
+
static struct hmap ofport_map__ = HMAP_INITIALIZER(&ofport_map__);
static struct hmap *ofport_map OVS_GUARDED_BY(rwlock) = &ofport_map__;
@@ -131,6 +148,7 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
struct tnl_port *existing_port;
struct tnl_port *tnl_port;
struct hmap **map;
+ unsigned int idx;
cfg = netdev_get_tunnel_config(netdev);
ovs_assert(cfg);
@@ -141,14 +159,17 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
tnl_port->change_seq = seq_read(connectivity_seq_get());
tnl_port->match.in_key = cfg->in_key;
+ tnl_port->match.in_nsp = cfg->in_nsp;
tnl_port->match.ip_src = cfg->ip_src;
tnl_port->match.ip_dst = cfg->ip_dst;
tnl_port->match.ip_src_flow = cfg->ip_src_flow;
tnl_port->match.ip_dst_flow = cfg->ip_dst_flow;
tnl_port->match.pkt_mark = cfg->ipsec ? IPSEC_MARK : 0;
tnl_port->match.in_key_flow = cfg->in_key_flow;
+ tnl_port->match.in_nsp_flow = cfg->in_nsp_flow;
tnl_port->match.odp_port = odp_port;
+ idx = tnl_match_m_to_idx(&tnl_port->match);
map = tnl_match_map(&tnl_port->match);
existing_port = tnl_find_exact(&tnl_port->match, *map);
if (existing_port) {
@@ -169,6 +190,7 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
if (!*map) {
*map = xmalloc(sizeof **map);
hmap_init(*map);
+ tnl_match_maps_bm_set(idx);
}
hmap_insert(*map, &tnl_port->match_node, tnl_hash(&tnl_port->match));
tnl_port_mod_log(tnl_port, "adding");
@@ -219,6 +241,7 @@ static void
tnl_port_del__(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(rwlock)
{
struct tnl_port *tnl_port;
+ unsigned int idx;
if (!ofport) {
return;
@@ -229,10 +252,12 @@ tnl_port_del__(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(rwlock)
struct hmap **map;
tnl_port_mod_log(tnl_port, "removing");
+ idx = tnl_match_m_to_idx(&tnl_port->match);
map = tnl_match_map(&tnl_port->match);
hmap_remove(*map, &tnl_port->match_node);
if (hmap_is_empty(*map)) {
hmap_destroy(*map);
+ tnl_match_maps_bm_reset(idx);
free(*map);
*map = NULL;
}
@@ -379,6 +404,10 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
flow->tunnel.tun_id = cfg->out_key;
}
+ if (!cfg->out_nsp_flow) {
+ flow->tunnel.nsp = cfg->out_nsp;
+ }
+
if (cfg->ttl_inherit && is_ip_any(flow)) {
wc->masks.nw_ttl = 0xff;
flow->tunnel.ip_ttl = flow->nw_ttl;
@@ -406,6 +435,7 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
flow->tunnel.flags = (cfg->dont_fragment ? FLOW_TNL_F_DONT_FRAGMENT : 0)
| (cfg->csum ? FLOW_TNL_F_CSUM : 0)
+ | (cfg->out_nsp_present ? FLOW_TNL_F_NSP : 0)
| (cfg->out_key_present ? FLOW_TNL_F_KEY : 0);
if (pre_flow_str) {
@@ -468,46 +498,22 @@ tnl_find_exact(struct tnl_match *match, struct hmap *map)
static struct tnl_port *
tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
{
- enum ip_src_type ip_src;
- int in_key_flow;
- int ip_dst_flow;
int i;
- i = 0;
- for (in_key_flow = 0; in_key_flow < 2; in_key_flow++) {
- for (ip_dst_flow = 0; ip_dst_flow < 2; ip_dst_flow++) {
- for (ip_src = 0; ip_src < 3; ip_src++) {
- struct hmap *map = tnl_match_maps[i];
-
- if (map) {
- struct tnl_port *tnl_port;
- struct tnl_match match;
-
- memset(&match, 0, sizeof match);
-
- /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
- * correct, because "struct tnl_match" is expressed in
- * terms of packets being sent out, but we are using it
- * here as a description of how to treat received
- * packets. */
- match.in_key = in_key_flow ? 0 : flow->tunnel.tun_id;
- match.ip_src = (ip_src == IP_SRC_CFG
- ? flow->tunnel.ip_dst
- : 0);
- match.ip_dst = ip_dst_flow ? 0 : flow->tunnel.ip_src;
- match.odp_port = flow->in_port.odp_port;
- match.pkt_mark = flow->pkt_mark;
- match.in_key_flow = in_key_flow;
- match.ip_dst_flow = ip_dst_flow;
- match.ip_src_flow = ip_src == IP_SRC_FLOW;
-
- tnl_port = tnl_find_exact(&match, map);
- if (tnl_port) {
- return tnl_port;
- }
- }
+ for (i = 0; i < N_MATCH_TYPES; i++) {
+ if (tnl_match_maps_bm_check(i)) {
+ struct hmap *map = tnl_match_maps[i];
+
+ if (map) {
+ struct tnl_port *tnl_port;
+ struct tnl_match match;
- i++;
+ memset(&match, 0, sizeof match);
+ tnl_match_idx_to_m(flow, i, &match);
+ tnl_port = tnl_find_exact(&match, map);
+ if (tnl_port) {
+ return tnl_port;
+ }
}
}
}
@@ -515,10 +521,58 @@ tnl_find(const struct flow *flow) OVS_REQ_RDLOCK(rwlock)
return NULL;
}
-/* Returns a pointer to the 'tnl_match_maps' element corresponding to 'm''s
- * matching criteria. */
-static struct hmap **
-tnl_match_map(const struct tnl_match *m)
+/* Coverts a index to corresponding matching criteria 'm'. */
+static void
+tnl_match_idx_to_m(const struct flow *flow, unsigned int idx,
+ struct tnl_match *m)
+{
+ enum ip_src_type ip_src;
+ bool in_key_flow;
+ bool ip_dst_flow;
+ bool in_nsp_flow;
+
+ if (!m)
+ return;
+
+ in_key_flow = (idx < (N_MATCH_TYPES / 2)) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / 2))
+ idx -= (N_MATCH_TYPES / 2);
+
+ ip_dst_flow = (idx < (N_MATCH_TYPES / (2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2));
+
+ in_nsp_flow = (idx < (N_MATCH_TYPES / (2 * 2 * 2))) ? false : true;
+
+ if (idx >= (N_MATCH_TYPES / (2 * 2 * 2)))
+ idx -= (N_MATCH_TYPES / (2 * 2 * 2));
+
+ ip_src = idx;
+
+ /* The apparent mix-up of 'ip_dst' and 'ip_src' below is
+ * correct, because "struct tnl_match" is expressed in
+ * terms of packets being sent out, but we are using it
+ * here as a description of how to treat received
+ * packets. */
+ m->in_key = in_key_flow ? 0 : flow->tunnel.tun_id;
+ m->ip_src = (ip_src == IP_SRC_CFG
+ ? flow->tunnel.ip_dst
+ : 0);
+ m->in_nsp = in_nsp_flow ? 0 : flow->tunnel.nsp;
+ m->ip_dst = ip_dst_flow ? 0 : flow->tunnel.ip_src;
+ m->odp_port = flow->in_port.odp_port;
+ m->pkt_mark = flow->pkt_mark;
+ m->in_key_flow = in_key_flow;
+ m->ip_dst_flow = ip_dst_flow;
+ m->in_nsp_flow = in_nsp_flow;
+ m->ip_src_flow = ip_src == IP_SRC_FLOW;
+}
+
+/* Returns a index corresponding to 'm''s matching criteria. */
+static unsigned int
+tnl_match_m_to_idx(const struct tnl_match *m)
{
enum ip_src_type ip_src;
@@ -526,7 +580,42 @@ tnl_match_map(const struct tnl_match *m)
: m->ip_src ? IP_SRC_CFG
: IP_SRC_ANY);
- return &tnl_match_maps[6 * m->in_key_flow + 3 * m->ip_dst_flow + ip_src];
+ return (m->in_key_flow * (N_MATCH_TYPES / 2) +
+ m->ip_dst_flow * (N_MATCH_TYPES / (2 * 2)) +
+ m->in_nsp_flow * (N_MATCH_TYPES / (2 * 2 * 2)) +
+ ip_src);
+}
+
+/* Returns a pointer to the 'tnl_match_maps' element corresponding to 'm''s
+ * matching criteria. */
+static struct hmap **
+tnl_match_map(const struct tnl_match *m)
+{
+ return &tnl_match_maps[tnl_match_m_to_idx(m)];
+}
+
+/* Set the bit corresponding to idx in tnl_match_maps_bm */
+static void
+tnl_match_maps_bm_set(unsigned int idx)
+{
+ if (idx < N_MATCH_TYPES)
+ tnl_match_maps_bm |= 1 << idx;
+}
+
+/* Reset the bit corresponding to idx in tnl_match_maps_bm */
+static void
+tnl_match_maps_bm_reset(unsigned int idx)
+{
+ if (idx < N_MATCH_TYPES)
+ tnl_match_maps_bm &= ~(1 << idx);
+}
+
+/* Return the bit corresponding to idx in tnl_match_maps_bm */
+static bool
+tnl_match_maps_bm_check(unsigned int idx)
+{
+ if (idx < N_MATCH_TYPES)
+ return (tnl_match_maps_bm & (1 << idx)) != 0;
}
static void
@@ -548,6 +637,12 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
}
+ if (match->in_nsp_flow) {
+ ds_put_cstr(ds, ", nsp=flow");
+ } else {
+ ds_put_format(ds, ", nsp=%#"PRIx32, ntohl(match->in_nsp));
+ }
+
ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
ds_put_format(ds, ", pkt mark=%"PRIu32, match->pkt_mark);
}
@@ -591,6 +686,19 @@ tnl_port_fmt(const struct tnl_port *tnl_port) OVS_REQ_RDLOCK(rwlock)
}
}
+ if (cfg->out_nsp != cfg->in_nsp ||
+ cfg->out_nsp_present != cfg->in_nsp_present ||
+ cfg->out_nsp_flow != cfg->in_nsp_flow) {
+ ds_put_cstr(&ds, ", out_nsp=");
+ if (!cfg->out_nsp_present) {
+ ds_put_cstr(&ds, "none");
+ } else if (cfg->out_nsp_flow) {
+ ds_put_cstr(&ds, "flow");
+ } else {
+ ds_put_format(&ds, "%#"PRIx32, ntohl(cfg->out_nsp));
+ }
+ }
+
if (cfg->ttl_inherit) {
ds_put_cstr(&ds, ", ttl=inherit");
} else {
--
1.7.9.5
More information about the dev
mailing list