pkt->md.ct_label = alg_exp->master_label;
key = &alg_exp->master_key;
}
+
pkt->md.ct_orig_tuple_ipv6 = false;
+
if (key) {
if (key->dl_type == htons(ETH_TYPE_IP)) {
+
pkt->md.ct_orig_tuple.ipv4 = (struct ovs_key_ct_tuple_ipv4) {
key->src.addr.ipv4_aligned,
key->dst.addr.ipv4_aligned,
pkt->md.ct_state = CS_INVALID;
return nc;
}
+
pkt->md.ct_state = CS_NEW;
+ if (alg_exp) {
+ pkt->md.ct_state |= CS_RELATED;
+ }
+ if (alg_exp) {
+ pkt->md.ct_state |= CS_RELATED;
+ }
+
if (commit) {
unsigned int n_conn_limit;
-
atomic_read_relaxed(&ct->n_conn_limit, &n_conn_limit);
if (atomic_count_get(&ct->n_conn) >= n_conn_limit) {
ovs_mutex_lock(&netdev_hmap_mutex);
data = netdev_ports_lookup(port_no, dpif_class);
-
if (data) {
+ int ifindex = netdev_get_ifindex(data->netdev);
+
+ if (ifindex > 0) {
+ struct ifindex_to_port_data *ifidx = NULL;
+
+ HMAP_FOR_EACH_WITH_HASH (ifidx, node, ifindex, &ifindex_to_port) {
+ if (ifidx->port == port_no) {
+ hmap_remove(&ifindex_to_port, &ifidx->node);
+ free(ifidx);
+ break;
+ }
+ }
+ ovs_assert(ifidx);
+ } else {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+ VLOG_WARN_RL(&rl, "netdev ports map has dpif port %"PRIu32
+ " but netdev has no ifindex: %s", port_no,
+ ovs_strerror(ifindex));
+ }
+
dpif_port_destroy(&data->dpif_port);
netdev_close(data->netdev); /* unref and possibly close */
- hmap_remove(&port_to_netdev, &data->node);
+ hmap_remove(&port_to_netdev, &data->portno_node);
+ hmap_remove(&ifindex_to_port, &data->ifindex_node);
free(data);
ret = 0;
}
return s - s_;
}
+ static void
+ nsh_key_to_attr(struct ofpbuf *buf, const struct ovs_key_nsh *nsh,
+ uint8_t * metadata, size_t md_size,
+ bool is_mask)
+ {
+ size_t nsh_key_ofs;
+ struct ovs_nsh_key_base base;
+
+ base.flags = nsh->flags;
+ base.ttl = nsh->ttl;
+ base.mdtype = nsh->mdtype;
+ base.np = nsh->np;
+ base.path_hdr = nsh->path_hdr;
+
+ nsh_key_ofs = nl_msg_start_nested(buf, OVS_KEY_ATTR_NSH);
+ nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_BASE, &base, sizeof base);
+
+ if (is_mask) {
+ nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, nsh->context,
+ sizeof nsh->context);
+ } else {
+ switch (nsh->mdtype) {
+ case NSH_M_TYPE1:
+ nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD1, nsh->context,
+ sizeof nsh->context);
+ break;
+ case NSH_M_TYPE2:
+ if (metadata && md_size > 0) {
+ nl_msg_put_unspec(buf, OVS_NSH_KEY_ATTR_MD2, metadata,
+ md_size);
+ }
+ break;
+ default:
+ /* No match support for other MD formats yet. */
+ break;
+ }
+ }
+ nl_msg_end_nested(buf, nsh_key_ofs);
+ }
+
+
+ static int
+ parse_odp_push_nsh_action(const char *s, struct ofpbuf *actions)
+ {
+ int n = 0;
+ int ret = 0;
+ uint32_t spi = 0;
+ uint8_t si = 255;
+ uint32_t cd;
+ struct ovs_key_nsh nsh;
+ uint8_t metadata[NSH_CTX_HDRS_MAX_LEN];
+ uint8_t md_size = 0;
+
+ if (!ovs_scan_len(s, &n, "push_nsh(")) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* The default is NSH_M_TYPE1 */
+ nsh.flags = 0;
+ nsh.ttl = 63;
+ nsh.mdtype = NSH_M_TYPE1;
+ nsh.np = NSH_P_ETHERNET;
+ nsh.path_hdr = nsh_spi_si_to_path_hdr(0, 255);
+ memset(nsh.context, 0, NSH_M_TYPE1_MDLEN);
+
+ for (;;) {
+ n += strspn(s + n, delimiters);
+ if (s[n] == ')') {
+ break;
+ }
+
+ if (ovs_scan_len(s, &n, "flags=%"SCNi8, &nsh.flags)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "ttl=%"SCNi8, &nsh.ttl)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &nsh.mdtype)) {
+ switch (nsh.mdtype) {
+ case NSH_M_TYPE1:
+ /* This is the default format. */;
+ break;
+ case NSH_M_TYPE2:
+ /* Length will be updated later. */
+ md_size = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "np=%"SCNi8, &nsh.np)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &spi)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "si=%"SCNi8, &si)) {
+ continue;
+ }
+ if (nsh.mdtype == NSH_M_TYPE1) {
+ if (ovs_scan_len(s, &n, "c1=0x%"SCNx32, &cd)) {
+ nsh.context[0] = htonl(cd);
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c2=0x%"SCNx32, &cd)) {
+ nsh.context[1] = htonl(cd);
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c3=0x%"SCNx32, &cd)) {
+ nsh.context[2] = htonl(cd);
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c4=0x%"SCNx32, &cd)) {
+ nsh.context[3] = htonl(cd);
+ continue;
+ }
+ }
+ else if (nsh.mdtype == NSH_M_TYPE2) {
+ struct ofpbuf b;
+ char buf[512];
+ size_t mdlen, padding;
+ if (ovs_scan_len(s, &n, "md2=0x%511[0-9a-fA-F]", buf)) {
+ ofpbuf_use_stub(&b, metadata,
+ NSH_CTX_HDRS_MAX_LEN);
+ ofpbuf_put_hex(&b, buf, &mdlen);
+ /* Pad metadata to 4 bytes. */
+ padding = PAD_SIZE(mdlen, 4);
+ if (padding > 0) {
+ ofpbuf_push_zeros(&b, padding);
+ }
+ md_size = mdlen + padding;
+ ofpbuf_uninit(&b);
+ continue;
+ }
+ }
+
+ ret = -EINVAL;
+ goto out;
+ }
+ out:
+ if (ret >= 0) {
+ nsh.path_hdr = nsh_spi_si_to_path_hdr(spi, si);
+ size_t offset = nl_msg_start_nested(actions, OVS_ACTION_ATTR_PUSH_NSH);
+ nsh_key_to_attr(actions, &nsh, metadata, md_size, false);
+ nl_msg_end_nested(actions, offset);
+ ret = n;
+ }
+ return ret;
+ }
+
+static int
+parse_odp_encap_nsh_action(const char *s, struct ofpbuf *actions)
+{
+ int n = 0;
+ int ret = 0;
+ struct ovs_action_encap_nsh encap_nsh;
+ uint32_t spi;
+ uint8_t si;
+ uint32_t cd;
+
+ if (!ovs_scan_len(s, &n, "encap_nsh(")) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* The default is NSH_M_TYPE1 */
+ encap_nsh.flags = 0;
+ encap_nsh.mdtype = NSH_M_TYPE1;
+ encap_nsh.mdlen = NSH_M_TYPE1_MDLEN;
+ encap_nsh.path_hdr = htonl(255);
+ memset(encap_nsh.metadata, 0, NSH_M_TYPE1_MDLEN);
+
+ for (;;) {
+ n += strspn(s + n, delimiters);
+ if (s[n] == ')') {
+ break;
+ }
+
+ if (ovs_scan_len(s, &n, "flags=%"SCNi8, &encap_nsh.flags)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "mdtype=%"SCNi8, &encap_nsh.mdtype)) {
+ switch (encap_nsh.mdtype) {
+ case NSH_M_TYPE1:
+ /* This is the default format. */;
+ break;
+ case NSH_M_TYPE2:
+ /* Length will be updated later. */
+ encap_nsh.mdlen = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "np=%"SCNi8, &encap_nsh.np)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "spi=0x%"SCNx32, &spi)) {
+ encap_nsh.path_hdr =
+ htonl(((spi << NSH_SPI_SHIFT) & NSH_SPI_MASK) |
+ (ntohl(encap_nsh.path_hdr) & ~NSH_SPI_MASK));
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "si=%"SCNi8, &si)) {
+ encap_nsh.path_hdr =
+ htonl((si << NSH_SI_SHIFT) |
+ (ntohl(encap_nsh.path_hdr) & ~NSH_SI_MASK));
+ continue;
+ }
+ if (encap_nsh.mdtype == NSH_M_TYPE1) {
+ struct nsh_md1_ctx *md1 =
+ ALIGNED_CAST(struct nsh_md1_ctx *, encap_nsh.metadata);
+ if (ovs_scan_len(s, &n, "c1=0x%"SCNx32, &cd)) {
+ put_16aligned_be32(&md1->c[0], htonl(cd));
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c2=0x%"SCNx32, &cd)) {
+ put_16aligned_be32(&md1->c[1], htonl(cd));
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c3=0x%"SCNx32, &cd)) {
+ put_16aligned_be32(&md1->c[2], htonl(cd));
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c4=0x%"SCNx32, &cd)) {
+ put_16aligned_be32(&md1->c[3], htonl(cd));
+ continue;
+ }
+ }
+ else if (encap_nsh.mdtype == NSH_M_TYPE2) {
+ struct ofpbuf b;
+ char buf[512];
+ size_t mdlen;
+ if (ovs_scan_len(s, &n, "md2=0x%511[0-9a-fA-F]", buf)) {
+ ofpbuf_use_stub(&b, encap_nsh.metadata,
+ OVS_ENCAP_NSH_MAX_MD_LEN);
+ ofpbuf_put_hex(&b, buf, &mdlen);
+ encap_nsh.mdlen = mdlen;
+ ofpbuf_uninit(&b);
+ }
+ continue;
+ }
+ }
+out:
+ if (ret < 0) {
+ return ret;
+ } else {
+ size_t size = offsetof(struct ovs_action_encap_nsh, metadata)
+ + ROUND_UP(encap_nsh.mdlen, 4);
+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_ENCAP_NSH,
+ &encap_nsh, size);
+ return n;
+ }
+}
+
static int
parse_action_list(const char *s, const struct simap *port_names,
struct ofpbuf *actions)
xlate_report_debug(ctx, OFT_ACTION,
"Dropping packet as encap(ethernet) is not "
"supported for packet type ethernet.");
- ctx->error = 1;
+ ctx->error = XLATE_UNSUPPORTED_PACKET_TYPE;
+ }
+ }
+
+ /* For an MD2 NSH header returns a pointer to an ofpbuf with the encoded
+ * MD2 TLVs provided as encap properties to the encap operation. This
+ * will be stored as encap_data in the ctx and copied into the push_nsh
+ * action at the next commit. */
+ static struct ofpbuf *
+ rewrite_flow_push_nsh(struct xlate_ctx *ctx,
+ const struct ofpact_encap *encap,
+ struct flow *flow,
+ struct flow_wildcards *wc)
+ {
+ ovs_be32 packet_type = flow->packet_type;
+ const char *ptr = (char *) encap->props;
+ struct ofpbuf *buf = ofpbuf_new(NSH_CTX_HDRS_MAX_LEN);
+ uint8_t md_type = NSH_M_TYPE1;
+ uint8_t np = 0;
+ int i;
+
+ /* Scan the optional NSH encap TLV properties, if any. */
+ for (i = 0; i < encap->n_props; i++) {
+ struct ofpact_ed_prop *prop_ptr =
+ ALIGNED_CAST(struct ofpact_ed_prop *, ptr);
+ if (prop_ptr->prop_class == OFPPPC_NSH) {
+ switch (prop_ptr->type) {
+ case OFPPPT_PROP_NSH_MDTYPE: {
+ struct ofpact_ed_prop_nsh_md_type *prop_md_type =
+ ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *,
+ prop_ptr);
+ md_type = prop_md_type->md_type;
+ break;
+ }
+ case OFPPPT_PROP_NSH_TLV: {
+ struct ofpact_ed_prop_nsh_tlv *tlv_prop =
+ ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *,
+ prop_ptr);
+ struct nsh_md2_tlv *md2_ctx =
+ ofpbuf_put_uninit(buf, sizeof(*md2_ctx));
+ md2_ctx->md_class = tlv_prop->tlv_class;
+ md2_ctx->type = tlv_prop->tlv_type;
+ md2_ctx->length = tlv_prop->tlv_len;
+ size_t len = ROUND_UP(md2_ctx->length, 4);
+ size_t padding = len - md2_ctx->length;
+ ofpbuf_put(buf, tlv_prop->data, md2_ctx->length);
+ ofpbuf_put_zeros(buf, padding);
+ break;
+ }
+ default:
+ /* No other NSH encap properties defined yet. */
+ break;
+ }
+ }
+ ptr += ROUND_UP(prop_ptr->len, 8);
+ }
+ if (buf->size == 0 || buf->size > NSH_CTX_HDRS_MAX_LEN) {
+ ofpbuf_delete(buf);
+ buf = NULL;
}
+
+ /* Determine the Next Protocol field for NSH header. */
+ switch (ntohl(packet_type)) {
+ case PT_ETH:
+ np = NSH_P_ETHERNET;
+ break;
+ case PT_IPV4:
+ np = NSH_P_IPV4;
+ break;
+ case PT_IPV6:
+ np = NSH_P_IPV6;
+ break;
+ case PT_NSH:
+ np = NSH_P_NSH;
+ break;
+ default:
+ /* Error handling: drop packet. */
+ xlate_report_debug(ctx, OFT_ACTION,
+ "Dropping packet as encap(nsh) is not "
+ "supported for packet type (%d,0x%x)",
+ pt_ns(packet_type), pt_ns_type(packet_type));
+ ctx->error = XLATE_UNSUPPORTED_PACKET_TYPE;
+ return buf;
+ }
+ /* Note that we have matched on packet_type! */
+ wc->masks.packet_type = OVS_BE32_MAX;
+
+ /* Reset all current flow packet headers. */
+ memset(&flow->dl_dst, 0,
+ sizeof(struct flow) - offsetof(struct flow, dl_dst));
+
+ /* Populate the flow with the new NSH header. */
+ flow->packet_type = htonl(PT_NSH);
+ flow->dl_type = htons(ETH_TYPE_NSH);
+ flow->nsh.flags = 0;
+ flow->nsh.ttl = 63;
+ flow->nsh.np = np;
+ flow->nsh.path_hdr = htonl(255);
+
+ if (md_type == NSH_M_TYPE1) {
+ flow->nsh.mdtype = NSH_M_TYPE1;
+ memset(flow->nsh.context, 0, sizeof flow->nsh.context);
+ if (buf) {
+ /* Drop any MD2 context TLVs. */
+ ofpbuf_delete(buf);
+ buf = NULL;
+ }
+ } else if (md_type == NSH_M_TYPE2) {
+ flow->nsh.mdtype = NSH_M_TYPE2;
+ }
+ flow->nsh.mdtype &= NSH_MDTYPE_MASK;
+
+ return buf;
}
+/* For an MD2 NSH header returns a pointer to an ofpbuf with the encoded
+ * MD2 TLVs provided as encap properties to the encap operation. This
+ * will be stored as encap_data in the ctx and copied into the encap_nsh
+ * action at the next commit. */
+static struct ofpbuf *
+rewrite_flow_encap_nsh(struct xlate_ctx *ctx,
+ const struct ofpact_encap *encap,
+ struct flow *flow,
+ struct flow_wildcards *wc)
+{
+ ovs_be32 packet_type = flow->packet_type;
+ const char *ptr = (char *) encap->props;
+ struct ofpbuf *buf = ofpbuf_new(OVS_ENCAP_NSH_MAX_MD_LEN);
+ uint8_t md_type = NSH_M_TYPE1;
+ uint8_t np = 0;
+ int i;
+
+ /* Scan the optional NSH encap TLV properties, if any. */
+ for (i = 0; i < encap->n_props; i++) {
+ struct ofpact_ed_prop *prop_ptr =
+ ALIGNED_CAST(struct ofpact_ed_prop *, ptr);
+ if (prop_ptr->prop_class == OFPPPC_NSH) {
+ switch (prop_ptr->type) {
+ case OFPPPT_PROP_NSH_MDTYPE: {
+ struct ofpact_ed_prop_nsh_md_type *prop_md_type =
+ ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *,
+ prop_ptr);
+ md_type = prop_md_type->md_type;
+ break;
+ }
+ case OFPPPT_PROP_NSH_TLV: {
+ struct ofpact_ed_prop_nsh_tlv *tlv_prop =
+ ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *,
+ prop_ptr);
+ struct nsh_md2_tlv *md2_ctx =
+ ofpbuf_put_uninit(buf, sizeof(*md2_ctx));
+ md2_ctx->md_class = tlv_prop->tlv_class;
+ md2_ctx->type = tlv_prop->tlv_type;
+ md2_ctx->length = tlv_prop->tlv_len;
+ size_t len = ROUND_UP(md2_ctx->length, 4);
+ size_t padding = len - md2_ctx->length;
+ ofpbuf_put(buf, tlv_prop->data, md2_ctx->length);
+ ofpbuf_put_zeros(buf, padding);
+ break;
+ }
+ default:
+ /* No other NSH encap properties defined yet. */
+ break;
+ }
+ }
+ ptr += ROUND_UP(prop_ptr->len, 8);
+ }
+ if (buf->size == 0 || buf->size > OVS_ENCAP_NSH_MAX_MD_LEN) {
+ ofpbuf_delete(buf);
+ buf = NULL;
+ }
+
+ /* Determine the Next Protocol field for NSH header. */
+ switch (ntohl(packet_type)) {
+ case PT_ETH:
+ np = NSH_P_ETHERNET;
+ break;
+ case PT_IPV4:
+ np = NSH_P_IPV4;
+ break;
+ case PT_IPV6:
+ np = NSH_P_IPV6;
+ break;
+ case PT_NSH:
+ np = NSH_P_NSH;
+ break;
+ default:
+ /* Error handling: drop packet. */
+ xlate_report_debug(ctx, OFT_ACTION,
+ "Dropping packet as encap(nsh) is not "
+ "supported for packet type (%d,0x%x)",
+ pt_ns(packet_type), pt_ns_type(packet_type));
+ ctx->error = 1;
+ return buf;
+ }
+ /* Note that we have matched on packet_type! */
+ wc->masks.packet_type = OVS_BE32_MAX;
+
+ /* Reset all current flow packet headers. */
+ memset(&flow->dl_dst, 0,
+ sizeof(struct flow) - offsetof(struct flow, dl_dst));
+
+ /* Populate the flow with the new NSH header. */
+ flow->packet_type = htonl(PT_NSH);
+ flow->dl_type = htons(ETH_TYPE_NSH);
+ flow->nsh.flags = 0; /* */
+ flow->nsh.np = np;
+ flow->nsh.spi = 0;
+ flow->nsh.si = 255;
+
+ if (md_type == NSH_M_TYPE1) {
+ flow->nsh.mdtype = NSH_M_TYPE1;
+ memset(flow->nsh.c, 0, sizeof flow->nsh.c);
+ if (buf) {
+ /* Drop any MD2 context TLVs. */
+ ofpbuf_delete(buf);
+ buf = NULL;
+ }
+ } else if (md_type == NSH_M_TYPE2) {
+ flow->nsh.mdtype = NSH_M_TYPE2;
+ }
+
+ return buf;
+}
+
static void
xlate_generic_encap_action(struct xlate_ctx *ctx,
const struct ofpact_encap *encap)