Actions may provide information to allow further decoding of a flow. For example:
In the case of MPLS, L3 and L4 information may not initially be decoded from the frame as the ethernet type of the frame is an MPLS type and no information is known about the type of the inner frame. However, the type of the inner frame may be provided by an mpls_pop action in which case L3 and L4 information may be decoded providing a finer grained match than is otherwise possible. Signed-off-by: Simon Horman <ho...@verge.net.au> --- v2.13 - v2.16 * No change v2.12 * As suggested by Jarno Rajahalme - Use flow->encap_dl_type instead of of obtaining the value by scanning the actions. v2.11 * First post --- lib/dpif-netdev.c | 5 +++-- lib/odp-util.c | 37 ++++++++++++++++++++----------------- lib/odp-util.h | 2 +- ofproto/ofproto-dpif.c | 36 ++++++++++++++++++++++++++++++++---- tests/test-odp.c | 2 +- 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 0c41a5a..a47deb4 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -878,7 +878,8 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *state_, struct ofpbuf buf; ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf); - odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port); + odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port, + htons(0)); *key = buf.data; *key_len = buf.size; @@ -1116,7 +1117,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet, buf = &u->buf; ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size); - odp_flow_key_from_flow(buf, flow, flow->in_port); + odp_flow_key_from_flow(buf, flow, flow->in_port, htons(0)); key_len = buf->size; ofpbuf_pull(buf, key_len); ofpbuf_reserve(buf, 2); diff --git a/lib/odp-util.c b/lib/odp-util.c index c00b5a9..3cd85bd 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1432,10 +1432,11 @@ odp_to_flow_flags(uint32_t tun_flags) * capable of being expanded to allow for that much space. */ void odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, - uint32_t odp_in_port) + uint32_t odp_in_port, ovs_be16 encap_dl_type) { struct ovs_key_ethernet *eth_key; size_t encap; + ovs_be16 dl_type; if (flow->skb_priority) { nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority); @@ -1488,7 +1489,18 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, flow->dl_type); - if (flow->dl_type == htons(ETH_TYPE_IP)) { + dl_type = flow->dl_type; + + if (flow->mpls_depth) { + struct ovs_key_mpls *mpls_key; + + mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS, + sizeof *mpls_key); + mpls_key->mpls_top_label = flow->mpls_lse; + dl_type = encap_dl_type; + } + + if (dl_type == htons(ETH_TYPE_IP)) { struct ovs_key_ipv4 *ipv4_key; ipv4_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV4, @@ -1499,7 +1511,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, ipv4_key->ipv4_tos = flow->nw_tos; ipv4_key->ipv4_ttl = flow->nw_ttl; ipv4_key->ipv4_frag = ovs_to_odp_frag(flow->nw_frag); - } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { + } else if (dl_type == htons(ETH_TYPE_IPV6)) { struct ovs_key_ipv6 *ipv6_key; ipv6_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV6, @@ -1511,8 +1523,8 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, ipv6_key->ipv6_tclass = flow->nw_tos; ipv6_key->ipv6_hlimit = flow->nw_ttl; ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->nw_frag); - } else if (flow->dl_type == htons(ETH_TYPE_ARP) || - flow->dl_type == htons(ETH_TYPE_RARP)) { + } else if (dl_type == htons(ETH_TYPE_ARP) || + dl_type == htons(ETH_TYPE_RARP)) { struct ovs_key_arp *arp_key; arp_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ARP, @@ -1525,16 +1537,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, memcpy(arp_key->arp_tha, flow->arp_tha, ETH_ADDR_LEN); } - if (flow->mpls_depth) { - struct ovs_key_mpls *mpls_key; - - mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS, - sizeof *mpls_key); - mpls_key->mpls_top_label = flow->mpls_lse; - } - - if ((flow->dl_type == htons(ETH_TYPE_IP) - || flow->dl_type == htons(ETH_TYPE_IPV6)) + if ((dl_type == htons(ETH_TYPE_IP) || dl_type == htons(ETH_TYPE_IPV6)) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { if (flow->nw_proto == IPPROTO_TCP) { @@ -1551,7 +1554,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, sizeof *udp_key); udp_key->udp_src = flow->tp_src; udp_key->udp_dst = flow->tp_dst; - } else if (flow->dl_type == htons(ETH_TYPE_IP) + } else if (dl_type == htons(ETH_TYPE_IP) && flow->nw_proto == IPPROTO_ICMP) { struct ovs_key_icmp *icmp_key; @@ -1559,7 +1562,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, sizeof *icmp_key); icmp_key->icmp_type = ntohs(flow->tp_src); icmp_key->icmp_code = ntohs(flow->tp_dst); - } else if (flow->dl_type == htons(ETH_TYPE_IPV6) + } else if (dl_type == htons(ETH_TYPE_IPV6) && flow->nw_proto == IPPROTO_ICMPV6) { struct ovs_key_icmpv6 *icmpv6_key; diff --git a/lib/odp-util.h b/lib/odp-util.h index 9d38f33..e4ded77 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -85,7 +85,7 @@ int odp_flow_key_from_string(const char *s, const struct simap *port_names, struct ofpbuf *); void odp_flow_key_from_flow(struct ofpbuf *, const struct flow *, - uint32_t odp_in_port); + uint32_t odp_in_port, ovs_be16 encap_dl_type); uint32_t odp_flow_key_hash(const struct nlattr *, size_t); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index d000a4e..ad58b42 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3236,6 +3236,22 @@ flow_miss_should_make_facet(struct ofproto_dpif *ofproto, list_size(&miss->packets)); } +static ovs_be16 +actions_allow_l3_extraction(const struct ofpact *ofpacts, size_t ofpacts_len) +{ + const struct ofpact *a; + + OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { + if (a->type == OFPACT_EXIT) + break; + if (a->type == OFPACT_POP_MPLS) + return ofpact_get_POP_MPLS(a)->ethertype; + } + + return htons(0); +} + + /* Handles 'miss', which matches 'rule', without creating a facet or subfacet * or creating any datapath flow. May add an "execute" operation to 'ops' and * increment '*n_ops'. */ @@ -4103,7 +4119,8 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow, ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, flow, - ofp_port_to_odp_port(ofproto, flow->in_port)); + ofp_port_to_odp_port(ofproto, flow->in_port), + flow->encap_dl_type); error = dpif_execute(ofproto->backer->dpif, key.data, key.size, odp_actions, actions_len, packet); @@ -4432,6 +4449,14 @@ facet_check_consistency(struct facet *facet) continue; } + if (actions_allow_l3_extraction(rule->up.ofpacts, + rule->up.ofpacts_len)) { + /* The actions for flows that depend on actions for evaluation + * may legitimately vary from one packet to the next. + * We're done. */ + continue; + } + if (!subfacet_should_install(subfacet, subfacet->slow, &odp_actions)) { continue; } @@ -4820,7 +4845,8 @@ subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf, struct flow *flow = &subfacet->facet->flow; ofpbuf_use_stack(key, keybuf, sizeof *keybuf); - odp_flow_key_from_flow(key, flow, subfacet->odp_in_port); + odp_flow_key_from_flow(key, flow, subfacet->odp_in_port, + htons(0)); } else { ofpbuf_use_const(key, subfacet->key, subfacet->key_len); } @@ -5220,7 +5246,8 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &flow, - ofp_port_to_odp_port(ofproto, flow.in_port)); + ofp_port_to_odp_port(ofproto, flow.in_port), + htons(0)); ofpbuf_init(&odp_actions, 32); compose_sflow_action(ofproto, &odp_actions, &flow, odp_port); @@ -7014,7 +7041,8 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, flow, - ofp_port_to_odp_port(ofproto, flow->in_port)); + ofp_port_to_odp_port(ofproto, flow->in_port), + flow->encap_dl_type); dpif_flow_stats_extract(flow, packet, time_msec(), &stats); diff --git a/tests/test-odp.c b/tests/test-odp.c index 5ed31a9..6fc618b 100644 --- a/tests/test-odp.c +++ b/tests/test-odp.c @@ -70,7 +70,7 @@ parse_keys(void) /* Convert cls_rule back to odp_key. */ ofpbuf_uninit(&odp_key); ofpbuf_init(&odp_key, 0); - odp_flow_key_from_flow(&odp_key, &flow, flow.in_port); + odp_flow_key_from_flow(&odp_key, &flow, flow.in_port, htons(0)); if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) { printf ("too long: %zu > %d\n", -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev