Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/odp-util.c | 397 +++++++++++++++++++++++++++++------------- lib/odp-util.h | 5 +- ofproto/ofproto-dpif-xlate.c | 12 +- tests/ofproto-dpif.at | 49 +++--- tests/tunnel.at | 8 +- 5 files changed, 314 insertions(+), 157 deletions(-)
diff --git a/lib/odp-util.c b/lib/odp-util.c index f71b74d..1b3f67e 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -3520,14 +3520,6 @@ commit_masked_set_action(struct ofpbuf *odp_actions, nl_msg_end_nested(odp_actions, offset); } -void -odp_put_pkt_mark_action(const uint32_t pkt_mark, - struct ofpbuf *odp_actions) -{ - commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, &pkt_mark, - sizeof(pkt_mark)); -} - /* If any of the flow key data that ODP actions can modify are different in * 'base->tunnel' and 'flow->tunnel', appends a set_tunnel ODP action to * 'odp_actions' that change the flow tunneling information in key from @@ -3551,26 +3543,44 @@ commit_odp_tunnel_action(const struct flow *flow, struct flow *base, static void commit_set_ether_addr_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions, - struct flow_wildcards *wc) -{ - struct ovs_key_ethernet eth_key; - - if (eth_addr_equals(base->dl_src, flow->dl_src) && - eth_addr_equals(base->dl_dst, flow->dl_dst)) { + struct flow_wildcards *wc, + bool use_masked) +{ + struct ovs_key_ethernet key, mask; + bool have_mask_src = !eth_addr_is_zero(wc->masks.dl_src); + bool have_mask_dst = !eth_addr_is_zero(wc->masks.dl_dst); + + /* Wildcard bits are set when we have either read or set the corresponding + * values. Unwildcarded bits will be exact-matched, no need to set them + * if the value did not actually change. */ + if ((!have_mask_src && !have_mask_dst) || + (eth_addr_equals(base->dl_src, flow->dl_src) && + eth_addr_equals(base->dl_dst, flow->dl_dst))) { return; } - memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src); - memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst); - memcpy(base->dl_src, flow->dl_src, ETH_ADDR_LEN); memcpy(base->dl_dst, flow->dl_dst, ETH_ADDR_LEN); - memcpy(eth_key.eth_src, base->dl_src, ETH_ADDR_LEN); - memcpy(eth_key.eth_dst, base->dl_dst, ETH_ADDR_LEN); + /* Do not use mask if fully masked. */ + if (use_masked && !(have_mask_src && have_mask_dst)) { + memcpy(mask.eth_src, wc->masks.dl_src, ETH_ADDR_LEN); + eth_addr_bitand(base->dl_src, wc->masks.dl_src, key.eth_src); + memcpy(mask.eth_dst, wc->masks.dl_dst, ETH_ADDR_LEN); + eth_addr_bitand(base->dl_dst, wc->masks.dl_dst, key.eth_dst); + + commit_masked_set_action(odp_actions, OVS_KEY_ATTR_ETHERNET, &key, + &mask, sizeof key); + } else { + memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src); + memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst); + + memcpy(key.eth_src, base->dl_src, ETH_ADDR_LEN); + memcpy(key.eth_dst, base->dl_dst, ETH_ADDR_LEN); - commit_set_action(odp_actions, OVS_KEY_ATTR_ETHERNET, - ð_key, sizeof(eth_key)); + commit_set_action(odp_actions, OVS_KEY_ATTR_ETHERNET, &key, + sizeof key); + } } static void @@ -3673,80 +3683,164 @@ commit_mpls_action(const struct flow *flow, struct flow *base, static void commit_set_ipv4_action(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) + struct ofpbuf *odp_actions, struct flow_wildcards *wc, + bool use_masked) { - struct ovs_key_ipv4 ipv4_key; + struct ovs_key_ipv4 key, mask; - if (base->nw_src == flow->nw_src && - base->nw_dst == flow->nw_dst && - base->nw_tos == flow->nw_tos && - base->nw_ttl == flow->nw_ttl && - base->nw_frag == flow->nw_frag) { - return; - } + ovs_assert(!((base->nw_src ^ flow->nw_src) & ~wc->masks.nw_src) + && !((base->nw_dst ^ flow->nw_dst) & ~wc->masks.nw_dst) + && !((base->nw_tos ^ flow->nw_tos) & ~wc->masks.nw_tos) + && !((base->nw_ttl ^ flow->nw_ttl) & ~wc->masks.nw_ttl)); + + /* Wildcard bits are set when we have either read or set the corresponding + * values. Unwildcarded bits will be exact-matched, no need to set them + * if the value did not actually change. */ + if ((base->nw_src ^ flow->nw_src) & wc->masks.nw_src || + (base->nw_dst ^ flow->nw_dst) & wc->masks.nw_dst || + (base->nw_tos ^ flow->nw_tos) & wc->masks.nw_tos || + (base->nw_ttl ^ flow->nw_ttl) & wc->masks.nw_ttl) { + + base->nw_src = flow->nw_src; + base->nw_dst = flow->nw_dst; + base->nw_tos = flow->nw_tos; + base->nw_ttl = flow->nw_ttl; + + if (use_masked) { + mask.ipv4_src = wc->masks.nw_src; + key.ipv4_src = base->nw_src & wc->masks.nw_src;; + + mask.ipv4_dst = wc->masks.nw_dst; + key.ipv4_dst = base->nw_dst & wc->masks.nw_dst; - memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); - memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); - memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos); - memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl); - memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); - memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag); + mask.ipv4_tos = wc->masks.nw_tos; + key.ipv4_tos = base->nw_tos & wc->masks.nw_tos; - ipv4_key.ipv4_src = base->nw_src = flow->nw_src; - ipv4_key.ipv4_dst = base->nw_dst = flow->nw_dst; - ipv4_key.ipv4_tos = base->nw_tos = flow->nw_tos; - ipv4_key.ipv4_ttl = base->nw_ttl = flow->nw_ttl; - ipv4_key.ipv4_proto = base->nw_proto; - ipv4_key.ipv4_frag = ovs_to_odp_frag(base->nw_frag); + mask.ipv4_ttl = wc->masks.nw_ttl; + key.ipv4_ttl = base->nw_ttl & wc->masks.nw_ttl; - commit_set_action(odp_actions, OVS_KEY_ATTR_IPV4, - &ipv4_key, sizeof(ipv4_key)); + key.ipv4_proto = mask.ipv4_proto = 0; /* Not writeable. */ + key.ipv4_frag = mask.ipv4_frag = 0; /* Not writeable. */ + + commit_masked_set_action(odp_actions, OVS_KEY_ATTR_IPV4, &key, + &mask, sizeof key); + } else { + memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); + memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); + memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos); + memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl); + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag); + + key.ipv4_src = base->nw_src; + key.ipv4_dst = base->nw_dst; + key.ipv4_tos = base->nw_tos; + key.ipv4_ttl = base->nw_ttl; + key.ipv4_proto = base->nw_proto; + key.ipv4_frag = ovs_to_odp_frag(base->nw_frag); + + commit_set_action(odp_actions, OVS_KEY_ATTR_IPV4, &key, + sizeof key); + } + } } +#define IPV6_MASKED(MASKED, ADDR, MASK) \ + *(struct in6_addr *)&MASKED = \ + ipv6_addr_bitand((const struct in6_addr *)&ADDR, \ + (const struct in6_addr *)&MASK) + static void commit_set_ipv6_action(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) + struct ofpbuf *odp_actions, struct flow_wildcards *wc, + bool use_masked) { - struct ovs_key_ipv6 ipv6_key; + struct ovs_key_ipv6 key, mask; + + ovs_assert(!((base->ipv6_label ^ flow->ipv6_label) & ~wc->masks.ipv6_label) + && !((base->nw_tos ^ flow->nw_tos) & ~wc->masks.nw_tos) + && !((base->nw_ttl ^ flow->nw_ttl) & ~wc->masks.nw_ttl)); + + /* Wildcard bits are set when we have either read or set the corresponding + * values. Nothing to be done if no bits are set. */ + if (!(ipv6_mask_is_any(&wc->masks.ipv6_src) || + ipv6_mask_is_any(&wc->masks.ipv6_dst) || + wc->masks.ipv6_label || wc->masks.nw_tos || wc->masks.nw_ttl)) { + return; + } if (ipv6_addr_equals(&base->ipv6_src, &flow->ipv6_src) && ipv6_addr_equals(&base->ipv6_dst, &flow->ipv6_dst) && base->ipv6_label == flow->ipv6_label && base->nw_tos == flow->nw_tos && - base->nw_ttl == flow->nw_ttl && - base->nw_frag == flow->nw_frag) { + base->nw_ttl == flow->nw_ttl) { return; } - memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src); - memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst); - memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label); - memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos); - memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl); - memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); - memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag); - base->ipv6_src = flow->ipv6_src; - memcpy(&ipv6_key.ipv6_src, &base->ipv6_src, sizeof(ipv6_key.ipv6_src)); base->ipv6_dst = flow->ipv6_dst; - memcpy(&ipv6_key.ipv6_dst, &base->ipv6_dst, sizeof(ipv6_key.ipv6_dst)); + base->ipv6_label = flow->ipv6_label; + base->nw_tos = flow->nw_tos; + base->nw_ttl = flow->nw_ttl; + + if (use_masked) { + *(struct in6_addr *)&mask.ipv6_src = wc->masks.ipv6_src; + IPV6_MASKED(key.ipv6_src, base->ipv6_src, wc->masks.ipv6_src); + + *(struct in6_addr *)&mask.ipv6_dst = wc->masks.ipv6_dst; + IPV6_MASKED(key.ipv6_dst, base->ipv6_dst, wc->masks.ipv6_dst); + + mask.ipv6_label = wc->masks.ipv6_label; + key.ipv6_label = base->ipv6_label & wc->masks.ipv6_label; - ipv6_key.ipv6_label = base->ipv6_label = flow->ipv6_label; - ipv6_key.ipv6_tclass = base->nw_tos = flow->nw_tos; - ipv6_key.ipv6_hlimit = base->nw_ttl = flow->nw_ttl; - ipv6_key.ipv6_proto = base->nw_proto; - ipv6_key.ipv6_frag = ovs_to_odp_frag(base->nw_frag); + mask.ipv6_tclass = wc->masks.nw_tos; + key.ipv6_tclass = base->nw_tos & wc->masks.nw_tos; + + mask.ipv6_hlimit = wc->masks.nw_ttl; + key.ipv6_hlimit = base->nw_ttl & wc->masks.nw_ttl; + + key.ipv6_proto = mask.ipv6_proto = 0; /* Not writeable. */ + key.ipv6_frag = mask.ipv6_frag = 0; /* Not writeable. */ + + commit_masked_set_action(odp_actions, OVS_KEY_ATTR_IPV6, &key, + &mask, sizeof key); + } else { + memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src); + memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst); + memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label); + memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos); + memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl); + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag); - commit_set_action(odp_actions, OVS_KEY_ATTR_IPV6, - &ipv6_key, sizeof(ipv6_key)); + memcpy(&key.ipv6_src, &base->ipv6_src, sizeof(key.ipv6_src)); + memcpy(&key.ipv6_dst, &base->ipv6_dst, sizeof(key.ipv6_dst)); + + key.ipv6_label = base->ipv6_label; + key.ipv6_tclass = base->nw_tos; + key.ipv6_hlimit = base->nw_ttl; + key.ipv6_proto = base->nw_proto; + key.ipv6_frag = ovs_to_odp_frag(base->nw_frag); + + commit_set_action(odp_actions, OVS_KEY_ATTR_IPV6, &key, sizeof key); + } } static enum slow_path_reason commit_set_arp_action(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) + struct ofpbuf *odp_actions, struct flow_wildcards *wc, + bool use_masked) { - struct ovs_key_arp arp_key; + struct ovs_key_arp key, mask; + /* Wildcard bits are set when we have either read or set the corresponding + * values. Unwildcarded bits will be exact-matched, no need to set them + * if the value did not actually change. */ + if (!wc->masks.nw_src && !wc->masks.nw_dst && !wc->masks.nw_proto && + eth_addr_is_zero(wc->masks.arp_sha) && + eth_addr_is_zero(wc->masks.arp_tha)) { + return 0; + } if (base->nw_src == flow->nw_src && base->nw_dst == flow->nw_dst && base->nw_proto == flow->nw_proto && @@ -3755,32 +3849,52 @@ commit_set_arp_action(const struct flow *flow, struct flow *base, return 0; } - memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); - memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); - memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); - memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha); - memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha); - base->nw_src = flow->nw_src; base->nw_dst = flow->nw_dst; base->nw_proto = flow->nw_proto; memcpy(base->arp_sha, flow->arp_sha, ETH_ADDR_LEN); memcpy(base->arp_tha, flow->arp_tha, ETH_ADDR_LEN); - arp_key.arp_sip = base->nw_src; - arp_key.arp_tip = base->nw_dst; - arp_key.arp_op = htons(base->nw_proto); - memcpy(arp_key.arp_sha, flow->arp_sha, ETH_ADDR_LEN); - memcpy(arp_key.arp_tha, flow->arp_tha, ETH_ADDR_LEN); + if (use_masked) { + mask.arp_sip = wc->masks.nw_src; + key.arp_sip = base->nw_src & wc->masks.nw_src; + + mask.arp_tip = wc->masks.nw_dst; + key.arp_tip = base->nw_dst & wc->masks.nw_dst; + + mask.arp_op = htons(wc->masks.nw_proto); + key.arp_op = htons(base->nw_proto & wc->masks.nw_proto); - commit_set_action(odp_actions, OVS_KEY_ATTR_ARP, &arp_key, sizeof arp_key); + memcpy(mask.arp_sha, wc->masks.arp_sha, ETH_ADDR_LEN); + eth_addr_bitand(base->arp_sha, wc->masks.arp_sha, key.arp_sha); + memcpy(mask.arp_tha, wc->masks.arp_tha, ETH_ADDR_LEN); + eth_addr_bitand(base->arp_tha, wc->masks.arp_tha, key.arp_tha); + + commit_masked_set_action(odp_actions, OVS_KEY_ATTR_ARP, &key, + &mask, sizeof key); + } else { + memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); + memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha); + memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha); + + key.arp_sip = base->nw_src; + key.arp_tip = base->nw_dst; + key.arp_op = htons(base->nw_proto); + memcpy(key.arp_sha, base->arp_sha, ETH_ADDR_LEN); + memcpy(key.arp_tha, base->arp_tha, ETH_ADDR_LEN); + + commit_set_action(odp_actions, OVS_KEY_ATTR_ARP, &key, sizeof key); + } return SLOW_ACTION; } static enum slow_path_reason commit_set_nw_action(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) + struct ofpbuf *odp_actions, struct flow_wildcards *wc, + bool use_masked) { /* Check if 'flow' really has an L3 header. */ if (!flow->nw_proto) { @@ -3789,25 +3903,46 @@ commit_set_nw_action(const struct flow *flow, struct flow *base, switch (ntohs(base->dl_type)) { case ETH_TYPE_IP: - commit_set_ipv4_action(flow, base, odp_actions, wc); + commit_set_ipv4_action(flow, base, odp_actions, wc, use_masked); break; case ETH_TYPE_IPV6: - commit_set_ipv6_action(flow, base, odp_actions, wc); + commit_set_ipv6_action(flow, base, odp_actions, wc, use_masked); break; case ETH_TYPE_ARP: - return commit_set_arp_action(flow, base, odp_actions, wc); + return commit_set_arp_action(flow, base, odp_actions, wc, use_masked); } return 0; } +/* TCP, UDP, and SCTP keys have the same layout. */ +BUILD_ASSERT_DECL(sizeof(struct ovs_key_tcp) == sizeof(struct ovs_key_udp) && + sizeof(struct ovs_key_tcp) == sizeof(struct ovs_key_sctp)); + static void commit_set_port_action(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) + struct ofpbuf *odp_actions, struct flow_wildcards *wc, + bool use_masked) { - if (!is_ip_any(base) || (!base->tp_src && !base->tp_dst)) { + enum ovs_key_attr key_type; + struct ovs_key_tcp key, mask; /* Used for UDP and SCTP, too. */ + + ovs_assert(!(~wc->masks.tp_src & (base->tp_src ^ flow->tp_src))); + ovs_assert(!(~wc->masks.tp_dst & (base->tp_dst ^ flow->tp_dst))); + + if (!is_ip_any(base) || (!wc->masks.tp_src && !wc->masks.tp_dst)) { + return; + } + + if (flow->nw_proto == IPPROTO_TCP) { + key_type = OVS_KEY_ATTR_TCP; + } else if (flow->nw_proto == IPPROTO_UDP) { + key_type = OVS_KEY_ATTR_UDP; + } else if (flow->nw_proto == IPPROTO_SCTP) { + key_type = OVS_KEY_ATTR_SCTP; + } else { return; } @@ -3816,66 +3951,81 @@ commit_set_port_action(const struct flow *flow, struct flow *base, return; } - memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); - memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); - - if (flow->nw_proto == IPPROTO_TCP) { - struct ovs_key_tcp port_key; - - port_key.tcp_src = base->tp_src = flow->tp_src; - port_key.tcp_dst = base->tp_dst = flow->tp_dst; + base->tp_src = flow->tp_src; + base->tp_dst = flow->tp_dst; - commit_set_action(odp_actions, OVS_KEY_ATTR_TCP, - &port_key, sizeof(port_key)); + if (use_masked && (wc->masks.tp_src != OVS_BE16_MAX + || wc->masks.tp_dst != OVS_BE16_MAX)) { + mask.tcp_src = wc->masks.tp_src; + key.tcp_src = base->tp_src & wc->masks.tp_src; - } else if (flow->nw_proto == IPPROTO_UDP) { - struct ovs_key_udp port_key; + mask.tcp_dst = wc->masks.tp_dst; + key.tcp_dst = base->tp_dst & wc->masks.tp_dst; - port_key.udp_src = base->tp_src = flow->tp_src; - port_key.udp_dst = base->tp_dst = flow->tp_dst; - - commit_set_action(odp_actions, OVS_KEY_ATTR_UDP, - &port_key, sizeof(port_key)); - } else if (flow->nw_proto == IPPROTO_SCTP) { - struct ovs_key_sctp port_key; + commit_masked_set_action(odp_actions, key_type, &key, &mask, + sizeof key); + } else { + memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); + memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); - port_key.sctp_src = base->tp_src = flow->tp_src; - port_key.sctp_dst = base->tp_dst = flow->tp_dst; + key.tcp_src = base->tp_src; + key.tcp_dst = base->tp_dst; - commit_set_action(odp_actions, OVS_KEY_ATTR_SCTP, - &port_key, sizeof(port_key)); + commit_set_action(odp_actions, key_type, &key, sizeof key); } } static void commit_set_priority_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions, - struct flow_wildcards *wc) + struct flow_wildcards *wc, + bool use_masked) { - if (base->skb_priority == flow->skb_priority) { + ovs_assert(!(~wc->masks.skb_priority & (base->skb_priority + ^ flow->skb_priority))); + + if (!wc->masks.skb_priority || base->skb_priority == flow->skb_priority) { return; } - memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority); base->skb_priority = flow->skb_priority; - commit_set_action(odp_actions, OVS_KEY_ATTR_PRIORITY, - &base->skb_priority, sizeof(base->skb_priority)); + if (wc->masks.skb_priority != OVS_BE32_MAX && use_masked) { + commit_masked_set_action(odp_actions, OVS_KEY_ATTR_PRIORITY, + &base->skb_priority, &wc->masks.skb_priority, + sizeof(base->skb_priority)); + } else { + memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority); + + commit_set_action(odp_actions, OVS_KEY_ATTR_PRIORITY, + &base->skb_priority, sizeof(base->skb_priority)); + } } static void commit_set_pkt_mark_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions, - struct flow_wildcards *wc) + struct flow_wildcards *wc, + bool use_masked) { - if (base->pkt_mark == flow->pkt_mark) { + ovs_assert(!(~wc->masks.pkt_mark & (base->pkt_mark ^ flow->pkt_mark))); + + /* If none of the masked bits are different, we need not do anything. */ + if (!(wc->masks.pkt_mark & (base->pkt_mark ^ flow->pkt_mark))) { return; } - memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark); base->pkt_mark = flow->pkt_mark; - odp_put_pkt_mark_action(base->pkt_mark, odp_actions); + if (wc->masks.pkt_mark != OVS_BE32_MAX && use_masked) { + commit_masked_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, + &base->pkt_mark, &wc->masks.pkt_mark, + sizeof(base->pkt_mark)); + } else { + memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark); + commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, &base->pkt_mark, + sizeof(base->pkt_mark)); + } } /* If any of the flow key data that ODP actions can modify are different in @@ -3889,17 +4039,18 @@ commit_set_pkt_mark_action(const struct flow *flow, struct flow *base, * slow path, if there is one, otherwise 0. */ enum slow_path_reason commit_odp_actions(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) + struct ofpbuf *odp_actions, struct flow_wildcards *wc, + bool use_masked) { enum slow_path_reason slow; - commit_set_ether_addr_action(flow, base, odp_actions, wc); - slow = commit_set_nw_action(flow, base, odp_actions, wc); - commit_set_port_action(flow, base, odp_actions, wc); + commit_set_ether_addr_action(flow, base, odp_actions, wc, use_masked); + slow = commit_set_nw_action(flow, base, odp_actions, wc, use_masked); + commit_set_port_action(flow, base, odp_actions, wc, use_masked); commit_mpls_action(flow, base, odp_actions, wc); commit_vlan_action(flow->vlan_tci, base, odp_actions, wc); - commit_set_priority_action(flow, base, odp_actions, wc); - commit_set_pkt_mark_action(flow, base, odp_actions, wc); + commit_set_priority_action(flow, base, odp_actions, wc, use_masked); + commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked); return slow; } diff --git a/lib/odp-util.h b/lib/odp-util.h index fbd2984..2afc357 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -185,7 +185,8 @@ void commit_masked_set_action(struct ofpbuf *odp_actions, enum slow_path_reason commit_odp_actions(const struct flow *, struct flow *base, struct ofpbuf *odp_actions, - struct flow_wildcards *wc); + struct flow_wildcards *wc, + bool use_masked); /* ofproto-dpif interface. * @@ -238,7 +239,5 @@ size_t odp_put_userspace_action(uint32_t pid, struct ofpbuf *odp_actions); void odp_put_tunnel_action(const struct flow_tnl *tunnel, struct ofpbuf *odp_actions); -void odp_put_pkt_mark_action(const uint32_t pkt_mark, - struct ofpbuf *odp_actions); #endif /* odp-util.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index c1ca6d4..c7695e6 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -1842,7 +1842,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (out_port != ODPP_NONE) { ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc); + &ctx->xout->wc, + ctx->xbridge->masked_set_action); if (ctx->xout->use_recirc) { struct ovs_action_recirc *act_recirc; @@ -2186,7 +2187,8 @@ execute_controller_action(struct xlate_ctx *ctx, int len, ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc); + &ctx->xout->wc, + ctx->xbridge->masked_set_action); odp_execute_actions(NULL, packet, false, &md, ofpbuf_data(&ctx->xout->odp_actions), @@ -2238,7 +2240,8 @@ compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls) if (!n) { ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc); + &ctx->xout->wc, + ctx->xbridge->masked_set_action); } else if (n >= FLOW_MAX_MPLS_LABELS) { if (ctx->xin->packet != NULL) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -2561,7 +2564,8 @@ xlate_sample_action(struct xlate_ctx *ctx, ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc); + &ctx->xout->wc, + ctx->xbridge->masked_set_action); compose_flow_sample_cookie(os->probability, os->collector_set_id, os->obs_domain_id, os->obs_point_id, &cookie); diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 4fefa53..d797519 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -234,8 +234,8 @@ table=2 ip actions=set_field:192.168.3.91->ip_src,output(11) AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt]) AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout]) AT_CHECK([tail -2 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=128 -Datapath actions: 10,set(ipv4(src=192.168.3.91,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11,set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),13 + [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_src=192.168.0.1,nw_frag=no +Datapath actions: 10,set(ipv4(src=192.168.3.91/255.255.255.255,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no/0)),11,set(ipv4(src=192.168.3.90/255.255.255.255,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no/0)),13 ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -250,8 +250,8 @@ table=1 tcp actions=set_field:91->tp_src,output(11),clear_actions AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt]) AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=9'], [0], [stdout]) AT_CHECK([tail -2 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_frag=no,tp_src=8,tp_dst=9 -Datapath actions: 10,set(tcp(src=91,dst=9)),11 + [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_frag=no,tp_src=8 +Datapath actions: 10,set(tcp(src=91/0xffff,dst=0/0)),11 ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -273,9 +273,11 @@ ADD_OF_PORTS([br0], [1], [10], [11]) AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=all,bucket=output:10,set_field:192.168.3.90->ip_src,bucket=output:11']) AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=group:1234']) AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout]) +# Must match on the source address to be able to restore it's value for +# the second bucket AT_CHECK([tail -2 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=128 -Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11 + [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_src=192.168.0.1,nw_frag=no +Datapath actions: set(ipv4(src=192.168.3.90/255.255.255.255,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no/0)),10,set(ipv4(src=192.168.0.1/255.255.255.255,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no/0)),11 ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -298,9 +300,11 @@ ADD_OF_PORTS([br0], [1], [10], [11]) AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=all,bucket=output:10,set_field:192.168.3.90->ip_src,bucket=output:11']) AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=write_actions(group:1234)']) AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout]) +# Must match on the source address to be able to restore it's value for +# the third bucket AT_CHECK([tail -2 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=128 -Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11 + [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_src=192.168.0.1,nw_frag=no +Datapath actions: set(ipv4(src=192.168.3.90/255.255.255.255,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no/0)),10,set(ipv4(src=192.168.0.1/255.255.255.255,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no/0)),11 ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -458,20 +462,20 @@ table=1 in_port=1 action=dec_ttl,output:3 AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)' -generate], [0], [stdout]) AT_CHECK([tail -4 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=2 -Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),2,4 + [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_ttl=2,nw_frag=no +Datapath actions: set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=1/0xff,frag=no/0)),2,4 This flow is handled by the userspace slow path because it: - Sends "packet-in" messages to the OpenFlow controller. ]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=3,frag=no)'], [0], [stdout]) AT_CHECK([tail -2 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=3 -Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),3,4 + [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_ttl=3,nw_frag=no +Datapath actions: set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=2/0xff,frag=no/0)),2,set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=1/0xff,frag=no/0)),3,4 ]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'], [0], [stdout]) AT_CHECK([tail -2 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,ipv6,in_port=1,ipv6_src=::1,ipv6_dst=::2,ipv6_label=0x00000,nw_proto=10,nw_tos=112,nw_ecn=0,nw_ttl=128 -Datapath actions: set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=127,frag=no)),2,set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=126,frag=no)),3,4 + [Megaflow: recirc_id=0,skb_priority=0,ipv6,in_port=1,nw_ttl=128,nw_frag=no +Datapath actions: set(ipv6(src=::/::,dst=::/::,label=0/0,proto=0/0,tclass=0/0,hlimit=127/0xff,frag=no/0)),2,set(ipv6(src=::/::,dst=::/::,label=0/0,proto=0/0,tclass=0/0,hlimit=126/0xff,frag=no/0)),3,4 ]) AT_CAPTURE_FILE([ofctl_monitor.log]) @@ -568,16 +572,15 @@ AT_CHECK([ovs-vsctl -- \ --id=@q2 create Queue dscp=2], [0], [ignore]) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(9),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0xff,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) AT_CHECK([tail -2 stdout], [0], - [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=9,nw_src=1.1.1.1,nw_dst=2.2.2.2,nw_tos=252,nw_ecn=3,nw_ttl=128 + [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=9,nw_tos=252,nw_frag=no Datapath actions: dnl 100,dnl -set(ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0x7,ttl=128,frag=no)),set(skb_priority(0x1)),1,dnl -set(ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0xb,ttl=128,frag=no)),set(skb_priority(0x2)),1,dnl +set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0x4/0xfc,ttl=0/0,frag=no/0)),set(skb_priority(0x1)),1,dnl +set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0x8/0xfc,ttl=0/0,frag=no/0)),set(skb_priority(0x2)),1,dnl 1,dnl -set(ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0x7,ttl=128,frag=no)),set(skb_priority(0x1)),1,dnl -set(ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0xff,ttl=128,frag=no)),set(skb_priority(0)),1,dnl -set(ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0x3,ttl=128,frag=no)),1,dnl -100 +set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0x4/0xfc,ttl=0/0,frag=no/0)),set(skb_priority(0x1)),1,dnl +set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0xfc/0xfc,ttl=0/0,frag=no/0)),set(skb_priority(0)),1,dnl +set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0xfc,ttl=0/0,frag=no/0)),1,100 ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -4286,7 +4289,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00: sleep 1 AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del> -skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no), packets:0, bytes:0, used:never, actions: <del> +skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/0.0.0.0,proto=1/0xff,tos=0/0,ttl=64/0xff,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del> ]) OVS_VSWITCHD_STOP AT_CLEANUP @@ -4313,7 +4316,7 @@ dnl un-wildcarded, since the ODP commit functions update both the source dnl and destination MAC addresses. AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_USED], [0], [dnl skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/ff:ff:ff:ff:ff:ff),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:2 -skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:set(eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0a)),2 +skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/00:00:00:00:00:00,dst=50:54:00:00:00:0c/ff:ff:ff:ff:ff:ff),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:set(eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=50:54:00:00:00:0a/ff:ff:ff:ff:ff:ff)),2 ]) OVS_VSWITCHD_STOP AT_CLEANUP diff --git a/tests/tunnel.at b/tests/tunnel.at index aa16d58..d7fa641 100644 --- a/tests/tunnel.at +++ b/tests/tunnel.at @@ -88,15 +88,15 @@ Datapath actions: 2 dnl Tunnel CE and encapsulated packet ECT(1) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) AT_CHECK([tail -2 stdout], [0], - [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,tcp,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=1,nw_ttl=64 -Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2 + [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=1,nw_frag=no +Datapath actions: set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0x3/0x3,ttl=0/0,frag=no/0)),2 ]) dnl Tunnel CE and encapsulated packet ECT(2) AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=2,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout]) AT_CHECK([tail -2 stdout], [0], - [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,tcp,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=2,nw_ttl=64 -Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2 + [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=2,nw_frag=no +Datapath actions: set(ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0x3/0x3,ttl=0/0,frag=no/0)),2 ]) dnl Tunnel CE and encapsulated packet Non-ECT -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev