Add a new action type OVS_ACTION_ATTR_SET_MASKED, and support for parsing, printing, and committing them.
Masked set actions add a mask, immediately following the netlink attribute data, within the netlink attribute itself. Thus the key attribute size for a masked set action is exactly double of the non-masked set action. Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- include/linux/openvswitch.h | 4 + lib/dpif-netdev.c | 1 + lib/dpif.c | 1 + lib/odp-execute.c | 242 +++++++++++++++++++++++++++++++++++++++---- lib/odp-util.c | 85 ++++++++++++++- lib/odp-util.h | 3 + tests/odp.at | 22 ++++ 7 files changed, 335 insertions(+), 23 deletions(-) diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index 603382e..35e5a4c 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -601,6 +601,10 @@ enum ovs_action_attr { OVS_ACTION_ATTR_PUSH_MPLS, /* struct ovs_action_push_mpls. */ OVS_ACTION_ATTR_POP_MPLS, /* __be16 ethertype. */ OVS_ACTION_ATTR_RECIRC, /* struct ovs_action_recirc. */ + OVS_ACTION_ATTR_SET_MASKED, /* One nested OVS_KEY_ATTR_* including + * data immediately followed by a mask. + * The data must be zero for the unmasked + * bits. */ __OVS_ACTION_ATTR_MAX }; diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 9ad9386..99916c9 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2173,6 +2173,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_SET: + case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: diff --git a/lib/dpif.c b/lib/dpif.c index a8bd674..b9acd87 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1131,6 +1131,7 @@ dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet, case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_SET: + case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_UNSPEC: case OVS_ACTION_ATTR_RECIRC: diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 37e44e3..127df85 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -18,6 +18,7 @@ #include <config.h> #include "odp-execute.h" #include <linux/openvswitch.h> +#include <netinet/ip6.h> #include <stdlib.h> #include <string.h> @@ -29,19 +30,121 @@ #include "unaligned.h" #include "util.h" +/* Masked copy of an ethernet address. 'src' is already properly masked. */ static void -odp_eth_set_addrs(struct ofpbuf *packet, - const struct ovs_key_ethernet *eth_key) +ether_addr_copy_masked(uint8_t *dst, const uint8_t *src, + const uint8_t *mask) +{ + int i; + + for (i=0; i < ETH_ADDR_LEN; i++) { + dst[i] = src[i] | (dst[i] & ~mask[i]); + } +} + +static void +odp_eth_set_addrs(struct ofpbuf *packet, const struct ovs_key_ethernet *key, + const struct ovs_key_ethernet *mask) { struct eth_header *eh = ofpbuf_l2(packet); if (eh) { - memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src); - memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst); + if (!mask) { + memcpy(eh->eth_src, key->eth_src, sizeof eh->eth_src); + memcpy(eh->eth_dst, key->eth_dst, sizeof eh->eth_dst); + } else { + ether_addr_copy_masked(eh->eth_src, key->eth_src, mask->eth_src); + ether_addr_copy_masked(eh->eth_dst, key->eth_dst, mask->eth_dst); + } } } static void +odp_set_ipv4(struct ofpbuf *packet, const struct ovs_key_ipv4 *key, + const struct ovs_key_ipv4 *mask) +{ + struct ip_header *nh = ofpbuf_l3(packet); + + packet_set_ipv4(packet, + key->ipv4_src + | (get_16aligned_be32(&nh->ip_src) & ~mask->ipv4_src), + key->ipv4_dst + | (get_16aligned_be32(&nh->ip_dst) & ~mask->ipv4_dst), + key->ipv4_tos | (nh->ip_tos & ~mask->ipv4_tos), + key->ipv4_ttl | (nh->ip_ttl & ~mask->ipv4_ttl)); +} + +static const ovs_be32 * +mask_ipv6_addr(const ovs_be16 *old, const ovs_be32 *addr_, + const ovs_be32 *mask_, ovs_be32 *masked_) +{ + const ovs_be16 *addr = (const ovs_be16 *)addr_; + const ovs_be16 *mask = (const ovs_be16 *)mask_; + ovs_be16 *masked = (ovs_be16 *)masked_; + + masked[0] = addr[0] | (old[0] & ~mask[0]); + masked[1] = addr[1] | (old[1] & ~mask[1]); + masked[2] = addr[2] | (old[2] & ~mask[2]); + masked[3] = addr[3] | (old[3] & ~mask[3]); + masked[4] = addr[4] | (old[4] & ~mask[4]); + masked[5] = addr[5] | (old[5] & ~mask[5]); + masked[6] = addr[6] | (old[6] & ~mask[6]); + masked[7] = addr[7] | (old[7] & ~mask[7]); + + return masked_; +} + +static void +odp_set_ipv6(struct ofpbuf *packet, const struct ovs_key_ipv6 *key, + const struct ovs_key_ipv6 *mask) +{ + struct ovs_16aligned_ip6_hdr *nh = ofpbuf_l3(packet); + ovs_be32 sbuf[4], dbuf[4]; + uint8_t old_tc = ntohl(get_16aligned_be32(&nh->ip6_flow)) >> 20; + ovs_be32 old_fl = get_16aligned_be32(&nh->ip6_flow) & htonl(0xfffff); + + packet_set_ipv6(packet, key->ipv6_proto, + mask_ipv6_addr((const ovs_be16 *)nh->ip6_src.be32, + key->ipv6_src, mask->ipv6_src, sbuf), + mask_ipv6_addr((const ovs_be16 *)nh->ip6_dst.be32, + key->ipv6_dst, mask->ipv6_dst, dbuf), + key->ipv6_tclass | (old_tc & ~mask->ipv6_tclass), + key->ipv6_label | (old_fl & ~mask->ipv6_label), + key->ipv6_hlimit | (nh->ip6_hlim & ~mask->ipv6_hlimit)); +} + +static void +odp_set_tcp(struct ofpbuf *packet, const struct ovs_key_tcp *key, + const struct ovs_key_tcp *mask) +{ + struct tcp_header *th = ofpbuf_l4(packet); + + packet_set_tcp_port(packet, key->tcp_src | (th->tcp_src & ~mask->tcp_src), + key->tcp_dst | (th->tcp_dst & ~mask->tcp_dst)); +} + +static void +odp_set_udp(struct ofpbuf *packet, const struct ovs_key_udp *key, + const struct ovs_key_udp *mask) +{ + struct udp_header *uh = ofpbuf_l4(packet); + + packet_set_udp_port(packet, key->udp_src | (uh->udp_src & ~mask->udp_src), + key->udp_dst | (uh->udp_dst & ~mask->udp_dst)); +} + +static void +odp_set_sctp(struct ofpbuf *packet, const struct ovs_key_sctp *key, + const struct ovs_key_sctp *mask) +{ + struct sctp_header *sh = ofpbuf_l4(packet); + + packet_set_sctp_port(packet, + key->sctp_src | (sh->sctp_src & ~mask->sctp_src), + key->sctp_dst | (sh->sctp_dst & ~mask->sctp_dst)); +} + +static void odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key) { enum odp_key_fitness fitness; @@ -51,20 +154,36 @@ odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key) } static void -set_arp(struct ofpbuf *packet, const struct ovs_key_arp *arp_key) +set_arp(struct ofpbuf *packet, const struct ovs_key_arp *key, + const struct ovs_key_arp *mask) { struct arp_eth_header *arp = ofpbuf_l3(packet); - arp->ar_op = arp_key->arp_op; - memcpy(arp->ar_sha, arp_key->arp_sha, ETH_ADDR_LEN); - put_16aligned_be32(&arp->ar_spa, arp_key->arp_sip); - memcpy(arp->ar_tha, arp_key->arp_tha, ETH_ADDR_LEN); - put_16aligned_be32(&arp->ar_tpa, arp_key->arp_tip); + if (!mask) { + arp->ar_op = key->arp_op; + memcpy(arp->ar_sha, key->arp_sha, ETH_ADDR_LEN); + put_16aligned_be32(&arp->ar_spa, key->arp_sip); + memcpy(arp->ar_tha, key->arp_tha, ETH_ADDR_LEN); + put_16aligned_be32(&arp->ar_tpa, key->arp_tip); + } else { + ovs_be32 ar_spa = get_16aligned_be32(&arp->ar_spa); + ovs_be32 ar_tpa = get_16aligned_be32(&arp->ar_tpa); + + arp->ar_op = key->arp_op | (arp->ar_op & ~mask->arp_op); + ether_addr_copy_masked(arp->ar_sha, key->arp_sha, mask->arp_sha); + put_16aligned_be32(&arp->ar_spa, + key->arp_sip | (ar_spa & ~mask->arp_sip)); + ether_addr_copy_masked(arp->ar_tha, key->arp_tha, mask->arp_tha); + put_16aligned_be32(&arp->ar_tpa, + key->arp_tip | (ar_tpa & ~mask->arp_tip)); + } } +#define get_value(a) (const void *)(a + 1) + static void -odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, - struct pkt_metadata *md) +odp_execute_set_action(struct pkt_metadata *md, struct ofpbuf *packet, + const struct nlattr *a) { enum ovs_key_attr type = nl_attr_type(a); const struct ovs_key_ipv4 *ipv4_key; @@ -87,8 +206,7 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, break; case OVS_KEY_ATTR_ETHERNET: - odp_eth_set_addrs(packet, - nl_attr_get_unspec(a, sizeof(struct ovs_key_ethernet))); + odp_eth_set_addrs(packet, get_value(a), NULL); break; case OVS_KEY_ATTR_IPV4: @@ -120,11 +238,11 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, break; case OVS_KEY_ATTR_MPLS: - set_mpls_lse(packet, nl_attr_get_be32(a)); - break; + set_mpls_lse(packet, nl_attr_get_be32(a)); + break; case OVS_KEY_ATTR_ARP: - set_arp(packet, nl_attr_get_unspec(a, sizeof(struct ovs_key_arp))); + set_arp(packet, get_value(a), NULL); break; case OVS_KEY_ATTR_DP_HASH: @@ -150,6 +268,90 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, } } +#define get_mask(a, type) ((const type *)(const void *)(a + 1) + 1) + +static void +odp_execute_masked_set_action(struct pkt_metadata *md, struct ofpbuf *packet, + const struct nlattr *a) +{ + enum ovs_key_attr type = nl_attr_type(a); + struct mpls_hdr *mh; + + switch (type) { + case OVS_KEY_ATTR_PRIORITY: + md->skb_priority = nl_attr_get_u32(a) + | (md->skb_priority & ~*get_mask(a, uint32_t)); + break; + + case OVS_KEY_ATTR_SKB_MARK: + md->pkt_mark = nl_attr_get_u32(a) + | (md->pkt_mark & ~*get_mask(a, uint32_t)); + break; + + case OVS_KEY_ATTR_ETHERNET: + odp_eth_set_addrs(packet, get_value(a), + get_mask(a, struct ovs_key_ethernet)); + break; + + case OVS_KEY_ATTR_IPV4: + odp_set_ipv4(packet, get_value(a), get_mask(a, struct ovs_key_ipv4)); + break; + + case OVS_KEY_ATTR_IPV6: + odp_set_ipv6(packet, get_value(a), get_mask(a, struct ovs_key_ipv6)); + break; + + case OVS_KEY_ATTR_TCP: + odp_set_tcp(packet, get_value(a), get_mask(a, struct ovs_key_tcp)); + break; + + case OVS_KEY_ATTR_UDP: + odp_set_udp(packet, get_value(a), get_mask(a, struct ovs_key_udp)); + break; + + case OVS_KEY_ATTR_SCTP: + odp_set_sctp(packet, get_value(a), get_mask(a, struct ovs_key_sctp)); + break; + + case OVS_KEY_ATTR_MPLS: + mh = ofpbuf_l2_5(packet); + if (mh) { + put_16aligned_be32(&mh->mpls_lse, nl_attr_get_be32(a) + | (get_16aligned_be32(&mh->mpls_lse) + & ~*get_mask(a, ovs_be32))); + } + break; + + case OVS_KEY_ATTR_ARP: + set_arp(packet, get_value(a), get_mask(a, struct ovs_key_arp)); + break; + + case OVS_KEY_ATTR_DP_HASH: + md->dp_hash = nl_attr_get_u32(a) + | (md->dp_hash & ~*get_mask(a, uint32_t)); + break; + + case OVS_KEY_ATTR_RECIRC_ID: + md->recirc_id = nl_attr_get_u32(a) + | (md->recirc_id & ~*get_mask(a, uint32_t)); + break; + + case OVS_KEY_ATTR_TUNNEL: /* Masked data not supported for tunnel. */ + case OVS_KEY_ATTR_UNSPEC: + case OVS_KEY_ATTR_ENCAP: + case OVS_KEY_ATTR_ETHERTYPE: + case OVS_KEY_ATTR_IN_PORT: + case OVS_KEY_ATTR_VLAN: + case OVS_KEY_ATTR_ICMP: + case OVS_KEY_ATTR_ICMPV6: + case OVS_KEY_ATTR_ND: + case OVS_KEY_ATTR_TCP_FLAGS: + case __OVS_KEY_ATTR_MAX: + default: + OVS_NOT_REACHED(); + } +} + static void odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, struct pkt_metadata *, @@ -239,7 +441,11 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, break; case OVS_ACTION_ATTR_SET: - odp_execute_set_action(packet, nl_attr_get(a), md); + odp_execute_set_action(md, packet, nl_attr_get(a)); + break; + + case OVS_ACTION_ATTR_SET_MASKED: + odp_execute_masked_set_action(md, packet, nl_attr_get(a)); break; case OVS_ACTION_ATTR_SAMPLE: diff --git a/lib/odp-util.c b/lib/odp-util.c index f61c2b2..6c3cd36 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -81,6 +81,7 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_POP_MPLS: return sizeof(ovs_be16); case OVS_ACTION_ATTR_RECIRC: return sizeof(struct ovs_action_recirc); case OVS_ACTION_ATTR_SET: return -2; + case OVS_ACTION_ATTR_SET_MASKED: return -2; case OVS_ACTION_ATTR_SAMPLE: return -2; case OVS_ACTION_ATTR_UNSPEC: @@ -405,6 +406,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a) int expected_len; enum ovs_action_attr type = nl_attr_type(a); const struct ovs_action_push_vlan *vlan; + size_t size; expected_len = odp_action_len(nl_attr_type(a)); if (expected_len != -2 && nl_attr_get_size(a) != expected_len) { @@ -424,6 +426,27 @@ format_odp_action(struct ds *ds, const struct nlattr *a) case OVS_ACTION_ATTR_RECIRC: format_odp_recirc_action(ds, nl_attr_get(a)); break; + case OVS_ACTION_ATTR_SET_MASKED: + a = nl_attr_get(a); + size = nl_attr_get_size(a) / 2; + ds_put_cstr(ds, "set("); + + /* Masked set action not supported for tunnel key, which is bigger. */ + if (size <= sizeof(struct ovs_key_ipv6)) { + struct nlattr attr[1 + DIV_ROUND_UP(sizeof(struct ovs_key_ipv6), + sizeof(struct nlattr))]; + struct nlattr mask[1 + DIV_ROUND_UP(sizeof(struct ovs_key_ipv6), + sizeof(struct nlattr))]; + mask->nla_type = attr->nla_type = nl_attr_type(a); + mask->nla_len = attr->nla_len = NLA_HDRLEN + size; + memcpy(attr + 1, (char *)(a + 1), size); + memcpy(mask + 1, (char *)(a + 1) + size, size); + format_odp_key_attr(attr, mask, NULL, ds, true); + } else { + format_odp_key_attr(a, NULL, NULL, ds, true); + } + ds_put_cstr(ds, ")"); + break; case OVS_ACTION_ATTR_SET: ds_put_cstr(ds, "set("); format_odp_key_attr(nl_attr_get(a), NULL, NULL, ds, true); @@ -615,15 +638,47 @@ parse_odp_action(const char *s, const struct simap *port_names, if (!strncmp(s, "set(", 4)) { size_t start_ofs; int retval; + struct nlattr mask[128/sizeof(struct nlattr)]; + struct ofpbuf maskbuf; + struct nlattr *nested, *key; + size_t size; + + /* 'mask' is big enough to hold any key. */ + ofpbuf_use_stack(&maskbuf, mask, sizeof mask); start_ofs = nl_msg_start_nested(actions, OVS_ACTION_ATTR_SET); - retval = parse_odp_key_mask_attr(s + 4, port_names, actions, NULL); + retval = parse_odp_key_mask_attr(s + 4, port_names, actions, &maskbuf); if (retval < 0) { return retval; } if (s[retval + 4] != ')') { return -EINVAL; } + + nested = ofpbuf_at_assert(actions, start_ofs, sizeof *nested); + key = nested + 1; + + size = nl_attr_get_size(mask); + if (size == nl_attr_get_size(key)) { + size_t i = size; + uint8_t *data = (uint8_t *)(mask + 1); + + while (i) { + if (*data++ != 0xff) { + break; + } + i--; + } + /* Change to masked set action if not fully masked. */ + if (i) { + key->nla_len += size; + ofpbuf_put(actions, mask + 1, size); + /* 'actions' may have been reallocated by ofpbuf_put(). */ + nested = ofpbuf_at_assert(actions, start_ofs, sizeof *nested); + nested->nla_type = OVS_ACTION_ATTR_SET_MASKED; + } + } + nl_msg_end_nested(actions, start_ofs); return retval + 5; } @@ -1156,16 +1211,15 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, size_t size = nl_attr_get_size(a); if (!size || size % sizeof *mpls_key) { - ds_put_format(ds, "(bad key length %"PRIuSIZE")", - nl_attr_get_size(a)); + ds_put_format(ds, "(bad key length %"PRIuSIZE")", size); return; } if (!is_exact) { mpls_mask = nl_attr_get(ma); - if (nl_attr_get_size(a) != nl_attr_get_size(ma)) { + if (size != nl_attr_get_size(ma)) { ds_put_format(ds, "(key length %"PRIuSIZE" != " "mask length %"PRIuSIZE")", - nl_attr_get_size(a), nl_attr_get_size(ma)); + size, nl_attr_get_size(ma)); return; } } @@ -3491,6 +3545,27 @@ commit_set_action(struct ofpbuf *odp_actions, enum ovs_key_attr key_type, nl_msg_end_nested(odp_actions, offset); } +/* Masked set actions have a mask following the data within the netlink + * attribute. The unmasked bits in the data will be cleared as the data + * is copied to the action. */ +void +commit_masked_set_action(struct ofpbuf *odp_actions, + enum ovs_key_attr key_type, + const void *key_, const void *mask_, size_t key_size) +{ + size_t offset = nl_msg_start_nested(odp_actions, + OVS_ACTION_ATTR_SET_MASKED); + char *data = nl_msg_put_unspec_uninit(odp_actions, key_type, key_size * 2); + const char *key = key_, *mask = mask_; + + memcpy(data + key_size, mask, key_size); + /* Clear unmasked bits while copying. */ + while (key_size--) { + *data++ = *key++ & *mask++; + } + nl_msg_end_nested(odp_actions, offset); +} + void odp_put_pkt_mark_action(const uint32_t pkt_mark, struct ofpbuf *odp_actions) diff --git a/lib/odp-util.h b/lib/odp-util.h index 7bc64c7..fbd2984 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -179,6 +179,9 @@ const char *odp_key_fitness_to_string(enum odp_key_fitness); void commit_odp_tunnel_action(const struct flow *, struct flow *base, struct ofpbuf *odp_actions); +void commit_masked_set_action(struct ofpbuf *odp_actions, + enum ovs_key_attr key_type, const void *key, + const void *mask, size_t key_size); enum slow_path_reason commit_odp_actions(const struct flow *, struct flow *base, struct ofpbuf *odp_actions, diff --git a/tests/odp.at b/tests/odp.at index 26f561f..adf9469 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -238,13 +238,35 @@ userspace(pid=6633,flow_sample(probability=123,collector_set_id=1234,obs_domain_ userspace(pid=6633,ipfix) set(in_port(2)) set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15)) +set(eth(src=00:01:02:03:04:05/ff:ff:ff:ff:ff:ff,dst=10:11:12:13:14:15/ff:ff:ff:00:00:00)) set(eth_type(0x1234)) set(ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,ttl=128,frag=no)) +set(ipv4(src=35.8.2.41/255.255.255.255,dst=172.16.0.20/255.255.255.255,proto=5/0xff,tos=0x80/0,ttl=128/0xff,frag=no/0xff)) +set(ipv4(src=35.8.2.41/255.255.255.0,dst=172.16.0.20/255.255.255.255,proto=5/0xff,tos=0x80/0xff,ttl=128/0xff,frag=no/0xff)) +set(ipv4(src=35.8.2.41/255.255.255.0,dst=172.16.0.20/0.0.0.0,proto=5/0,tos=0x80/0xff,ttl=128/0xff,frag=no/0xff)) +set(ipv4(src=35.8.2.41/0.0.0.0,dst=172.16.0.20/0.0.0.0,proto=5/0,tos=0x80/0x3,ttl=128/0,frag=no/0)) +set(ipv4(src=35.8.2.41/0.0.0.0,dst=172.16.0.20/0.0.0.0,proto=5/0,tos=0x80/0xfc,ttl=128/0,frag=no/0)) +set(ipv4(src=35.8.2.41/0.0.0.0,dst=172.16.0.20/0.0.0.0,proto=5/0,tos=0x80/0,ttl=128/0xff,frag=no/0x3)) +set(ipv4(src=35.8.2.41/0.0.0.0,dst=172.16.0.20/0.0.0.0,proto=5/0,tos=0x80/0,ttl=128/0,frag=no/0xff)) set(tcp(src=80,dst=8080)) +set(tcp(src=80/0xff00,dst=8080/0xffff)) +set(tcp(src=80/0xffff,dst=0/0)) +set(tcp(src=0/0,dst=8080/0xffff)) set(udp(src=81,dst=6632)) +set(udp(src=81/0xff00,dst=6632/0xffff)) +set(udp(src=81/0xffff,dst=0/0)) +set(udp(src=0/0,dst=6633/0xffff)) set(sctp(src=82,dst=6633)) +set(sctp(src=82/0xff00,dst=6633/0xffff)) +set(sctp(src=82/0xffff,dst=0/0)) +set(sctp(src=0/0,dst=6632/0xffff)) set(icmp(type=1,code=2)) set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)) +set(ipv6(src=::1/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,dst=::2/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,label=0/0,proto=10/0,tclass=0x70/0,hlimit=128/0,frag=no/0x3)) +set(ipv6(src=::/::,dst=::/::,label=0/0xfffff,proto=10/0xff,tclass=0x70/0xff,hlimit=128/0xff,frag=no/0x3)) +set(ipv6(src=::/::,dst=::/::,label=0/0xfffff,proto=10/0xff,tclass=0x70/0,hlimit=128/0xff,frag=no/0x3)) +set(ipv6(src=::/::,dst=::/::,label=0/0xfffff,proto=10/0xff,tclass=0x70/0,hlimit=128/0,frag=no/0x3)) +set(ipv6(src=::/::,dst=::/::,label=0/0xfffff,proto=10/0,tclass=0x70/0,hlimit=128/0,frag=no/0x3)) set(icmpv6(type=1,code=2)) push_vlan(vid=12,pcp=0) push_vlan(vid=13,pcp=5,cfi=0) -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev