NSH service path (nsp) can be set/unset while creating the port as well nsp can be matched on incoming packets.
Signed-off-by: Pritesh Kothari <pritesh.koth...@cisco.com> --- lib/flow.c | 2 + lib/flow.h | 2 + lib/match.c | 21 ++++++ lib/match.h | 2 + lib/meta-flow.c | 43 ++++++++++- lib/meta-flow.h | 3 + lib/netdev-vport.c | 65 +++++++++++++++- lib/netdev.h | 8 ++ lib/odp-util.c | 23 +++++- lib/odp-util.h | 3 +- lib/packets.h | 2 +- ofproto/tunnel.c | 208 ++++++++++++++++++++++++++++++++++++++++------------ 12 files changed, 329 insertions(+), 53 deletions(-) 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..83cbdc6 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, OVS_BE32_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_be32_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 d90477a..d1e3457 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: { @@ -1395,6 +1416,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(); @@ -1591,6 +1616,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(); @@ -1807,6 +1836,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(); @@ -2015,6 +2048,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(); @@ -2183,6 +2220,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..83f550d 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, + &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(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/lib/packets.h b/lib/packets.h index 1855a1c..69f2fce 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -40,7 +40,7 @@ struct pkt_metadata { }; #define PKT_METADATA_INITIALIZER(PORT) \ - (struct pkt_metadata){ { 0, 0, 0, 0, 0, 0}, 0, 0, (PORT) } + (struct pkt_metadata){ { 0, 0, 0, 0, 0, 0, 0}, 0, 0, (PORT) } bool dpid_from_string(const char *s, uint64_t *dpidp); diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c index 38b782f..e78170d 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) OVS_REQ_WRLOCK(rwlock); +static void tnl_match_maps_bm_reset(unsigned int) OVS_REQ_WRLOCK(rwlock); +static bool tnl_match_maps_bm_check(unsigned int) OVS_REQ_RDLOCK(rwlock); + +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,46 @@ 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) OVS_REQ_WRLOCK(rwlock) +{ + 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) OVS_REQ_WRLOCK(rwlock) +{ + 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) OVS_REQ_RDLOCK(rwlock) +{ + if (idx < N_MATCH_TYPES) { + return (tnl_match_maps_bm & (1 << idx)) != 0; + } + return false; } static void @@ -548,6 +641,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 +690,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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev