@@ -756,6 +756,23 @@ struct ovs_action_push_eth {
#endif
};
+#define OVS_ENDECAP_MAX_PROPS_LEN 256
+/*
+ * struct ovs_action_endecap - %OVS_ACTION_ATTR_ENCAP, OVS_ACTION_ATTR_DECAP
+ * @ns: packet type name space.
+ * @type: packet type.
+ * @hdr_size: size of encap or decap header.
+ * @props_len: length of encap or decap properties.
+ * @props: encap or decap properties.
+ */
+struct ovs_action_endecap {
+ uint16_t ns;
+ uint16_t type;
+ uint16_t hdr_size;
+ uint16_t props_len;
+ uint8_t props[OVS_ENDECAP_MAX_PROPS_LEN];
+};
+
/**
* enum ovs_nat_attr - Attributes for %OVS_CT_ATTR_NAT.
*
@@ -831,6 +848,10 @@ enum ovs_nat_attr {
* @OVS_ACTION_ATTR_PUSH_ETH: Push a new outermost Ethernet header onto the
* packet.
* @OVS_ACTION_ATTR_POP_ETH: Pop the outermost Ethernet header off the packet.
+ * @OVS_ACTION_ATTR_ENCAP: Generic encap action to push generic header, such
+ * as NSH header, Ethernet header, etc.
+ * @OVS_ACTION_ATTR_DECAP: Generic decap action to remove generic header, such
+ * as NSH header, Ethernet header, etc.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -866,6 +887,8 @@ enum ovs_action_attr {
OVS_ACTION_ATTR_TRUNC, /* u32 struct ovs_action_trunc. */
OVS_ACTION_ATTR_PUSH_ETH, /* struct ovs_action_push_eth. */
OVS_ACTION_ATTR_POP_ETH, /* No argument. */
+ OVS_ACTION_ATTR_ENCAP, /* struct ovs_action_endecap. */
+ OVS_ACTION_ATTR_DECAP, /* struct ovs_action_endecap. */
#ifndef __KERNEL__
OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/
@@ -12,6 +12,7 @@ openvswitchinclude_HEADERS = \
include/openvswitch/meta-flow.h \
include/openvswitch/ofpbuf.h \
include/openvswitch/ofp-actions.h \
+ include/openvswitch/ofp-ed-props.h \
include/openvswitch/ofp-errors.h \
include/openvswitch/ofp-msgs.h \
include/openvswitch/ofp-parse.h \
@@ -25,6 +25,7 @@
#include "openvswitch/ofp-util.h"
#include "openvswitch/ofp-errors.h"
#include "openvswitch/types.h"
+#include "openvswitch/ofp-ed-props.h"
struct vl_mff_map;
@@ -89,6 +90,10 @@ struct vl_mff_map;
OFPACT(PUSH_MPLS, ofpact_push_mpls, ofpact, "push_mpls") \
OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact, "pop_mpls") \
\
+ /* Generic encap & decap */ \
+ OFPACT(ENCAP, ofpact_encap, ofpact, "encap") \
+ OFPACT(DECAP, ofpact_decap, ofpact, "decap") \
+ \
/* Metadata. */ \
OFPACT(SET_TUNNEL, ofpact_tunnel, ofpact, "set_tunnel") \
OFPACT(SET_QUEUE, ofpact_queue, ofpact, "set_queue") \
@@ -969,6 +974,30 @@ struct ofpact_unroll_xlate {
ovs_be64 rule_cookie; /* OVS_BE64_MAX if none. */
};
+/* OFPACT_ENCAP.
+ *
+ * Used for OFPAT_ENCAP. */
+struct ofpact_encap {
+ struct ofpact ofpact;
+ struct ofp_header_type new_pkt_type; /* new header type */
+ uint16_t hdr_size; /* new header size in bytes */
+ uint16_t props_len; /* total length in bytes of props */
+ uint8_t pads[4]; /* aligned to 8 bytes */
+ uint8_t props[0]; /* encap/decap properties */
+};
+
+/* OFPACT_DECAP.
+ *
+ * Used for OFPAT_DECAP. */
+struct ofpact_decap {
+ struct ofpact ofpact;
+ struct ofp_header_type new_pkt_type; /* new header type */
+ uint16_t hdr_size; /* new header size in bytes */
+ uint16_t props_len; /* total length in bytes of props */
+ uint8_t pads[4]; /* aligned to 8 bytes */
+ uint8_t props[0]; /* encap/decap properties */
+};
+
/* Converting OpenFlow to ofpacts. */
enum ofperr ofpacts_pull_openflow_actions(struct ofpbuf *openflow,
unsigned int actions_len,
new file mode 100644
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017 Intel, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OPENVSWITCH_OFP_ED_PROPS_H
+#define OPENVSWITCH_OFP_ED_PROPS_H 1
+
+#include "openvswitch/ofp-errors.h"
+#include "openvswitch/types.h"
+#include "openvswitch/ofpbuf.h"
+
+enum ofp_ed_prop_class {
+ OFPPPC_BASIC = 0, /* ONF Basic class */
+ OFPPPC_MPLS = 1, /* MPLS property class */
+ OFPPPC_GRE = 2, /* GRE property class */
+ OFPPPC_GTP = 3, /* GTP property class */
+ OFPPPC_NSH = 4, /* NSH property class */
+ /* new values go here */
+ OFPPPC_EXPERIMENTER=0xffff, /* experimenter property class
+ * first 32 bits of property data is exp
+ * id after that is the experimenter
+ * property data
+ */
+};
+
+enum ofp_ed_nsh_prop_type {
+ OFPPPT_PROP_NSH_NONE = 0, /* unused */
+ OFPPPT_PROP_NSH_MDTYPE = 1, /* property MDTYPE in NSH */
+ OFPPPT_PROP_NSH_TLV = 2, /* property TLV in NSH */
+ /* new values go here */
+};
+
+struct ofp_header_type {
+ uint16_t ns;
+ uint16_t type;
+};
+
+struct ofp_ed_prop_header {
+ uint16_t prop_class;
+ uint8_t type;
+ uint8_t len;
+};
+
+struct ofp_ed_prop_nsh_md_type {
+ ovs_be16 prop_class; /* encap/decap property class NSH */
+ uint8_t type; /* encap/decap property type MDTYPE */
+ uint8_t len; /* property length = 8 */
+ uint8_t md_type; /* NSH MD type */
+ uint8_t pad[3]; /* Padding to 8 bytes */
+};
+
+struct ofp_ed_prop_nsh_tlv {
+ ovs_be16 prop_class; /* encap/decap property class NSH */
+ uint8_t type; /* encap/decap property type TLV */
+ uint8_t len; /* property length = 8 + tlv_len + padding */
+ ovs_be16 tlv_class; /* Metadata class */
+ uint8_t tlv_type; /* Metadata type including C bit */
+ uint8_t tlv_len; /* Metadata value length (0-127) */
+ uint8_t data[0]; /* tlv_len octets of metadata value,
+ * padded to a multiple of 4 bytes
+ */
+};
+
+enum ofperr ed_prop_ntohs(struct ofp_ed_prop_header * props, uint16_t length);
+enum ofperr ed_prop_htons(struct ofp_ed_prop_header * props, uint16_t length);
+struct ofp_header_type get_encap_header_type(const char * type);
+uint16_t get_ed_prop_class(const char * prop_class_name);
+uint8_t get_ed_prop_type(uint16_t prop_class, const char * prop_type_name);
+char * parse_and_put_ed_prop(char ** arg, struct ofpbuf *ofpacts, uint16_t * props_len);
+char * get_ed_pkt_type(const struct ofp_header_type * pkt_type);
+char * get_ed_prop_class_name(const struct ofp_ed_prop_header * prop_header);
+char * get_ed_prop_type_name(const struct ofp_ed_prop_header * prop_header);
+void format_ed_props(const struct ofp_ed_prop_header *props, const uint16_t props_len, struct ds *s);
+
+#endif /* ofp-ed-props.h */
@@ -149,6 +149,7 @@ lib_libopenvswitch_la_SOURCES = \
lib/odp-util.c \
lib/odp-util.h \
lib/ofp-actions.c \
+ lib/ofp-ed-props.c \
lib/ofp-errors.c \
lib/ofp-msgs.c \
lib/ofp-parse.c \
@@ -5175,6 +5175,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
case OVS_ACTION_ATTR_PUSH_ETH:
case OVS_ACTION_ATTR_POP_ETH:
case OVS_ACTION_ATTR_CLONE:
+ case OVS_ACTION_ATTR_ENCAP:
+ case OVS_ACTION_ATTR_DECAP:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
}
@@ -1224,6 +1224,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
case OVS_ACTION_ATTR_PUSH_ETH:
case OVS_ACTION_ATTR_POP_ETH:
case OVS_ACTION_ATTR_CLONE:
+ case OVS_ACTION_ATTR_ENCAP:
+ case OVS_ACTION_ATTR_DECAP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
@@ -615,6 +615,8 @@ requires_datapath_assistance(const struct nlattr *a)
case OVS_ACTION_ATTR_PUSH_ETH:
case OVS_ACTION_ATTR_POP_ETH:
case OVS_ACTION_ATTR_CLONE:
+ case OVS_ACTION_ATTR_ENCAP:
+ case OVS_ACTION_ATTR_DECAP:
return false;
case OVS_ACTION_ATTR_UNSPEC:
@@ -772,6 +774,13 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
}
break;
+ case OVS_ACTION_ATTR_ENCAP:
+ /* TODO */
+ break;
+ case OVS_ACTION_ATTR_DECAP:
+ /* TODO */
+ break;
+
case OVS_ACTION_ATTR_OUTPUT:
case OVS_ACTION_ATTR_TUNNEL_PUSH:
case OVS_ACTION_ATTR_TUNNEL_POP:
@@ -128,6 +128,8 @@ odp_action_len(uint16_t type)
case OVS_ACTION_ATTR_PUSH_ETH: return sizeof(struct ovs_action_push_eth);
case OVS_ACTION_ATTR_POP_ETH: return 0;
case OVS_ACTION_ATTR_CLONE: return ATTR_LEN_VARIABLE;
+ case OVS_ACTION_ATTR_ENCAP: return ATTR_LEN_VARIABLE;
+ case OVS_ACTION_ATTR_DECAP: return ATTR_LEN_VARIABLE;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
@@ -911,6 +913,12 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
case OVS_ACTION_ATTR_CLONE:
format_odp_clone_action(ds, a);
break;
+ case OVS_ACTION_ATTR_ENCAP:
+ /* TODO */
+ break;
+ case OVS_ACTION_ATTR_DECAP:
+ /* TODO */
+ break;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
@@ -255,6 +255,12 @@ enum ofp_raw_action_type {
/* NX1.0-1.4(6): struct nx_action_reg_move, ... VLMFF */
NXAST_RAW_REG_MOVE,
+ /* OF1.3+(29): struct ofp_action_encap, ... */
+ OFPAT_RAW13_ENCAP,
+
+ /* OF1.3+(30): struct ofp_action_decap, ... */
+ OFPAT_RAW13_DECAP,
+
/* ## ------------------------- ## */
/* ## Nicira extension actions. ## */
/* ## ------------------------- ## */
@@ -471,6 +477,8 @@ ofpact_next_flattened(const struct ofpact *ofpact)
case OFPACT_WRITE_METADATA:
case OFPACT_GOTO_TABLE:
case OFPACT_NAT:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
return ofpact_next(ofpact);
case OFPACT_CLONE:
@@ -3881,6 +3889,203 @@ format_FIN_TIMEOUT(const struct ofpact_fin_timeout *a, struct ds *s)
ds_chomp(s, ',');
ds_put_format(s, "%s)%s", colors.paren, colors.end);
}
+
+/* Action structure for OFPAT_ENCAP */
+struct ofp_action_encap {
+ ovs_be16 type; /* OFPAT_ENCAP */
+ ovs_be16 len; /* Total size including any property TLVs */
+ struct ofp_header_type new_pkt_type;
+ /* Header type to add and PACKET_TYPE of result */
+ ovs_be16 hdr_size; /* (optional) Header size in bytes to add,
+ 0=not specified*/
+ uint8_t pad[6]; /* Align to 64bits. */
+ struct ofp_ed_prop_header props[0];
+ /* encap/decap properties */
+};
+OFP_ASSERT(sizeof(struct ofp_action_encap) == 16);
+
+static enum ofperr
+decode_OFPAT_RAW13_ENCAP(const struct ofp_action_encap *oae,
+ enum ofp_version ofp_version OVS_UNUSED,
+ struct ofpbuf *ofpacts)
+{
+ struct ofpact_encap * encap;
+ uint16_t length;
+ struct ofp_ed_prop_header * props = NULL;
+
+ encap = ofpact_put_ENCAP(ofpacts);
+ encap->ofpact.raw = OFPAT_RAW13_ENCAP;
+ encap->new_pkt_type.ns = ntohs(oae->new_pkt_type.ns);
+ encap->new_pkt_type.type = ntohs(oae->new_pkt_type.type);
+ encap->hdr_size = ntohs(oae->hdr_size);
+
+ length = ntohs(oae->len) - offsetof(struct ofp_action_encap, props);
+ encap->props_len = length;
+ if (length > 0) {
+ props = ofpbuf_put(ofpacts, oae->props, length);
+ ed_prop_ntohs(props, length);
+ }
+ encap = ofpacts->header;
+ ofpact_finish_ENCAP(ofpacts, &encap);
+ return 0;
+}
+
+static void
+encode_ENCAP(const struct ofpact_encap *encap,
+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
+{
+ size_t start_ofs = out->size;
+ struct ofp_action_encap *oae = put_OFPAT13_ENCAP(out);
+ struct ofp_ed_prop_header * props = NULL;
+
+ oae->new_pkt_type.ns = htons(encap->new_pkt_type.ns);
+ oae->new_pkt_type.type = htons(encap->new_pkt_type.type);
+ oae->hdr_size = htons(encap->hdr_size);
+ if (encap->props_len > 0) {
+ props = ofpbuf_put(out, encap->props, encap->props_len);
+ ed_prop_htons(props, encap->props_len);
+ }
+ pad_ofpat(out, start_ofs);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_ENCAP(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ struct ofpact_encap * encap;
+ char *key, *value;
+ char *error = NULL;
+ uint16_t props_len;
+
+ encap = ofpact_put_ENCAP(ofpacts);
+
+ /* Parse encap type */
+ if (!ofputil_parse_key_value(&arg, &key, &value)) {
+ return xasprintf("Invalid encap arguments: %s", arg);
+ }
+ struct ofp_header_type header_type = get_encap_header_type(key);
+ encap->new_pkt_type.ns = header_type.ns;
+ encap->new_pkt_type.type = header_type.type;
+
+ error = parse_and_put_ed_prop(&arg, ofpacts, &props_len);
+ if (error != NULL) {
+ return error;
+ }
+ encap = ofpacts->header;
+ encap->props_len = props_len;
+ ofpact_finish_ENCAP(ofpacts, &encap);
+ return NULL;
+}
+
+static void
+format_ENCAP(const struct ofpact_encap *a, struct ds *s)
+{
+ struct ofp_ed_prop_header * prop_hdr = (struct ofp_ed_prop_header *)a->props;
+
+ ds_put_format(s, "%sencap(%s", colors.paren, colors.end);
+ ds_put_format(s, "%s", get_ed_pkt_type(&a->new_pkt_type));
+ format_ed_props(prop_hdr, a->props_len, s);
+ ds_put_format(s, "%s)%s", colors.paren, colors.end);
+}
+
+/* Action structure for OFPAT_DECAP */
+struct ofp_action_decap {
+ ovs_be16 type; /* OFPAT_DECAP */
+ ovs_be16 len; /* Total size including any property TLVs */
+ struct ofp_header_type new_pkt_type;
+ /* Header type to add and PACKET_TYPE of result */
+ ovs_be16 hdr_size; /* (optional) Header size in bytes to add,
+ 0=not specified*/
+ uint8_t pad[6]; /* Align to 64bits. */
+ struct ofp_ed_prop_header props[0];
+ /* encap/decap properties */
+};
+OFP_ASSERT(sizeof(struct ofp_action_decap) == 16);
+
+static enum ofperr
+decode_OFPAT_RAW13_DECAP(const struct ofp_action_decap *oad,
+ enum ofp_version ofp_version OVS_UNUSED,
+ struct ofpbuf *ofpacts)
+{
+ struct ofpact_decap * decap;
+ uint16_t length;
+ struct ofp_ed_prop_header * props = NULL;
+
+ decap = ofpact_put_DECAP(ofpacts);
+ decap->ofpact.raw = OFPAT_RAW13_DECAP;
+ decap->new_pkt_type.ns = ntohs(oad->new_pkt_type.ns);
+ decap->new_pkt_type.type = ntohs(oad->new_pkt_type.type);
+ decap->hdr_size = ntohs(oad->hdr_size);
+
+ length = ntohs(oad->len) - offsetof(struct ofp_action_decap, props);
+ decap->props_len = length;
+ if (length > 0) {
+ props = ofpbuf_put(ofpacts, oad->props, length);
+ ed_prop_ntohs(props, length);
+ }
+ decap = ofpacts->header;
+ ofpact_finish_DECAP(ofpacts, &decap);
+ return 0;
+}
+
+static void
+encode_DECAP(const struct ofpact_decap *decap,
+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
+{
+ size_t start_ofs = out->size;
+ struct ofp_action_decap *oad = put_OFPAT13_DECAP(out);
+ struct ofp_ed_prop_header * props = NULL;
+
+ oad->new_pkt_type.ns = htons(decap->new_pkt_type.ns);
+ oad->new_pkt_type.type = htons(decap->new_pkt_type.type);
+ oad->hdr_size = htons(decap->hdr_size);
+ if (decap->props_len > 0) {
+ props = ofpbuf_put(out, decap->props, decap->props_len);
+ ed_prop_htons(props, decap->props_len);
+ }
+ pad_ofpat(out, start_ofs);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_DECAP(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ struct ofpact_decap * decap;
+ char *key, *value;
+ char *error = NULL;
+ uint16_t props_len;
+
+ decap = ofpact_put_DECAP(ofpacts);
+
+ /* Parse decap type */
+ if (!ofputil_parse_key_value(&arg, &key, &value)) {
+ return xasprintf("Invalid decap arguments: %s", arg);
+ }
+ struct ofp_header_type header_type = get_encap_header_type(key);
+ decap->new_pkt_type.ns = header_type.ns;
+ decap->new_pkt_type.type = header_type.type;
+
+ error = parse_and_put_ed_prop(&arg, ofpacts, &props_len);
+ if (error != NULL) {
+ return error;
+ }
+ decap = ofpacts->header;
+ decap->props_len = props_len;
+ ofpact_finish_DECAP(ofpacts, &decap);
+ return NULL;
+}
+
+static void
+format_DECAP(const struct ofpact_decap *a, struct ds *s)
+{
+ struct ofp_ed_prop_header * prop_hdr = (struct ofp_ed_prop_header *)a->props;
+
+ ds_put_format(s, "%sdecap(%s", colors.paren, colors.end);
+ ds_put_format(s, "%s", get_ed_pkt_type(&a->new_pkt_type));
+ format_ed_props(prop_hdr, a->props_len, s);
+ ds_put_format(s, "%s)%s", colors.paren, colors.end);
+}
+
/* Action structures for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE, and
* NXAST_RESUBMIT_TABLE_CT.
@@ -6590,6 +6795,8 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
case OFPACT_SET_TUNNEL:
case OFPACT_SET_VLAN_PCP:
case OFPACT_SET_VLAN_VID:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
return true;
case OFPACT_BUNDLE:
case OFPACT_CLEAR_ACTIONS:
@@ -6665,6 +6872,8 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
case OFPACT_SET_VLAN_PCP:
case OFPACT_SET_VLAN_VID:
case OFPACT_STRIP_VLAN:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
return true;
/* In general these actions are excluded because they are not part of
@@ -6772,6 +6981,8 @@ ofpacts_execute_action_set(struct ofpbuf *action_list,
/* The OpenFlow spec "Action Set" section specifies this order. */
ofpacts_copy_last(action_list, action_set, OFPACT_STRIP_VLAN);
ofpacts_copy_last(action_list, action_set, OFPACT_POP_MPLS);
+ ofpacts_copy_last(action_list, action_set, OFPACT_DECAP);
+ ofpacts_copy_last(action_list, action_set, OFPACT_ENCAP);
ofpacts_copy_last(action_list, action_set, OFPACT_PUSH_MPLS);
ofpacts_copy_last(action_list, action_set, OFPACT_PUSH_VLAN);
ofpacts_copy_last(action_list, action_set, OFPACT_DEC_TTL);
@@ -6915,6 +7126,8 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
case OFPACT_CT:
case OFPACT_CT_CLEAR:
case OFPACT_NAT:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
default:
return OVSINST_OFPIT11_APPLY_ACTIONS;
}
@@ -7573,6 +7786,10 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
case OFPACT_DEBUG_RECIRC:
return 0;
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
+ return 0;
+
default:
OVS_NOT_REACHED();
}
@@ -8064,6 +8281,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
case OFPACT_CT:
case OFPACT_CT_CLEAR:
case OFPACT_NAT:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
default:
return false;
}
new file mode 100644
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2017 Intel, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <arpa/inet.h>
+#include "openvswitch/ofp-ed-props.h"
+#include "openvswitch/ofp-util.h"
+#include "openvswitch/ofpbuf.h"
+#include "openvswitch/ofp-parse.h"
+#include "util.h"
+
+enum ofperr
+ed_prop_ntohs(struct ofp_ed_prop_header * props, uint16_t length)
+{
+ char * ptr = (char *)props;
+ while (length > sizeof(struct ofp_ed_prop_header)) {
+ uint16_t prop_class = ntohs(props->prop_class);
+ switch(prop_class) {
+ case OFPPPC_NSH:
+ switch(props->type) {
+ case OFPPPT_PROP_NSH_MDTYPE: {
+ props->prop_class = prop_class;
+ ptr += sizeof(struct ofp_ed_prop_nsh_md_type);
+ length -= sizeof(struct ofp_ed_prop_nsh_md_type);
+ break;
+ case OFPPPT_PROP_NSH_TLV: {
+ struct ofp_ed_prop_nsh_tlv * prop_nsh_tlv = (struct ofp_ed_prop_nsh_tlv *)props;
+ props->prop_class = prop_class;
+ prop_nsh_tlv->tlv_class = ntohs(prop_nsh_tlv->tlv_class);
+ ptr += sizeof(struct ofp_ed_prop_nsh_tlv) + prop_nsh_tlv->tlv_len;
+ length -= sizeof(struct ofp_ed_prop_nsh_tlv) + prop_nsh_tlv->tlv_len;
+ break;
+ }
+ default:
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ props = (struct ofp_ed_prop_header *)ptr;
+ break;
+ }
+ default:
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ }
+ return 0;
+}
+
+enum ofperr
+ed_prop_htons(struct ofp_ed_prop_header * props, uint16_t length)
+{
+ char * ptr = (char *)props;
+ while (length > sizeof(struct ofp_ed_prop_header)) {
+ uint16_t prop_class = props->prop_class;
+ switch(prop_class) {
+ case OFPPPC_NSH:
+ switch(props->type) {
+ case OFPPPT_PROP_NSH_MDTYPE: {
+ props->prop_class = htons(prop_class);
+ ptr += sizeof(struct ofp_ed_prop_nsh_md_type);
+ length -= sizeof(struct ofp_ed_prop_nsh_md_type);
+ break;
+ case OFPPPT_PROP_NSH_TLV: {
+ struct ofp_ed_prop_nsh_tlv * prop_nsh_tlv = (struct ofp_ed_prop_nsh_tlv *)props;
+ props->prop_class = htons(prop_class);
+ prop_nsh_tlv->tlv_class = htons(prop_nsh_tlv->tlv_class);
+ ptr += sizeof(struct ofp_ed_prop_nsh_tlv) + prop_nsh_tlv->tlv_len;
+ length -= sizeof(struct ofp_ed_prop_nsh_tlv) + prop_nsh_tlv->tlv_len;
+ break;
+ }
+ default:
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ props = (struct ofp_ed_prop_header *)ptr;
+ break;
+ }
+ default:
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ }
+ return 0;
+}
+
+struct ofp_header_type get_encap_header_type(const char * type)
+{
+ struct ofp_header_type header_type;
+ if (strcmp(type, "nsh") == 0) {
+ header_type.ns = OFPHTN_ETHERTYPE;
+ header_type.type = 0x894f;
+ } else {
+ header_type.ns = OFPHTN_ONF;
+ header_type.type = 0;
+ }
+ return header_type;
+}
+
+uint16_t
+get_ed_prop_class(const char * prop_class_name)
+{
+ if (strcmp(prop_class_name, "nsh") == 0) {
+ return OFPPPC_NSH;
+ } else {
+ return 0;
+ }
+}
+
+uint8_t
+get_ed_prop_type(uint16_t prop_class, const char * prop_type_name)
+{
+ switch(prop_class) {
+ case OFPPPC_NSH:
+ if (strcmp(prop_type_name, "md_type") == 0) {
+ return OFPPPT_PROP_NSH_MDTYPE;
+ } else if (strcmp(prop_type_name, "tlv_hdr") == 0) {
+ return OFPPPT_PROP_NSH_TLV;
+ } else {
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+char * parse_and_put_ed_prop(char ** arg, struct ofpbuf *ofpacts, uint16_t * props_len)
+{
+ char * error = NULL;
+ char *key, *value;
+ uint16_t length = 0;
+
+ while (true) {
+ *arg += strspn(*arg, ", \t\r\n{}");
+ if (**arg == '\0') {
+ break;
+ }
+
+ /* Get property class */
+ if (!ofputil_parse_key_value(arg, &key, &value)) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+ uint16_t prop_class = get_ed_prop_class(key);
+ if (prop_class == OFPPPC_BASIC) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+
+ /* Get property type */
+ if (!ofputil_parse_key_value(arg, &key, &value)) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+
+ uint8_t prop_type = get_ed_prop_type(prop_class, key);
+ if (prop_type == OFPPPT_PROP_NSH_NONE) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+
+ switch(prop_class) {
+ case OFPPPC_NSH:
+ switch(prop_type) {
+ case OFPPPT_PROP_NSH_MDTYPE: {
+ uint8_t md_type;
+ if (value == NULL) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+ error = str_to_u8(value, "md_type", &md_type);
+ if (error != NULL) {
+ return error;
+ }
+ struct ofp_ed_prop_nsh_md_type * prop_nsh_md_type
+ = ofpbuf_put_uninit(ofpacts, sizeof(struct ofp_ed_prop_nsh_md_type));
+ prop_nsh_md_type->prop_class = prop_class;
+ prop_nsh_md_type->type = prop_type;
+ prop_nsh_md_type->len = sizeof(struct ofp_ed_prop_nsh_md_type);
+ prop_nsh_md_type->md_type = md_type;
+ length += sizeof(struct ofp_ed_prop_nsh_md_type);
+ break;
+ }
+ case OFPPPT_PROP_NSH_TLV: {
+ uint16_t tlv_hdr;
+ size_t tlv_value_len;
+ if (value == NULL) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+ error = str_to_u16(value, "tlv_hdr", &tlv_hdr);
+ if (error != NULL) {
+ return error;
+ }
+ struct ofp_ed_prop_nsh_tlv * prop_nsh_tlv
+ = ofpbuf_put_uninit(ofpacts, sizeof(struct ofp_ed_prop_nsh_tlv));
+ prop_nsh_tlv->prop_class = prop_class;
+ prop_nsh_tlv->type = prop_type;
+ prop_nsh_tlv->tlv_class = tlv_hdr;
+
+ /* Get NSH TLV: tlv_type */
+ if (!ofputil_parse_key_value(arg, &key, &value)) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+ uint8_t tlv_type;
+ error = str_to_u8(key, "tlv_type", &tlv_type);
+ if (error != NULL) {
+ return error;
+ }
+ prop_nsh_tlv->tlv_type = tlv_type;
+
+ /* Get NSH TLV: tlv_len */
+ if (!ofputil_parse_key_value(arg, &key, &value)) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+ uint8_t tlv_len;
+ error = str_to_u8(key, "tlv_len", &tlv_len);
+ if (error != NULL) {
+ return error;
+ }
+ prop_nsh_tlv->tlv_len = tlv_len;
+
+ /* Get NSH TLV: value */
+ if (!ofputil_parse_key_value(arg, &key, &value)) {
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+
+ ofpbuf_put_hex(ofpacts, key + 2, &tlv_value_len);
+ prop_nsh_tlv->len = sizeof(struct ofp_ed_prop_nsh_tlv) + tlv_value_len;
+ length += sizeof(struct ofp_ed_prop_nsh_tlv) + tlv_value_len;
+ break;
+ }
+ default:
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+ break;
+ default:
+ return xasprintf("Invalid encap arguments: %s", *arg);
+ }
+ }
+ if (props_len != NULL) {
+ *props_len = length;
+ }
+ return NULL;
+}
+
+char *
+get_ed_pkt_type(const struct ofp_header_type * pkt_type)
+{
+ if ((pkt_type->ns == OFPHTN_ETHERTYPE)
+ && (pkt_type->type == 0x894f)) {
+ return "nsh";
+ } else {
+ /* TODO */
+ return NULL;
+ }
+}
+
+char *
+get_ed_prop_class_name(const struct ofp_ed_prop_header * prop_header)
+{
+ switch(prop_header->prop_class) {
+ case OFPPPC_NSH:
+ return "nsh";
+ default:
+ return NULL;
+ }
+}
+
+char *
+get_ed_prop_type_name(const struct ofp_ed_prop_header * prop_header)
+{
+ switch(prop_header->prop_class) {
+ case OFPPPC_NSH:
+ switch(prop_header->type) {
+ case OFPPPT_PROP_NSH_MDTYPE:
+ return "md_type";
+ case OFPPPT_PROP_NSH_TLV:
+ return "tlv_hdr";
+ default:
+ return NULL;
+ }
+ break;
+ default:
+ return NULL;
+ }
+}
+
+void
+format_ed_props(const struct ofp_ed_prop_header *props, const uint16_t props_len, struct ds *s)
+{
+ struct ofp_ed_prop_header * prop_hdr = NULL;
+ size_t ofs = 0;
+ const uint8_t * ptr = (uint8_t *)props;
+
+ while (ofs + sizeof(struct ofp_ed_prop_header) < props_len) {
+ prop_hdr = (struct ofp_ed_prop_header *)ptr;
+ ds_put_format(s, ",{%s,", get_ed_prop_class_name(prop_hdr));
+ ds_put_format(s, "%s:", get_ed_prop_type_name(prop_hdr));
+ switch(prop_hdr->prop_class) {
+ case OFPPPC_NSH:
+ switch(prop_hdr->type) {
+ case OFPPPT_PROP_NSH_MDTYPE: {
+ struct ofp_ed_prop_nsh_md_type * prop_nsh_md_type = (struct ofp_ed_prop_nsh_md_type *)prop_hdr;
+ ds_put_format(s, "%d}", prop_nsh_md_type->md_type);
+ ofs += sizeof(struct ofp_ed_prop_nsh_md_type);
+ ptr += sizeof(struct ofp_ed_prop_nsh_md_type);
+ break;
+ }
+ case OFPPPT_PROP_NSH_TLV: {
+ struct ofp_ed_prop_nsh_tlv * tlv = (struct ofp_ed_prop_nsh_tlv *)prop_hdr;
+ ds_put_format(s, "0x%04x,", tlv->tlv_class);
+ ds_put_format(s, "%d,%d,0x", tlv->tlv_type, tlv->tlv_len);
+ for (uint8_t i = 0; i < tlv->tlv_len; i++) {
+ ds_put_format(s, "%02x", tlv->data[i]);
+ }
+ ds_put_char(s, '}');
+ ofs += sizeof(struct ofp_ed_prop_nsh_tlv) + tlv->tlv_len;
+ ptr += sizeof(struct ofp_ed_prop_nsh_tlv) + tlv->tlv_len;
+ break;
+ }
+ default:
+ ofs += sizeof(struct ofp_ed_prop_header);
+ break;
+ }
+ break;
+ default:
+ ofs += sizeof(struct ofp_ed_prop_header);
+ break;
+ }
+ }
+}
@@ -7687,7 +7687,7 @@ ofputil_parse_key_value(char **stringp, char **keyp, char **valuep)
* If there is no value, we are done. */
const char *value_delims;
if (key_delim == ':' || key_delim == '=') {
- value_delims = ", \t\r\n";
+ value_delims = ", \t\r\n}";
} else if (key_delim == '(') {
value_delims = ")";
} else {
@@ -1199,6 +1199,8 @@ dpif_sflow_read_actions(const struct flow *flow,
break;
case OVS_ACTION_ATTR_SAMPLE:
case OVS_ACTION_ATTR_CLONE:
+ case OVS_ACTION_ATTR_ENCAP:
+ case OVS_ACTION_ATTR_DECAP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
@@ -4159,6 +4159,8 @@ xlate_fixup_actions(struct ofpbuf *b, const struct nlattr *actions,
case OVS_ACTION_ATTR_CT:
case OVS_ACTION_ATTR_PUSH_ETH:
case OVS_ACTION_ATTR_POP_ETH:
+ case OVS_ACTION_ATTR_ENCAP:
+ case OVS_ACTION_ATTR_DECAP:
case OVS_ACTION_ATTR_METER:
ofpbuf_put(b, a, nl_attr_len_pad(a, left));
break;
@@ -5264,6 +5266,8 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end,
case OFPACT_METER:
case OFPACT_SAMPLE:
case OFPACT_CLONE:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
case OFPACT_DEBUG_RECIRC:
case OFPACT_CT:
case OFPACT_CT_CLEAR:
@@ -5522,6 +5526,8 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
case OFPACT_EXIT:
case OFPACT_SAMPLE:
case OFPACT_CLONE:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
case OFPACT_UNROLL_XLATE:
case OFPACT_CT:
case OFPACT_CT_CLEAR:
@@ -5937,6 +5943,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
xlate_clone(ctx, ofpact_get_CLONE(a));
break;
+ case OFPACT_ENCAP:
+ /* TODO */
+ break;
+
+ case OFPACT_DECAP:
+ /* TODO */
+ break;
+
case OFPACT_CT:
compose_conntrack_action(ctx, ofpact_get_CT(a));
break;
Signed-off-by: Yi Yang <yi.y.yang@intel.com> --- datapath/linux/compat/include/linux/openvswitch.h | 23 ++ include/openvswitch/automake.mk | 1 + include/openvswitch/ofp-actions.h | 29 ++ include/openvswitch/ofp-ed-props.h | 87 ++++++ lib/automake.mk | 1 + lib/dpif-netdev.c | 2 + lib/dpif.c | 2 + lib/odp-execute.c | 9 + lib/odp-util.c | 8 + lib/ofp-actions.c | 219 ++++++++++++++ lib/ofp-ed-props.c | 334 ++++++++++++++++++++++ lib/ofp-util.c | 2 +- ofproto/ofproto-dpif-sflow.c | 2 + ofproto/ofproto-dpif-xlate.c | 14 + 14 files changed, 732 insertions(+), 1 deletion(-) create mode 100644 include/openvswitch/ofp-ed-props.h create mode 100644 lib/ofp-ed-props.c