Signed-off-by: Yi Yang <[email protected]>
---
datapath/linux/compat/include/linux/openvswitch.h | 23 ++++
lib/automake.mk | 2 +-
lib/dpif-netdev.c | 2 +
lib/dpif.c | 2 +
lib/odp-execute.c | 18 ++-
lib/odp-util.c | 154 ++++++++++++++++++++++
lib/packets.c | 48 +++++++
lib/packets.h | 3 +
ofproto/ofproto-dpif-sflow.c | 2 +
ofproto/ofproto-dpif-xlate.c | 97 +++++++++++++-
10 files changed, 344 insertions(+), 7 deletions(-)
diff --git a/datapath/linux/compat/include/linux/openvswitch.h
b/datapath/linux/compat/include/linux/openvswitch.h
index 5a64b38..03b10ff 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -773,6 +773,25 @@ struct ovs_action_endecap {
uint8_t props[OVS_ENDECAP_MAX_PROPS_LEN];
};
+#define OVS_ENCAP_NSH_MAX_MD_LEN 256
+/*
+ * struct ovs_action_encap_nsh - %OVS_ACTION_ATTR_ENCAP_NSH
+ * @flags: NSH header flags.
+ * @length: NSH header length/4.
+ * @md_type: NSH Metadata type.
+ * @next_proto: Inner packet type.
+ * @path_hdr: NSH service path and service index.
+ * @metadata: NSH metadata for MD type 1 or 2
+ */
+struct ovs_action_encap_nsh {
+ uint8_t flags;
+ uint8_t length;
+ uint8_t md_type;
+ uint8_t next_proto;
+ ovs_be32 path_hdr;
+ uint8_t metadata[OVS_ENCAP_NSH_MAX_MD_LEN];
+};
+
/**
* enum ovs_nat_attr - Attributes for %OVS_CT_ATTR_NAT.
*
@@ -852,6 +871,8 @@ enum ovs_nat_attr {
* as NSH header, Ethernet header, etc.
* @OVS_ACTION_ATTR_DECAP: Generic decap action to remove generic header, such
* as NSH header, Ethernet header, etc.
+ * @OVS_ACTION_ATTR_ENCAP_NSH: encap NSH action to push NSH header.
+ * @OVS_ACTION_ATTR_DECAP_NSH: decap NSH action to remove NSH header.
*
* 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
@@ -889,6 +910,8 @@ enum ovs_action_attr {
OVS_ACTION_ATTR_POP_ETH, /* No argument. */
OVS_ACTION_ATTR_ENCAP, /* struct ovs_action_endecap. */
OVS_ACTION_ATTR_DECAP, /* struct ovs_action_endecap. */
+ OVS_ACTION_ATTR_ENCAP_NSH, /* struct ovs_action_encap_nsh. */
+ OVS_ACTION_ATTR_DECAP_NSH, /* No argument. */
#ifndef __KERNEL__
OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/
diff --git a/lib/automake.mk b/lib/automake.mk
index 39977a6..26a51b6 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -149,7 +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-ed-props.c \
lib/ofp-errors.c \
lib/ofp-msgs.c \
lib/ofp-parse.c \
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index f5fd00c..e3b6862 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -5177,6 +5177,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch
*packets_,
case OVS_ACTION_ATTR_CLONE:
case OVS_ACTION_ATTR_ENCAP:
case OVS_ACTION_ATTR_DECAP:
+ case OVS_ACTION_ATTR_ENCAP_NSH:
+ case OVS_ACTION_ATTR_DECAP_NSH:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
}
diff --git a/lib/dpif.c b/lib/dpif.c
index fa0f617..3febf29 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1226,6 +1226,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch
*packets_,
case OVS_ACTION_ATTR_CLONE:
case OVS_ACTION_ATTR_ENCAP:
case OVS_ACTION_ATTR_DECAP:
+ case OVS_ACTION_ATTR_ENCAP_NSH:
+ case OVS_ACTION_ATTR_DECAP_NSH:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 4df1f0c..af6407d 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -617,6 +617,8 @@ requires_datapath_assistance(const struct nlattr *a)
case OVS_ACTION_ATTR_CLONE:
case OVS_ACTION_ATTR_ENCAP:
case OVS_ACTION_ATTR_DECAP:
+ case OVS_ACTION_ATTR_ENCAP_NSH:
+ case OVS_ACTION_ATTR_DECAP_NSH:
return false;
case OVS_ACTION_ATTR_UNSPEC:
@@ -774,11 +776,17 @@ odp_execute_actions(void *dp, struct dp_packet_batch
*batch, bool steal,
}
break;
- case OVS_ACTION_ATTR_ENCAP:
- /* TODO */
+ case OVS_ACTION_ATTR_ENCAP_NSH: {
+ const struct ovs_action_encap_nsh *oaen = nl_attr_get(a);
+ DP_PACKET_BATCH_FOR_EACH (packet, batch) {
+ encap_nsh(packet, oaen);
+ }
break;
- case OVS_ACTION_ATTR_DECAP:
- /* TODO */
+ }
+ case OVS_ACTION_ATTR_DECAP_NSH:
+ DP_PACKET_BATCH_FOR_EACH (packet, batch) {
+ decap_nsh(packet);
+ }
break;
case OVS_ACTION_ATTR_OUTPUT:
@@ -787,6 +795,8 @@ odp_execute_actions(void *dp, struct dp_packet_batch
*batch, bool steal,
case OVS_ACTION_ATTR_USERSPACE:
case OVS_ACTION_ATTR_RECIRC:
case OVS_ACTION_ATTR_CT:
+ case OVS_ACTION_ATTR_ENCAP:
+ case OVS_ACTION_ATTR_DECAP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 6da7d78..7389e85 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -130,6 +130,8 @@ odp_action_len(uint16_t type)
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_ENCAP_NSH: return ATTR_LEN_VARIABLE;
+ case OVS_ACTION_ATTR_DECAP_NSH: return 0;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
@@ -247,6 +249,46 @@ format_odp_clone_action(struct ds *ds, const struct nlattr
*attr)
ds_put_format(ds, ")");
}
+static void
+format_nsh_header(struct ds *ds, const struct nsh_hdr * nsh_header)
+{
+ uint8_t flags = (nsh_header->base.version << 6) &
+ (nsh_header->base.oam_flag << 5) &
+ (nsh_header->base.context_flag << 4) &
+ nsh_header->base.reserved_flags1;
+ ds_put_format(ds, "flags=%d", flags);
+ ds_put_format(ds, ",mdtype=%d", nsh_header->base.md_type);
+ ds_put_format(ds, ",np=%d", nsh_header->base.next_proto);
+ ds_put_format(ds, ",spi=%d", ntohl(nsh_header->base.path_hdr << 8));
+ ds_put_format(ds, ",si=%d", nsh_header->base.svc_idx);
+
+ if (nsh_header->base.md_type == NSH_M_TYPE1) {
+ const struct nsh_md1_ctx *md1_ctx = nsh_md1_ctx(nsh_header);
+ ds_put_format(ds, ",c1=0x%08x", ntohl(md1_ctx->c1));
+ ds_put_format(ds, ",c2=0x%08x", ntohl(md1_ctx->c2));
+ ds_put_format(ds, ",c3=0x%08x", ntohl(md1_ctx->c3));
+ ds_put_format(ds, ",c4=0x%08x", ntohl(md1_ctx->c4));
+ } else if (nsh_header->base.md_type == NSH_M_TYPE2) {
+ /* TODO */
+ }
+}
+
+static void
+format_odp_encap_nsh_action(struct ds *ds, const struct nlattr *attr)
+{
+ if (nl_attr_type(attr) != OVS_ACTION_ATTR_ENCAP_NSH) {
+ return;
+ }
+ ds_put_cstr(ds, "encap_nsh(");
+
+ size_t len = nl_attr_get_size(attr);
+ if (len) {
+ const struct nsh_hdr * nsh_header = (struct nsh_hdr
*)nl_attr_get(attr);
+ format_nsh_header(ds, nsh_header);
+ }
+ ds_put_format(ds, ")");
+}
+
static const char *
slow_path_reason_to_string(uint32_t reason)
{
@@ -919,6 +961,12 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
case OVS_ACTION_ATTR_DECAP:
/* TODO */
break;
+ case OVS_ACTION_ATTR_ENCAP_NSH:
+ format_odp_encap_nsh_action(ds, a);
+ break;
+ case OVS_ACTION_ATTR_DECAP_NSH:
+ ds_put_cstr(ds, "decap_nsh()");
+ break;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
@@ -1637,6 +1685,94 @@ find_end:
}
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;
+ struct nsh_hdr * nsh_header = (struct nsh_hdr *)&encap_nsh;
+ uint32_t spi;
+ uint8_t si;
+
+ if (!ovs_scan_len(s, &n, "encap_nsh(")) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* The default is NSH_M_TYPE1 */
+ nsh_header->base.version = 0;
+ nsh_header->base.oam_flag = 0;
+ nsh_header->base.context_flag = 0; //md_type=NSH_M_TYPE1
+ nsh_header->base.length = 6; //md_type=NSH_M_TYPE1
+
+ nsh_header->base.md_type = NSH_M_TYPE1;
+ nsh_header->base.next_proto = NSH_P_ETHERNET;
+ nsh_header->base.path_hdr = htonl(255);
+
+ struct nsh_md1_ctx * md1_ctx = nsh_md1_ctx(nsh_header);
+ md1_ctx->c1 = 0;
+ md1_ctx->c2 = 0;
+ md1_ctx->c3 = 0;
+ md1_ctx->c4 = 0;
+
+ 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.md_type)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "np=%"SCNi8, &encap_nsh.next_proto)) {
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "spi=%"SCNi32, &spi)) {
+ spi = htonl(spi);
+ encap_nsh.path_hdr = encap_nsh.path_hdr & ((spi >> 8) |
0xFF000000);
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "si=%"SCNi8, &si)) {
+ encap_nsh.path_hdr = encap_nsh.path_hdr & ((si << 24) |
0x00FFFFFF);
+ continue;
+ }
+ if (encap_nsh.md_type == NSH_M_TYPE1) {
+ if (ovs_scan_len(s, &n, "c1=0x%"SCNx32, &md1_ctx->c1)) {
+ md1_ctx->c1 = htonl(md1_ctx->c1);
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c2=0x%"SCNx32, &md1_ctx->c2)) {
+ md1_ctx->c2 = htonl(md1_ctx->c2);
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c3=0x%"SCNx32, &md1_ctx->c3)) {
+ md1_ctx->c3 = htonl(md1_ctx->c3);
+ continue;
+ }
+ if (ovs_scan_len(s, &n, "c4=0x%"SCNx32, &md1_ctx->c4)) {
+ md1_ctx->c4 = htonl(md1_ctx->c4);
+ continue;
+ }
+ }
+ else if (encap_nsh.md_type == NSH_M_TYPE2) {
+ /* TODO */
+ continue;
+ }
+ }
+out:
+ if (ret < 0) {
+ return ret;
+ } else {
+ size_t size = nsh_header->base.length << 2;
+ 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)
{
@@ -1838,6 +1974,24 @@ parse_odp_action(const char *s, const struct simap
*port_names,
}
{
+ if (!strncmp(s, "encap_nsh(", 10)) {
+ int retval = parse_odp_encap_nsh_action(s, actions);
+ if (retval < 0) {
+ return retval;
+ }
+ return retval + 1;
+ }
+ }
+
+ {
+ int n;
+ if (ovs_scan(s, "decap_nsh()%n", &n)) {
+ nl_msg_put_flag(actions, OVS_ACTION_ATTR_DECAP_NSH);
+ return n;
+ }
+ }
+
+ {
uint32_t port;
int n;
diff --git a/lib/packets.c b/lib/packets.c
index 9467768..c235b26 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -226,6 +226,54 @@ eth_pop_vlan(struct dp_packet *packet)
}
}
+void
+encap_nsh(struct dp_packet *packet, const struct ovs_action_encap_nsh * oaen) {
+ struct nsh_hdr * nsh_header = (struct nsh_hdr *)oaen;
+ uint16_t length = nsh_header->base.length << 2;
+ uint8_t next_proto = NSH_P_ETHERNET;
+
+ switch(packet->packet_type) {
+ case PT_ETH:
+ next_proto = NSH_P_ETHERNET;
+ break;
+ case PT_IPV4:
+ next_proto = NSH_P_IPV4;
+ break;
+ case PT_IPV6:
+ next_proto = NSH_P_IPV6;
+ break;
+ }
+
+ nsh_header = (struct nsh_hdr *)dp_packet_push_uninit(packet, length);
+ memcpy(nsh_header, oaen, length);
+ nsh_header->base.next_proto = next_proto;
+ packet->packet_type = htonl(PT_NSH);
+}
+
+void
+decap_nsh(struct dp_packet *packet) {
+ if ((packet->l3_ofs == 0) && (packet->packet_type == htonl(PT_NSH))) {
+ struct nsh_hdr * nsh_header = (struct nsh_hdr *)dp_packet_l3(packet);
+ uint8_t next_proto = nsh_header->base.next_proto;
+ enum packet_type next_pt = PT_ETH;
+ switch(next_proto) {
+ case NSH_P_ETHERNET:
+ next_pt = PT_ETH;
+ break;
+ case NSH_P_IPV4:
+ next_pt = PT_IPV4;
+ break;
+ case NSH_P_IPV6:
+ next_pt = PT_IPV6;
+ break;
+ }
+
+ size_t length = nsh_header->base.length << 2;
+ dp_packet_reset_packet(packet, length);
+ packet->packet_type = htonl(next_pt);
+ }
+}
+
/* Push Ethernet header onto 'packet' assuming it is layer 3 */
void
push_eth(struct dp_packet *packet, const struct eth_addr *dst,
diff --git a/lib/packets.h b/lib/packets.h
index 78ea838..8dbf399 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -404,6 +404,9 @@ struct eth_header {
});
BUILD_ASSERT_DECL(ETH_HEADER_LEN == sizeof(struct eth_header));
+void encap_nsh(struct dp_packet *packet, const struct ovs_action_encap_nsh *
encap_nsh);
+void decap_nsh(struct dp_packet *packet);
+
void push_eth(struct dp_packet *packet, const struct eth_addr *dst,
const struct eth_addr *src, ovs_be16 type);
void pop_eth(struct dp_packet *packet);
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 0d4e8f1..a59727c 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1201,6 +1201,8 @@ dpif_sflow_read_actions(const struct flow *flow,
case OVS_ACTION_ATTR_CLONE:
case OVS_ACTION_ATTR_ENCAP:
case OVS_ACTION_ATTR_DECAP:
+ case OVS_ACTION_ATTR_ENCAP_NSH:
+ case OVS_ACTION_ATTR_DECAP_NSH:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index a74e1ac..fd717b0 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -4161,6 +4161,8 @@ xlate_fixup_actions(struct ofpbuf *b, const struct nlattr
*actions,
case OVS_ACTION_ATTR_POP_ETH:
case OVS_ACTION_ATTR_ENCAP:
case OVS_ACTION_ATTR_DECAP:
+ case OVS_ACTION_ATTR_ENCAP_NSH:
+ case OVS_ACTION_ATTR_DECAP_NSH:
case OVS_ACTION_ATTR_METER:
ofpbuf_put(b, a, nl_attr_len_pad(a, left));
break;
@@ -5453,6 +5455,91 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct
ofpact_conntrack *ofc)
}
static void
+compose_encap_nsh_action(const struct ofpact_encap *ofe, struct
ovs_action_encap_nsh * encap_nsh)
+{
+ char * ptr = (char *)ofe->props;
+ size_t ofs = 0;
+ struct nsh_hdr * nsh_header = (struct nsh_hdr *)encap_nsh;
+
+ /* The default is NSH_M_TYPE1 */
+ nsh_header->base.version = 0;
+ nsh_header->base.oam_flag = 0;
+ nsh_header->base.context_flag = 0; //md_type=NSH_M_TYPE1
+ nsh_header->base.length = 6; //md_type=NSH_M_TYPE1
+
+ nsh_header->base.md_type = NSH_M_TYPE1;
+ nsh_header->base.next_proto = NSH_P_ETHERNET;
+ nsh_header->base.path_hdr = htonl(255);
+
+ struct nsh_md1_ctx * md1_ctx = nsh_md1_ctx(nsh_header);
+ md1_ctx->c1 = 0;
+ md1_ctx->c2 = 0;
+ md1_ctx->c3 = 0;
+ md1_ctx->c4 = 0;
+
+ if (ofe->props_len == 0) {
+ return;
+ }
+
+ struct ofp_ed_prop_header * prop_ptr = (struct ofp_ed_prop_header *)ptr;
+ if ((prop_ptr->prop_class == OFPPPC_NSH) && (prop_ptr->type ==
OFPPPT_PROP_NSH_MDTYPE)) {
+ struct ofp_ed_prop_nsh_md_type * md_type_prop = (struct
ofp_ed_prop_nsh_md_type *)prop_ptr;
+ nsh_header->base.md_type = md_type_prop->md_type;
+ switch(nsh_header->base.md_type) {
+ case NSH_M_TYPE1:
+ break;
+ case NSH_M_TYPE2:
+ nsh_header->base.context_flag = 1; //md_type=NSH_M_TYPE2
+ nsh_header->base.length = 2; //md_type=NSH_M_TYPE2
+ break;
+ }
+ ptr += sizeof(struct ofp_ed_prop_nsh_md_type);
+ ofs += sizeof(struct ofp_ed_prop_nsh_md_type);
+
+
+ /* Get TLVs */
+ struct nsh_md2_ctx * md2_ctx = nsh_md2_ctx(nsh_header);
+ while (ofs + sizeof(struct ofp_ed_prop_nsh_tlv) < ofe->props_len) {
+ struct ofp_ed_prop_nsh_tlv * tlv_prop = (struct
ofp_ed_prop_nsh_tlv *)ptr;
+ md2_ctx->md_class = htons(tlv_prop->tlv_class);
+ md2_ctx->type = tlv_prop->tlv_type;
+ md2_ctx->length = tlv_prop->tlv_len;
+ memcpy(md2_ctx->md_value, tlv_prop->data, md2_ctx->length);
+ nsh_header->base.length += 1 + md2_ctx->length/4;
+ ptr += sizeof(struct ofp_ed_prop_nsh_tlv) + tlv_prop->tlv_len;
+ ofs += sizeof(struct ofp_ed_prop_nsh_tlv) + tlv_prop->tlv_len;
+ md2_ctx = (struct nsh_md2_ctx *)((char *)md2_ctx + 4 +
md2_ctx->length);
+ }
+ } /* nsh encap */
+}
+
+static void
+compose_generic_encap_action(struct xlate_ctx *ctx, struct ofpact_encap *ofe)
+{
+ /* Ensure that any prior actions are applied before composing generic
+ * encap action. */
+ xlate_commit_actions(ctx);
+
+ /* encap_nsh */
+ if (PACKET_TYPE(ofe->new_pkt_type.ns, ofe->new_pkt_type.type) == PT_NSH) {
+ struct ovs_action_encap_nsh encap_nsh;
+ struct nsh_hdr * nsh_header = (struct nsh_hdr *)&encap_nsh;
+
+ compose_encap_nsh_action(ofe, &encap_nsh);
+ nl_msg_put_unspec(ctx->odp_actions, OVS_ACTION_ATTR_ENCAP_NSH,
&encap_nsh, nsh_header->base.length << 2);
+ }
+}
+
+static void
+compose_generic_decap_action(struct xlate_ctx *ctx, struct ofpact_decap *ofd)
+{
+ /* decap_nsh */
+ if (PACKET_TYPE(ofd->new_pkt_type.ns, ofd->new_pkt_type.type) == PT_NSH) {
+ nl_msg_put_flag(ctx->odp_actions, OVS_ACTION_ATTR_DECAP_NSH);
+ }
+}
+
+static void
recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
{
/* No need to recirculate if already exiting. */
@@ -5944,11 +6031,17 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t
ofpacts_len,
break;
case OFPACT_ENCAP:
- /* TODO */
+ compose_generic_encap_action(ctx, ofpact_get_ENCAP(a));
+ /* Recirculate for parse the encaped header */
+ ctx_trigger_freeze(ctx);
+ a = ofpact_next(a);
break;
case OFPACT_DECAP:
- /* TODO */
+ compose_generic_decap_action(ctx, ofpact_get_DECAP(a));
+ /* Recirculate for parse inner header */
+ ctx_trigger_freeze(ctx);
+ a = ofpact_next(a);
break;
case OFPACT_CT:
--
2.1.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev